More updates

This commit is contained in:
laf 2015-08-19 22:13:50 +00:00
parent 6f11ffee14
commit 471c4bacf3
183 changed files with 0 additions and 21281 deletions

View File

@ -1,14 +0,0 @@
language: php
php:
- 5.5
- 5.6
install:
- composer install
addons:
code_climate:
repo_token: 5371d86d298d66eb9007cc8de462d7063e58f6dd85e430928834736edee479a9
after_script:
- vendor/bin/test-reporter

View File

@ -1,50 +0,0 @@
/* CONTRIBUTE */
This is the contribute.md of influxdb-php. Great to have you here.
Here are a few ways you can help make this project better.
# Contribute.md
## Team members
* Stephen "TheCodeAssassin" Hoogendijk
* Daniel "danibrutal" Martinez
## Helping out
We appreciate any efforts to help us writing this library. You can contribute in any of the following ways:
* Documentation
* Unit tests
* New features
* Bug fixed
* Reviewing pull requests
## Guidelines
In order for your pull requests to get accepted we hold all the code to the following criteria:
* PSR-1/PSR-2 compliant
* Do not use left hand conditions such as false == $something
* New features need to be documented
* Breaking changes should be well highlighted and explained in the PR
* Only short-array syntax should be used for arrays
* Use regular string concatenation for single-variable strings, and sprintf for multi-variable strings
* Do not align variable assignments
The following is optional but encouraged:
* Code should be documented
* Code should be unit tested
* Do not write conditions like false === $something, rather $something === false.
## Special thanks
We would like to thank the following people for helping to make this library possible:
* InfluxDB Community
* LeaseWeb Technologies
* Paul Dix
* Sean Beckett
* CentaurWarchief

View File

@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 InfluxDB
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,348 +0,0 @@
# influxdb-php
## InfluxDB client library for PHP
[![Build Status](https://travis-ci.org/influxdb/influxdb-php.svg?branch=master)](https://travis-ci.org/influxdb/influxdb-php)
[![Code Climate](https://codeclimate.com/github/influxdb/influxdb-php/badges/gpa.svg)](https://codeclimate.com/github/influxdb/influxdb-php)
[![Test Coverage](https://codeclimate.com/github/influxdb/influxdb-php/badges/coverage.svg)](https://codeclimate.com/github/influxdb/influxdb-php/coverage)
### Overview
A easy to use library for using InfluxDB with PHP.
The influxdb-php library was created to have php port of the python influxdb client.
This way there will be a common abstraction library between different programming languages.
### Installation
Installation can be done with composer:
composer require influxdb/influxdb-php:dev-master
### NOTE for PHP 5.3 and PHP 5.4 users
If you use either PHP 5.3 and PHP 5.4, the 0.1.x release is still supported (bug fixes and new release fixes).
The 0.1.x branch will work on PHP 5.3 and PHP 5.4 but doesn't contain all the features that the 1.0.0 release has such as UDP support.
### Getting started
Initialize a new client object:
```php
$client = new InfluxDB\Client($host, $port);
```
This will create a new client object which you can use to read and write points to InfluxDB.
It's also possible to create a client from a DSN (Data Source Name):
```php
// directly get the database object
$database = InfluxDB\Client::fromDSN(sprintf('influxdb://user:pass@%s:%s/%s', $host, $port, $dbname));
// get the client to retrieve other databases
$client = $database->getClient();
```
### Reading
To fetch records from InfluxDB you can do a query directly on a database:
```php
// fetch the database
$database = $client->selectDB('influx_test_db');
// executing a query will yield a resultset object
$result = $database->query('select * from test_metric LIMIT 5');
// get the points from the resultset yields an array
$points = $result->getPoints();
```
It's also possible to use the QueryBuilder object. This is a class that simplifies the process of building queries.
```php
// retrieve points with the query builder
$result = $database->getQueryBuilder()
->select('cpucount')
->from('test_metric')
->limit(2)
->getResultSet()
->getPoints();
// get the query from the QueryBuilder
$query = $database->getQueryBuilder()
->select('cpucount')
->from('test_metric')
->getQuery();
```
### Writing data
Writing data is done by providing an array of points to the writePoints method on a database:
```php
// create an array of points
$points = array(
new Point(
'test_metric', // name of the measurement
0.64, // the measurement value
['host' => 'server01', 'region' => 'us-west'], // optional tags
['cpucount' => 10], // optional additional fields
1435255849 // Time precision has to be set to seconds!
),
new Point(
'test_metric', // name of the measurement
0.84, // the measurement value
['host' => 'server01', 'region' => 'us-west'], // optional tags
['cpucount' => 10], // optional additional fields
1435255849 // Time precision has to be set to seconds!
)
);
// we are writing unix timestamps, which have a second precision
$result = $database->writePoints($points, Database::PRECISION_SECONDS);
```
It's possible to add multiple [fields](https://influxdb.com/docs/v0.9/concepts/key_concepts.html) when writing
measurements to InfluxDB. The point class allows one to easily write data in batches to influxDB.
The name of a measurement and the value are mandatory. Additional fields, tags and a timestamp are optional.
InfluxDB takes the current time as the default timestamp.
You can also write multiple fields to a measurement without specifying a value:
```php
$points = [
new Point(
'instance', // the name of the measurement
null, // measurement value
['host' => 'server01', 'region' => 'us-west'], // measurement tags
['cpucount' => 10, 'free' => 1], // measurement fields
exec('date +%s%N') // timestamp in nanoseconds on Linux ONLY
),
new Point(
'instance', // the name of the measurement
null, // measurement value
['host' => 'server01', 'region' => 'us-west'], // measurement tags
['cpucount' => 10, 'free' => 2], // measurement fields
exec('date +%s%N') // timestamp in nanoseconds on Linux ONLY
)
];
```
#### Writing data using udp
First, set your InfluxDB host to support incoming UDP sockets:
```ini
[udp]
enabled = true
bind-address = ":4444"
database = "test_db"
```
Then, configure the UDP driver in the client:
```php
// set the UDP driver in the client
$client->setDriver(new \InfluxDB\Driver\UDP($client->getHost(), 4444));
$points = [
new Point(
'test_metric',
0.84,
['host' => 'server01', 'region' => 'us-west'],
['cpucount' => 10],
exec('date +%s%N') // this will produce a nanosecond timestamp on Linux ONLY
)
];
// now just write your points like you normally would
$result = $database->writePoints($points);
```
Or simply use a DSN (Data Source Name) to send metrics using UDP:
```php
// get a database object using a DSN (Data Source Name)
$database = \InfluxDB\Client::fromDSN('udp+influxdb://username:pass@localhost:4444/test123');
// write your points
$result = $database->writePoints($points);
```
*Note:* It is import to note that precision will be *ignored* when you use UDP. You should always use nanosecond
precision when writing data to InfluxDB using UDP.
#### Timestamp precision
It's important to provide the correct precision when adding a timestamp to a Point object. This is because
if you specify a timestamp in seconds and the default (nanosecond) precision is set; the entered timestamp will be invalid.
```php
// Points will require a nanosecond precision (this is default as per influxdb standard)
$newPoints = $database->writePoints($points);
// Points will require second precision
$newPoints = $database->writePoints($points, Database::PRECISION_SECONDS);
// Points will require microsecond precision
$newPoints = $database->writePoints($points, Database::PRECISION_MICROSECONDS);
```
Please note that `exec('date + %s%N')` does NOT work under MacOS; you can use PHP's `microtime` to get a timestamp with microsecond precision, like such:
```php
list( $usec, $sec ) = explode(' ', microtime() );
$timestamp = sprintf( '%d%06d', $sec, $usec*1000000 );
```
### Creating databases
When creating a database a default retention policy is added. This retention policy does not have a duration
so the data will be flushed with the memory.
This library makes it easy to provide a retention policy when creating a database:
```php
// create the client
$client = new \InfluxDB\Client($host, $port, '', '');
// select the database
$database = $client->selectDB('influx_test_db');
// create the database with a retention policy
$result = $database->create(new RetentionPolicy('test', '5d', 1, true));
// check if a database exists then create it if it doesn't
$database = $client->selectDB('test_db');
if (!$database->exists()) {
$database->create(new RetentionPolicy('test', '1d', 2, true));
}
```
You can also alter retention policies:
```php
$database->alterRetentionPolicy(new RetentionPolicy('test', '2d', 5, true));
```
and list them:
```php
$result = $database->listRetentionPolicies();
```
You can add more retention policies to a database:
```php
$result = $database->createRetentionPolicy(new RetentionPolicy('test2', '30d', 1, true));
```
### Client functions
Some functions are too general for a database. So these are available in the client:
```php
// list users
$result = $client->listUsers();
// list databases
$result = $client->listDatabases();
```
### Admin functionality
You can use the client's $client->admin functionality to administer InfluxDB via the API.
```php
// add a new user without privileges
$client->admin->createUser('testuser123', 'testpassword');
// add a new user with ALL cluster-wide privileges
$client->admin->createUser('admin_user', 'password', \InfluxDB\Client\Admin::PRIVILEGE_ALL);
// drop user testuser123
$client->admin->dropUser('testuser123');
```
List all the users:
```php
// show a list of all users
$results = $client->admin->showUsers();
// show users returns a ResultSet object
$users = $results->getPoints();
```
#### Granting and revoking privileges
Granting permissions can be done on both the database level and cluster-wide.
To grant a user specific privileges on a database, provide a database object or a database name.
```php
// grant permissions using a database object
$database = $client->selectDB('test_db');
$client->admin->grant(\InfluxDB\Client\Admin::PRIVILEGE_READ, 'testuser123', $database);
// give user testuser123 read privileges on database test_db
$client->admin->grant(\InfluxDB\Client\Admin::PRIVILEGE_READ, 'testuser123', 'test_db');
// revoke user testuser123's read privileges on database test_db
$client->admin->revoke(\InfluxDB\Client\Admin::PRIVILEGE_READ, 'testuser123', 'test_db');
// grant a user cluster-wide privileges
$client->admin->grant(\InfluxDB\Client\Admin::PRIVILEGE_READ, 'testuser123');
// Revoke an admin's cluster-wide privileges
$client->admin->revoke(\InfluxDB\Client\Admin::PRIVILEGE_ALL, 'admin_user');
```
## Todo
* More unit tests
* Increase documentation (wiki?)
* Add more features to the query builder
* Add validation to RetentionPolicy
## Changelog
####1.0.1
* Added support for authentication in the guzzle driver
* Added admin functionality
####1.0.0
* -BREAKING CHANGE- Dropped support for PHP 5.3 and PHP 5.4
* Allowing for custom drivers
* UDP support
####0.1.2
* Added exists method to Database class
* Added time precision to database class
####0.1.1
* Merged repository to influxdb/influxdb-php
* Added unit test for createRetentionPolicy
* -BREAKING CHANGE- changed $client->db to $client->selectDB

View File

@ -1,47 +0,0 @@
{
"name": "influxdb/influxdb-php",
"description": "InfluxDB client library for PHP",
"license": "MIT",
"keywords": [
"influxdb",
"client",
"time series",
"influxdb client",
"influxdb class",
"influxdb library"
],
"minimum-stability": "dev",
"authors": [
{
"name": "Stephen Hoogendijk",
"email": "stephen@tca0.nl"
},
{
"name": "Daniel Martinez",
"email": "danimartcas@hotmail.com"
}
],
"require": {
"php": ">=5.5",
"guzzlehttp/guzzle": "6.*",
"symfony/event-dispatcher": "2.*"
},
"require-dev": {
"codeclimate/php-test-reporter": "0.*",
"symfony/config": "~2.8",
"symfony/console": "~2.8",
"symfony/filesystem": "~2.8",
"symfony/stopwatch": "~2.8",
"symfony/yaml": "~2.8"
},
"autoload": {
"psr-4": {
"InfluxDB\\": "src/InfluxDB"
}
},
"autoload-dev": {
"psr-4": {
"InfluxDB\\Test\\": "tests"
}
}
}

View File

@ -1,812 +0,0 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "ee3f2e2a4eb50f8de36c6efbff37fe71",
"packages": [
{
"name": "guzzlehttp/guzzle",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "1879fbe853b0c64d109e369c7aeff09849e62d1e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/1879fbe853b0c64d109e369c7aeff09849e62d1e",
"reference": "1879fbe853b0c64d109e369c7aeff09849e62d1e",
"shasum": ""
},
"require": {
"guzzlehttp/promises": "~1.0",
"guzzlehttp/psr7": "~1.1",
"php": ">=5.5.0"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "~4.0",
"psr/log": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.0-dev"
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle is a PHP HTTP client library",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"time": "2015-07-10 20:04:21"
},
{
"name": "guzzlehttp/promises",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "f596be052ef429a16b2f640812fcf84392dd38f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/f596be052ef429a16b2f640812fcf84392dd38f7",
"reference": "f596be052ef429a16b2f640812fcf84392dd38f7",
"shasum": ""
},
"require": {
"php": ">=5.5.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"time": "2015-06-30 16:39:54"
},
{
"name": "guzzlehttp/psr7",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "af0e1758de355eb113917ad79c3c0e3604bce4bd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/af0e1758de355eb113917ad79c3c0e3604bce4bd",
"reference": "af0e1758de355eb113917ad79c3c0e3604bce4bd",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": [
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "PSR-7 message implementation",
"keywords": [
"http",
"message",
"stream",
"uri"
],
"time": "2015-06-24 19:55:15"
},
{
"name": "psr/http-message",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"time": "2015-05-04 20:22:00"
},
{
"name": "symfony/event-dispatcher",
"version": "2.8.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/EventDispatcher.git",
"reference": "d7246885b7fe4cb5a2786bda34362d2f0e40b730"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/d7246885b7fe4cb5a2786bda34362d2f0e40b730",
"reference": "d7246885b7fe4cb5a2786bda34362d2f0e40b730",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~2.0,>=2.0.5|~3.0.0",
"symfony/dependency-injection": "~2.6|~3.0.0",
"symfony/expression-language": "~2.6|~3.0.0",
"symfony/phpunit-bridge": "~2.7|~3.0.0",
"symfony/stopwatch": "~2.3|~3.0.0"
},
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\EventDispatcher\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
"time": "2015-06-24 15:32:32"
}
],
"packages-dev": [
{
"name": "codeclimate/php-test-reporter",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/codeclimate/php-test-reporter.git",
"reference": "418ae782307841ac50fe26daa4cfe04520b0de9c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/codeclimate/php-test-reporter/zipball/418ae782307841ac50fe26daa4cfe04520b0de9c",
"reference": "418ae782307841ac50fe26daa4cfe04520b0de9c",
"shasum": ""
},
"require": {
"ext-curl": "*",
"php": ">=5.3",
"satooshi/php-coveralls": "0.6.*",
"symfony/console": ">=2.0"
},
"require-dev": {
"ext-xdebug": "*",
"phpunit/phpunit": "3.7.*@stable"
},
"bin": [
"composer/bin/test-reporter"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.1.x-dev"
}
},
"autoload": {
"psr-0": {
"CodeClimate\\Component": "src/",
"CodeClimate\\Bundle": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Code Climate",
"email": "hello@codeclimate.com",
"homepage": "https://codeclimate.com"
}
],
"description": "PHP client for reporting test coverage to Code Climate",
"homepage": "https://github.com/codeclimate/php-test-reporter",
"keywords": [
"codeclimate",
"coverage"
],
"time": "2015-04-18 14:43:54"
},
{
"name": "guzzle/guzzle",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle3.git",
"reference": "b3f5050cb6270c7a728a0b74ac2de50a262b3e02"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle3/zipball/b3f5050cb6270c7a728a0b74ac2de50a262b3e02",
"reference": "b3f5050cb6270c7a728a0b74ac2de50a262b3e02",
"shasum": ""
},
"require": {
"ext-curl": "*",
"php": ">=5.3.3",
"symfony/event-dispatcher": "~2.1"
},
"replace": {
"guzzle/batch": "self.version",
"guzzle/cache": "self.version",
"guzzle/common": "self.version",
"guzzle/http": "self.version",
"guzzle/inflection": "self.version",
"guzzle/iterator": "self.version",
"guzzle/log": "self.version",
"guzzle/parser": "self.version",
"guzzle/plugin": "self.version",
"guzzle/plugin-async": "self.version",
"guzzle/plugin-backoff": "self.version",
"guzzle/plugin-cache": "self.version",
"guzzle/plugin-cookie": "self.version",
"guzzle/plugin-curlauth": "self.version",
"guzzle/plugin-error-response": "self.version",
"guzzle/plugin-history": "self.version",
"guzzle/plugin-log": "self.version",
"guzzle/plugin-md5": "self.version",
"guzzle/plugin-mock": "self.version",
"guzzle/plugin-oauth": "self.version",
"guzzle/service": "self.version",
"guzzle/stream": "self.version"
},
"require-dev": {
"doctrine/cache": "~1.3",
"monolog/monolog": "~1.0",
"phpunit/phpunit": "3.7.*",
"psr/log": "~1.0",
"symfony/class-loader": "~2.1",
"zendframework/zend-cache": "2.*,<2.3",
"zendframework/zend-log": "2.*,<2.3"
},
"suggest": {
"guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.9-dev"
}
},
"autoload": {
"psr-0": {
"Guzzle": "src/",
"Guzzle\\Tests": "tests/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Guzzle Community",
"homepage": "https://github.com/guzzle/guzzle/contributors"
}
],
"description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"time": "2015-04-29 17:06:53"
},
{
"name": "psr/log",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
"shasum": ""
},
"type": "library",
"autoload": {
"psr-0": {
"Psr\\Log\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"keywords": [
"log",
"psr",
"psr-3"
],
"time": "2012-12-21 11:40:51"
},
{
"name": "satooshi/php-coveralls",
"version": "v0.6.1",
"source": {
"type": "git",
"url": "https://github.com/satooshi/php-coveralls.git",
"reference": "dd0df95bd37a7cf5c5c50304dfe260ffe4b50760"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/dd0df95bd37a7cf5c5c50304dfe260ffe4b50760",
"reference": "dd0df95bd37a7cf5c5c50304dfe260ffe4b50760",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-simplexml": "*",
"guzzle/guzzle": ">=3.0",
"php": ">=5.3",
"psr/log": "1.0.0",
"symfony/config": ">=2.0",
"symfony/console": ">=2.0",
"symfony/stopwatch": ">=2.2",
"symfony/yaml": ">=2.0"
},
"require-dev": {
"apigen/apigen": "2.8.*@stable",
"pdepend/pdepend": "dev-master",
"phpmd/phpmd": "dev-master",
"phpunit/php-invoker": ">=1.1.0,<1.2.0",
"phpunit/phpunit": "3.7.*@stable",
"sebastian/finder-facade": "dev-master",
"sebastian/phpcpd": "1.4.*@stable",
"squizlabs/php_codesniffer": "1.4.*@stable",
"theseer/fdomdocument": "dev-master"
},
"bin": [
"composer/bin/coveralls"
],
"type": "library",
"autoload": {
"psr-0": {
"Contrib\\Component": "src/",
"Contrib\\Bundle": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kitamura Satoshi",
"email": "with.no.parachute@gmail.com",
"homepage": "https://www.facebook.com/satooshi.jp"
}
],
"description": "PHP client library for Coveralls API",
"homepage": "https://github.com/satooshi/php-coveralls",
"keywords": [
"ci",
"coverage",
"github",
"test"
],
"time": "2013-05-04 08:07:33"
},
{
"name": "symfony/config",
"version": "2.8.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/Config.git",
"reference": "358ec929e494b6f12d8508d88357cbd7383a10ca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Config/zipball/358ec929e494b6f12d8508d88357cbd7383a10ca",
"reference": "358ec929e494b6f12d8508d88357cbd7383a10ca",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
"symfony/filesystem": "~2.3|~3.0.0"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7|~3.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Config\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
"time": "2015-07-09 16:11:14"
},
{
"name": "symfony/console",
"version": "2.8.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/Console.git",
"reference": "fd85e7517e79a2bceafcee8f7e8b7bbd0919a90a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Console/zipball/fd85e7517e79a2bceafcee8f7e8b7bbd0919a90a",
"reference": "fd85e7517e79a2bceafcee8f7e8b7bbd0919a90a",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/event-dispatcher": "~2.1|~3.0.0",
"symfony/phpunit-bridge": "~2.7|~3.0.0",
"symfony/process": "~2.1|~3.0.0"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/process": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2015-07-16 12:22:14"
},
{
"name": "symfony/filesystem",
"version": "2.8.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/Filesystem.git",
"reference": "9f70c5625a32b2f1e6fc37222f52b4e0eb437b0e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/9f70c5625a32b2f1e6fc37222f52b4e0eb437b0e",
"reference": "9f70c5625a32b2f1e6fc37222f52b4e0eb437b0e",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7|~3.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
"time": "2015-07-09 16:11:14"
},
{
"name": "symfony/stopwatch",
"version": "2.8.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/Stopwatch.git",
"reference": "cd5f0dc1d3d0e2c83461dad77e20a9186beb6146"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Stopwatch/zipball/cd5f0dc1d3d0e2c83461dad77e20a9186beb6146",
"reference": "cd5f0dc1d3d0e2c83461dad77e20a9186beb6146",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7|~3.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Stopwatch\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Stopwatch Component",
"homepage": "https://symfony.com",
"time": "2015-07-01 18:24:26"
},
{
"name": "symfony/yaml",
"version": "2.8.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
"reference": "000e7fc2653335cd42c6d21405dac1c74224a387"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/000e7fc2653335cd42c6d21405dac1c74224a387",
"reference": "000e7fc2653335cd42c6d21405dac1c74224a387",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7|~3.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2015-07-01 14:16:54"
}
],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=5.5"
},
"platform-dev": []
}

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="Influxdb-php tests">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
<logging>
<log type="tap" target="build/report.tap"/>
<log type="junit" target="build/report.junit.xml"/>
<log type="coverage-html" target="build/coverage" charset="UTF-8" yui="true" highlight="true"/>
<log type="coverage-text" target="build/coverage.txt"/>
<log type="coverage-clover" target="build/logs/clover.xml"/>
</logging>
</phpunit>

View File

@ -1,324 +0,0 @@
<?php
namespace InfluxDB;
use InfluxDB\Client\Admin;
use InfluxDB\Client\Exception as ClientException;
use InfluxDB\Driver\DriverInterface;
use InfluxDB\Driver\Exception as DriverException;
use InfluxDB\Driver\Guzzle;
use InfluxDB\Driver\QueryDriverInterface;
use InfluxDB\Driver\UDP;
/**
* Class Client
*
* @package InfluxDB
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
class Client
{
/**
* @var Admin
*/
public $admin;
/**
* @var string
*/
protected $host = '';
/**
* @var int
*/
protected $port = 8086;
/**
* @var string
*/
protected $username = '';
/**
* @var string
*/
protected $password = '';
/**
* @var int
*/
protected $timeout = 0;
/**
* @var bool
*/
protected $scheme = 'http';
/**
* @var bool
*/
protected $verifySSL = false;
/**
* @var bool
*/
protected $useUdp = false;
/**
* @var int
*/
protected $udpPort = 4444;
/**
* @var
*/
protected $baseURI;
/**
* @var \Guzzle\Http\Client
*/
protected $httpClient;
/**
* @var array
*/
protected $options = array();
/**
* @var DriverInterface
*/
protected $driver;
/**
* @param string $host
* @param int $port
* @param string $username
* @param string $password
* @param bool $ssl
* @param bool $verifySSL
* @param int $timeout
*/
public function __construct(
$host,
$port = 8086,
$username = '',
$password = '',
$ssl = false,
$verifySSL = true,
$timeout = 0
) {
$this->host = (string) $host;
$this->port = (int) $port;
$this->username = (string) $username;
$this->password = (string) $password;
$this->timeout = (int) $timeout;
$this->verifySSL = (bool) $verifySSL;
if ($ssl) {
$this->scheme = 'https';
$this->options['verify'] = $verifySSL;
}
// the the base URI
$this->baseURI = sprintf('%s://%s:%d', $this->scheme, $this->host, $this->port);
// set the default driver to guzzle
$this->driver = new Guzzle(
new \GuzzleHttp\Client(
[
'timeout' => $this->timeout,
'base_uri' => $this->baseURI,
'verify' => $this->verifySSL
]
)
);
$this->admin = new Admin($this);
}
/**
* Use the given database
*
* @param string $name
* @return Database
*/
public function selectDB($name)
{
return new Database($name, $this);
}
/**
* Query influxDB
*
* @param string $database
* @param string $query
* @param array $parameters
*
* @return ResultSet
* @throws Exception
*/
public function query($database, $query, $parameters = [])
{
if (!$this->driver instanceof QueryDriverInterface) {
throw new Exception('The currently configured driver does not support query operations');
}
if ($database) {
$parameters['db'] = $database;
}
$driver = $this->getDriver();
$parameters = [
'url' => 'query?' . http_build_query(array_merge(['q' => $query], $parameters)),
'database' => $database,
'method' => 'get'
];
// add authentication to the driver if needed
if (!empty($this->username) && !empty($this->password)) {
$parameters += ['auth' => [$this->username, $this->password]];
}
$driver->setParameters($parameters);
try {
// perform the query and return the resultset
return $driver->query();
} catch (DriverException $e) {
throw new Exception('Query has failed', $e->getCode(), $e);
}
}
/**
* List all the databases
*/
public function listDatabases()
{
$result = $this->query(null, 'SHOW DATABASES')->getPoints();
return $this->pointsToArray($result);
}
/**
* List all the users
*
* @return array
* @throws Exception
*/
public function listUsers()
{
$result = $this->query(null, 'SHOW USERS')->getPoints();
return $this->pointsToArray($result);
}
/**
* Build the client from a dsn
* Examples:
*
* https+influxdb://username:pass@localhost:8086/databasename
* udp+influxdb://username:pass@localhost:4444/databasename
*
* @param string $dsn
* @param int $timeout
* @param bool $verifySSL
*
*@return Client|Database
* @throws ClientException
*/
public static function fromDSN($dsn, $timeout = 0, $verifySSL = false)
{
$connParams = parse_url($dsn);
$schemeInfo = explode('+', $connParams['scheme']);
$dbName = null;
$modifier = null;
$scheme = $schemeInfo[0];
if (isset($schemeInfo[1])) {
$modifier = strtolower($schemeInfo[0]);
$scheme = $schemeInfo[1];
}
if ($scheme != 'influxdb') {
throw new ClientException($scheme . ' is not a valid scheme');
}
$ssl = $modifier === 'https' ? true : false;
$dbName = $connParams['path'] ? substr($connParams['path'], 1) : null;
$client = new self(
$connParams['host'],
$connParams['port'],
$connParams['user'],
$connParams['pass'],
$ssl,
$verifySSL,
$timeout
);
// set the UDP driver when the DSN specifies UDP
if ($modifier == 'udp') {
$client->setDriver(new UDP($connParams['host'], $connParams['port']));
}
return ($dbName ? $client->selectDB($dbName) : $client);
}
/**
* @return mixed
*/
public function getBaseURI()
{
return $this->baseURI;
}
/**
* @return int
*/
public function getTimeout()
{
return $this->timeout;
}
/**
* @param Driver\DriverInterface $driver
*/
public function setDriver(DriverInterface $driver)
{
$this->driver = $driver;
}
/**
* @return DriverInterface|QueryDriverInterface
*/
public function getDriver()
{
return $this->driver;
}
/**
* @return string
*/
public function getHost()
{
return $this->host;
}
/**
* @param Point[] $points
* @return array
*/
protected function pointsToArray(array $points)
{
$names = [];
foreach ($points as $item) {
$names[] = $item['name'];
}
return $names;
}
}

View File

@ -1,158 +0,0 @@
<?php
/**
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
namespace InfluxDB\Client;
use InfluxDB\Client;
use InfluxDB\Database;
/**
* Class Admin
*
* @package InfluxDB\Client
*/
class Admin
{
/**
* @var Client
*/
private $client;
const PRIVILEGE_READ = 'READ';
const PRIVILEGE_WRITE = 'WRITE';
const PRIVILEGE_ALL= 'ALL';
public function __construct(Client $client)
{
$this->client = $client;
}
/**
* Create a user
*
* @param string $username
* @param string $password
*
* @param string $privilege
*
* @throws \InfluxDB\Exception
* @return \InfluxDB\ResultSet
*/
public function createUser($username, $password, $privilege = null)
{
$query = sprintf('CREATE USER %s WITH PASSWORD \'%s\'', $username, $password);
if ($privilege) {
$query .= " WITH $privilege PRIVILEGES";
}
return $this->client->query(null, $query);
}
/**
* @param string $username
*
* @return \InfluxDB\ResultSet
* @throws \InfluxDB\Exception
*/
public function dropUser($username)
{
return $this->client->query(null, 'DROP USER ' . $username);
}
/**
* Change a users password
*
* @param string $username
* @param string $newPassword
*
* @return \InfluxDB\ResultSet
* @throws \InfluxDB\Exception
*/
public function changeUserPassword($username, $newPassword)
{
return $this->client->query(null, "SET PASSWORD FOR $username = '$newPassword'");
}
/**
* Shows a list of all the users
*
* @return \InfluxDB\ResultSet
* @throws \InfluxDB\Exception
*/
public function showUsers()
{
return $this->client->query(null, "SHOW USERS");
}
/**
* Grants permissions
*
* @param string $privilege
* @param string $username
* @param Database|string $database
*
* @return \InfluxDB\ResultSet
*/
public function grant($privilege, $username, $database = null)
{
return $this->executePrivilege('GRANT', $privilege, $username, $database);
}
/**
* Revokes permissions
*
* @param string $privilege
* @param string $username
* @param Database|string $database
*
* @throws \InfluxDB\Exception
* @return \InfluxDB\ResultSet
*/
public function revoke($privilege, $username, $database = null)
{
return $this->executePrivilege('REVOKE', $privilege, $username, $database);
}
/**
* @param string $type
* @param string $privilege
* @param string $username
* @param Database|string $database
*
* @throws \InfluxDB\Exception
* @return \InfluxDB\ResultSet
*/
private function executePrivilege($type, $privilege, $username, $database = null)
{
if (!in_array($privilege, [self::PRIVILEGE_READ, self::PRIVILEGE_WRITE, self::PRIVILEGE_ALL])) {
throw new Exception($privilege . ' is not a valid privileges, allowed privileges: READ, WRITE, ALL');
}
if ($privilege != self::PRIVILEGE_ALL && !$database) {
throw new Exception('Only grant ALL cluster-wide privileges are allowed');
}
$database = ($database instanceof Database ? $database->getName() : (string) $database);
$query = "$type $privilege";
if ($database) {
$query .= sprintf(' ON %s ', $database);
} else {
$query .= " PRIVILEGES ";
}
if ($username && $type == 'GRANT') {
$query .= "TO $username";
} elseif ($username && $type == 'REVOKE') {
$query .= "FROM $username";
}
return $this->client->query(null, $query);
}
}

View File

@ -1,12 +0,0 @@
<?php
namespace InfluxDB\Client;
/**
* Class Exception
*
* @package InfluxDB\Client
*/
class Exception extends \InfluxDB\Exception
{
}

View File

@ -1,232 +0,0 @@
<?php
namespace InfluxDB;
use InfluxDB\Database\Exception as DatabaseException;
use InfluxDB\Database\RetentionPolicy;
use InfluxDB\Query\Builder as QueryBuilder;
/**
* Class Database
*
* @package InfluxDB
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
class Database
{
/**
* The name of the Database
*
* @var string
*/
protected $name = '';
/**
* @var Client
*/
protected $client;
/**
* Precision constants
*/
const PRECISION_NANOSECONDS = 'n';
const PRECISION_MICROSECONDS = 'u';
const PRECISION_MILLISECONDS = 'ms';
const PRECISION_SECONDS = 's';
const PRECISION_MINUTES = 'm';
const PRECISION_HOURS = 'h';
/**
* Construct a database object
*
* @param string $name
* @param Client $client
*/
public function __construct($name, Client $client)
{
if (empty($name)) {
throw new \InvalidArgumentException('No database name provided');
}
$this->name = (string) $name;
$this->client = $client;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Query influxDB
*
* @param string $query
* @param array $params
* @return ResultSet
* @throws Exception
*/
public function query($query, $params = [])
{
return $this->client->query($this->name, $query, $params);
}
/**
* Create this database
*
* @param RetentionPolicy $retentionPolicy
* @return ResultSet
* @throws DatabaseException
* @throws Exception
*/
public function create(RetentionPolicy $retentionPolicy = null)
{
try {
$this->query(sprintf('CREATE DATABASE %s', $this->name));
if ($retentionPolicy) {
$this->createRetentionPolicy($retentionPolicy);
}
} catch (\Exception $e) {
throw new DatabaseException(
sprintf('Failed to created database %s', $this->name),
$e->getCode(),
$e
);
}
}
/**
* @param RetentionPolicy $retentionPolicy
* @return ResultSet
*/
public function createRetentionPolicy(RetentionPolicy $retentionPolicy)
{
return $this->query($this->getRetentionPolicyQuery('CREATE', $retentionPolicy));
}
/**
* Writes points into InfluxDB
*
* @param Point[] $points Array of points
* @param string $precision The timestamp precision (defaults to nanoseconds)
* @return bool
* @throws Exception
*/
public function writePoints(array $points, $precision = self::PRECISION_NANOSECONDS)
{
$payload = array_map(
function (Point $point) {
return (string) $point;
},
$points
);
try {
$driver = $this->client->getDriver();
$parameters = [
'url' => sprintf('write?db=%s&precision=%s', $this->name, $precision),
'database' => $this->name,
'method' => 'post'
];
// add authentication to the driver if needed
if (!empty($this->username) && !empty($this->password)) {
$parameters += ['auth' => [$this->username, $this->password]];
}
$driver->setParameters($parameters);
// send the points to influxDB
$driver->write(implode(PHP_EOL, $payload));
return $driver->isSuccess();
} catch (\Exception $e) {
throw new Exception($e->getMessage(), $e->getCode());
}
}
/**
* @return bool
*/
public function exists()
{
$databases = $this->client->listDatabases();
return in_array($this->name, $databases);
}
/**
* @param RetentionPolicy $retentionPolicy
*/
public function alterRetentionPolicy(RetentionPolicy $retentionPolicy)
{
$this->query($this->getRetentionPolicyQuery('ALTER', $retentionPolicy));
}
/**
* @return array
* @throws Exception
*/
public function listRetentionPolicies()
{
return $this->query(sprintf('SHOW RETENTION POLICIES %s', $this->name))->getPoints();
}
/**
* Drop this database
*/
public function drop()
{
$this->query(sprintf('DROP DATABASE %s', $this->name));
}
/**
* Retrieve the query builder
*
* @return QueryBuilder
*/
public function getQueryBuilder()
{
return new QueryBuilder($this);
}
/**
* @return Client
*/
public function getClient()
{
return $this->client;
}
/**
* @param string $method
* @param RetentionPolicy $retentionPolicy
* @return string
*/
protected function getRetentionPolicyQuery($method, RetentionPolicy $retentionPolicy)
{
if (!in_array($method, ['CREATE', 'ALTER'])) {
throw new \InvalidArgumentException(sprintf('%s is not a valid method'));
}
$query = sprintf(
'%s RETENTION POLICY %s ON %s DURATION %s REPLICATION %s',
$method,
$retentionPolicy->name,
$this->name,
$retentionPolicy->duration,
$retentionPolicy->replication
);
if ($retentionPolicy->default) {
$query .= " DEFAULT";
}
return $query;
}
}

View File

@ -1,10 +0,0 @@
<?php
namespace InfluxDB\Database;
/**
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
class Exception extends \InfluxDB\Exception
{
}

View File

@ -1,48 +0,0 @@
<?php
namespace InfluxDB\Database;
/**
* Class RetentionPolicy
*
* @package InfluxDB\Database
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
class RetentionPolicy
{
/**
* @var string
*/
public $name;
/**
* @var string
*/
public $duration;
/**
* @var int
*/
public $replication;
/**
* @var bool
*/
public $default;
/**
* @param string $name
* @param string $duration
* @param int $replication
* @param bool $default
*
* @todo validate duration, replication
*/
public function __construct($name, $duration = '1d', $replication = 1, $default = false)
{
$this->name = (string) $name;
$this->duration = $duration;
$this->replication = (int) $replication;
$this->default = (bool) $default;
}
}

View File

@ -1,49 +0,0 @@
<?php
/**
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
namespace InfluxDB\Driver;
/**
* Interface DriverInterface
*
* @package InfluxDB\Driver
*/
interface DriverInterface
{
/**
* Called by the client write() method, will pass an array of required parameters such as db name
*
* will contain the following parameters:
*
* [
* 'database' => 'name of the database',
* 'url' => 'URL to the resource',
* 'method' => 'HTTP method used'
* ]
*
* @param array $parameters
*
* @return mixed
*/
public function setParameters(array $parameters);
/**
* Send the data
*
* @param $data
*
* @return mixed
*/
public function write($data = null);
/**
* Should return if sending the data was successful
*
* @return bool
*/
public function isSuccess();
}

View File

@ -1,16 +0,0 @@
<?php
/**
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
namespace InfluxDB\Driver;
/**
* Class Exception
*
* @package InfluxDB\Driver
*/
class Exception extends \InfluxDB\Client\Exception
{
}

View File

@ -1,134 +0,0 @@
<?php
/**
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
namespace InfluxDB\Driver;
use GuzzleHttp\Client;
use Guzzle\Http\Message\Response;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Psr7\Request;
use InfluxDB\ResultSet;
/**
* Class Guzzle
*
* @package InfluxDB\Driver
*/
class Guzzle implements DriverInterface, QueryDriverInterface
{
/**
* Array of options
*
* @var array
*/
private $parameters;
/**
* @var Client
*/
private $httpClient;
/**
* @var Response
*/
private $response;
/**
* Set the config for this driver
*
* @param Client $client
*
* @return mixed
*/
public function __construct(Client $client)
{
$this->httpClient = $client;
}
/**
* Called by the client write() method, will pass an array of required parameters such as db name
*
* will contain the following parameters:
*
* [
* 'database' => 'name of the database',
* 'url' => 'URL to the resource',
* 'method' => 'HTTP method used'
* ]
*
* @param array $parameters
*
* @return mixed
*/
public function setParameters(array $parameters)
{
$this->parameters = $parameters;
}
/**
* Send the data
*
* @param $data
*
* @throws Exception
* @return mixed
*/
public function write($data = null)
{
$this->response = $this->httpClient->post($this->parameters['url'], $this->getRequestParameters($data));
}
/**
* @throws Exception
* @return ResultSet
*/
public function query()
{
$response = $this->httpClient->get($this->parameters['url'], $this->getRequestParameters());
$raw = (string) $response->getBody();
$responseJson = json_encode($raw);
if (isset($responseJson->error)) {
throw new Exception($responseJson->error);
}
return new ResultSet($raw);
}
/**
* Should return if sending the data was successful
*
* @return bool
*/
public function isSuccess()
{
return in_array($this->response->getStatusCode(), ['200', '204']);
}
/**
* @param null $data
*
* @return array
*/
protected function getRequestParameters($data = null)
{
$requestParameters = ['http_errors' => false];
if ($data) {
$requestParameters += ['body' => $data];
}
if (isset($this->parameters['auth'])) {
$requestParameters += ['auth' => $this->parameters['auth']];
}
return $requestParameters;
}
}

View File

@ -1,22 +0,0 @@
<?php
/**
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
namespace InfluxDB\Driver;
use InfluxDB\ResultSet;
/**
* Interface QueryDriverInterface
*
* @package InfluxDB\Driver
*/
interface QueryDriverInterface
{
/**
* @return ResultSet
*/
public function query();
}

View File

@ -1,90 +0,0 @@
<?php
/**
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
namespace InfluxDB\Driver;
use Symfony\Component\Config\Definition\Exception\Exception;
/**
* Class UDP
*
* @package InfluxDB\Driver
*/
class UDP implements DriverInterface
{
/**
* Parameters
*
* @var array
*/
private $parameters;
/**
* @var array
*/
private $config;
/**
* @param string $host IP/hostname of the InfluxDB host
* @param int $port Port of the InfluxDB process
*/
public function __construct($host, $port)
{
$this->config['host'] = $host;
$this->config['port'] = $port;
}
/**
* Called by the client write() method, will pass an array of required parameters such as db name
*
* will contain the following parameters:
*
* [
* 'database' => 'name of the database',
* 'url' => 'URL to the resource',
* 'method' => 'HTTP method used'
* ]
*
* @param array $parameters
*
* @return mixed
*/
public function setParameters(array $parameters)
{
$this->parameters = $parameters;
}
/**
* Send the data
*
* @param $data
*
* @return mixed
*/
public function write($data = null)
{
$host = sprintf('udp://%s:%d', $this->config['host'], $this->config['port']);
// stream the data using UDP and suppress any errors
$stream = @stream_socket_client($host);
@stream_socket_sendto($stream, $data);
@fclose($stream);
return true;
}
/**
* Should return if sending the data was successful
*
* @return bool
*/
public function isSuccess()
{
return true;
}
}

View File

@ -1,10 +0,0 @@
<?php
namespace InfluxDB;
/**
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
class Exception extends \Exception
{
}

View File

@ -1,126 +0,0 @@
<?php
namespace InfluxDB;
use InfluxDB\Database\Exception as DatabaseException;
/**
* Class Point
*
* @package InfluxDB
*/
class Point
{
/**
* @var string
*/
private $measurement;
/**
* @var array
*/
private $tags = [];
/**
* @var array
*/
private $fields = [];
/**
* @var string
*/
private $timestamp;
/**
* The timestamp is optional. If you do not specify a timestamp the servers
* local timestamp will be used
*
* @param string $measurement
* @param float $value
* @param array $tags
* @param array $additionalFields
* @param null $timestamp
* @throws DatabaseException
*/
public function __construct(
$measurement,
$value = null,
array $tags = array(),
array $additionalFields = array(),
$timestamp = null
) {
if (empty($measurement)) {
throw new DatabaseException('Invalid measurement name provided');
}
$this->measurement = (string) $measurement;
$this->tags = $tags;
$this->fields = $additionalFields;
if ($value) {
$this->fields['value'] = $value;
}
if ($timestamp && !$this->isValidTimeStamp($timestamp)) {
throw new DatabaseException(sprintf('%s is not a valid timestamp', $timestamp));
}
$this->timestamp = $timestamp;
}
/**
* @see: https://influxdb.com/docs/v0.9/concepts/reading_and_writing_data.html
*
* Should return this format
* 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000'
*/
public function __toString()
{
$string = $this->measurement;
if (count($this->tags) > 0) {
$string .= ',' . $this->arrayToString($this->tags);
}
$string .= ' ' . $this->arrayToString($this->fields);
if ($this->timestamp) {
$string .= ' '.$this->timestamp;
}
return $string;
}
/**
* @param array $arr
* @return string
*/
private function arrayToString(array $arr)
{
$strParts = [];
foreach ($arr as $key => $value) {
$strParts[] = sprintf('%s=%s', $key, $value);
}
return implode(',', $strParts);
}
/**
* @param int $timestamp
* @return bool
*/
private function isValidTimeStamp($timestamp)
{
if ((int) $timestamp === $timestamp) {
return true;
}
if ($timestamp <= PHP_INT_MAX && $timestamp >= ~PHP_INT_MAX) {
return true;
}
return false;
}
}

View File

@ -1,271 +0,0 @@
<?php
namespace InfluxDB\Query;
use InfluxDB\Database;
use InfluxDB\ResultSet;
/**
* Class Builder
*
* Abstraction class for getting time series out of InfluxDB
*
* Sample usage:
*
* $series = new QueryBuilder($db);
* $series->percentile(95)->setTimeRange($timeFrom, $timeTo)->getResult();
*
* $series->select('*')->from('*')->getResult();
*
* @todo add inner join
* @todo add merge
*
* @package InfluxDB\Query
* @author Stephen "TheCodeAssassin" Hoogendijk <s.hoogendijk@tech.leaseweb.com>
*/
class Builder
{
/**
* @var Database
*/
protected $db;
/**
* @var string
*/
protected $selection = '*';
/**
* @var string[]
*/
protected $where = array();
/**
* @var string
*/
protected $startTime;
/**
* @var string
*/
protected $endTime;
/**
* @var string
*/
protected $metric;
/**
* @var string
*/
protected $limitClause = '';
/**
* @param Database $db
*/
public function __construct(Database $db)
{
$this->db = $db;
}
/**
* @param string $metric The metric to select (required)
* @return $this
*/
public function from($metric)
{
$this->metric = $metric;
return $this;
}
/**
* Custom select method
*
* example:
*
* $series->select('sum(value)',
*
* @param string $customSelect
* @return $this
*/
public function select($customSelect)
{
$this->selection = $customSelect;
return $this;
}
/**
* @param array $conditions
*
* Example: array('time > now()', 'time < now() -1d');
*
* @return $this
*/
public function where(array $conditions)
{
foreach ($conditions as $condition) {
$this->where[] = $condition;
}
return $this;
}
/**
* @param string $field
* @return $this
*/
public function count($field = 'type')
{
$this->selection = sprintf('count(%s)', $field);
return $this;
}
/**
* @param string $field
* @return $this
*/
public function median($field = 'type')
{
$this->selection = sprintf('median(%s)', $field);
return $this;
}
/**
* @param string $field
* @return $this
*/
public function mean($field = 'type')
{
$this->selection = sprintf('mean(%s)', $field);
return $this;
}
/**
* @param string $field
* @return $this
*/
public function sum($field = 'type')
{
$this->selection = sprintf('sum(%s)', $field);
return $this;
}
/**
* @param string $field
* @return $this
*/
public function first($field = 'type')
{
$this->selection = sprintf('first(%s)', $field);
return $this;
}
/**
* @param string $field
* @return $this
*/
public function last($field = 'type')
{
$this->selection = sprintf('last(%s)', $field);
return $this;
}
/**
* Set's the time range to select data from
*
* @param int $from
* @param int $to
* @return $this
*/
public function setTimeRange($from, $to)
{
$fromDate = date('Y-m-d H:i:s', (int) $from);
$toDate = date('Y-m-d H:i:s', (int) $to);
$this->where(array("time > '$fromDate'", "time < '$toDate'"));
return $this;
}
/**
* @param int $percentile Percentage to select (for example 95 for 95th percentile billing)
*
* @return $this
*/
public function percentile($percentile = 95)
{
$this->selection = sprintf('percentile(value, %d)', (int) $percentile);
return $this;
}
/**
* Limit the ResultSet to n records
*
* @param int $count
*
* @return $this
*/
public function limit($count)
{
$this->limitClause = sprintf(' LIMIT %s', (int) $count);
return $this;
}
/**
* @return string
*/
public function getQuery()
{
return $this->parseQuery();
}
/**
* Gets the result from the database (builds the query)
*
* @return ResultSet
*/
public function getResultSet()
{
return $this->db->query($this->parseQuery());
}
/**
* @return string
*/
protected function parseQuery()
{
$query = sprintf("SELECT %s FROM %s", $this->selection, $this->metric);
if (! $this->metric) {
throw new \InvalidArgumentException('No metric provided to from()');
}
for ($i = 0; $i < count($this->where); $i++) {
$selection = 'WHERE';
if ($i > 0) {
$selection = 'AND';
}
$clause = $this->where[$i];
$query .= ' ' . $selection . ' ' . $clause;
}
if ($this->limitClause) {
$query .= $this->limitClause;
}
return $query;
}
}

View File

@ -1,10 +0,0 @@
<?php
namespace InfluxDB\Query;
/**
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
class Exception extends \InfluxDB\Exception
{
}

View File

@ -1,106 +0,0 @@
<?php
namespace InfluxDB;
use InfluxDB\Client\Exception as ClientException;
/**
* Class ResultSet
*
* @package InfluxDB
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
class ResultSet
{
/**
* @var array|mixed
*/
protected $parsedResults = [];
/**
* @param string $raw
* @throws \InvalidArgumentException
* @throws Exception
*/
public function __construct($raw)
{
$this->parsedResults = json_decode((string) $raw, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \InvalidArgumentException('Invalid JSON');
}
// There was an error in the query thrown by influxdb
if (isset($this->parsedResults['error'])) {
throw new ClientException($this->parsedResults['error']);
}
// Check if there are errors in the first serie
if (isset($this->parsedResults['results'][0]['error'])) {
throw new ClientException($this->parsedResults['results'][0]['error']);
}
}
/**
* @param $metricName
* @param array $tags
* @return array $points
*/
public function getPoints($metricName = '', array $tags = array())
{
$points = [];
$series = $this->getSeries();
foreach ($series as $serie) {
if ((empty($metricName) && empty($tags)
|| $serie['name'] == $metricName
|| (isset($serie['tags']) && array_intersect($tags, $serie['tags'])))
&& isset($serie['values'])
) {
$points = array_merge($points, $this->getPointsFromSerie($serie));
}
}
return $points;
}
/**
* @see: https://influxdb.com/docs/v0.9/concepts/reading_and_writing_data.html
*
* results is an array of objects, one for each query,
* each containing the keys for a series
*
* @throws Exception
* @return array $series
*/
public function getSeries()
{
$series = array_map(
function ($object) {
if (isset($object['error'])) {
throw new ClientException($object['error']);
}
return isset($object['series']) ? $object['series'] : [];
},
$this->parsedResults['results']
);
return array_shift($series);
}
/**
* @param array $serie
* @return array
*/
private function getPointsFromSerie(array $serie)
{
$points = [];
foreach ($serie['values'] as $point) {
$points[] = array_combine($serie['columns'], $point);
}
return $points;
}
}

View File

@ -1,7 +0,0 @@
<?php
/**
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
// autoload dependencies
require __DIR__ . '/../vendor/autoload.php';

View File

@ -1,124 +0,0 @@
<?php
/**
* @author Stephen "TheCodeAssassin" Hoogendijk
*/
namespace InfluxDB\Test;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use InfluxDB\Client;
use InfluxDB\Database;
use InfluxDB\Driver\Guzzle;
use InfluxDB\ResultSet;
use PHPUnit_Framework_MockObject_MockObject;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Psr7\Response;
/**
* @property mixed resultData
*/
abstract class AbstractTest extends \PHPUnit_Framework_TestCase
{
/** @var Client|PHPUnit_Framework_MockObject_MockObject $client */
protected $mockClient;
/**
* @var string
*/
protected $emptyResult = '{"results":[{}]}';
/**
* @var ResultSet
*/
protected $mockResultSet;
/** @var Database $database */
protected $database = null;
public function setUp()
{
$this->mockClient = $this->getMockBuilder('\InfluxDB\Client')
->disableOriginalConstructor()
->getMock();
$this->resultData = file_get_contents(dirname(__FILE__) . '/result.example.json');
$this->mockClient->expects($this->any())
->method('getBaseURI')
->will($this->returnValue($this->equalTo('http://localhost:8086')));
$this->mockClient->expects($this->any())
->method('query')
->will($this->returnValue(new ResultSet($this->resultData)));
$httpMockClient = new Guzzle($this->buildHttpMockClient(''));
// make sure the client has a valid driver
$this->mockClient->expects($this->any())
->method('getDriver')
->will($this->returnValue($httpMockClient));
$this->database = new Database('influx_test_db', $this->mockClient);
}
/**
* @return mixed
*/
public function getMockResultSet()
{
return $this->mockResultSet;
}
/**
* @param mixed $mockResultSet
*/
public function setMockResultSet($mockResultSet)
{
$this->mockResultSet = $mockResultSet;
}
/**
* @return GuzzleClient
*/
public function buildHttpMockClient($body)
{
// Create a mock and queue two responses.
$mock = new MockHandler([new Response(200, array(), $body)]);
$handler = HandlerStack::create($mock);
return new GuzzleClient(['handler' => $handler]);
}
/**
* @return string
*/
public function getEmptyResult()
{
return $this->emptyResult;
}
/**
* @param bool $emptyResult
*
* @return PHPUnit_Framework_MockObject_MockObject|Client
*/
public function getClientMock($emptyResult = false)
{
$mockClient = $this->getMockBuilder('\InfluxDB\Client')
->disableOriginalConstructor()
->getMock();
if ($emptyResult) {
$mockClient->expects($this->once())
->method('query')
->will($this->returnValue(new ResultSet($this->getEmptyResult())));
}
return $mockClient;
}
}

View File

@ -1,72 +0,0 @@
<?php
namespace InfluxDB\Test;
use InfluxDB\Client;
use InfluxDB\Database;
use InfluxDB\Driver\Guzzle;
use InfluxDB\Point;
use InfluxDB\ResultSet;
use PHPUnit_Framework_MockObject_MockObject;
use PHPUnit_Framework_TestCase;
class AdminTest extends AbstractTest
{
/**
*
*/
public function setUp()
{
parent::setUp();
}
/**
*
*/
public function testCreateUser()
{
$adminObject = $this->getAdminObject(true);
$this->assertEquals(
new ResultSet($this->emptyResult),
$adminObject->createUser('test', 'test', Client\Admin::PRIVILEGE_ALL)
);
}
public function testChangeUserPassword()
{
$adminObject = $this->getAdminObject(true);
$this->assertEquals(
new ResultSet($this->emptyResult),
$adminObject->changeUserPassword('test', 'test')
);
}
public function testShowUsers()
{
$testJson = file_get_contents(dirname(__FILE__) . '/result-test-users.example.json');
$clientMock = $this->getClientMock();
$testResult = new ResultSet($testJson);
$clientMock->expects($this->once())
->method('query')
->will($this->returnValue($testResult));
$adminMock = new Client\Admin($clientMock);
$this->assertEquals($testResult, $adminMock->showUsers());
}
/**
* @return Client\Admin
*/
private function getAdminObject()
{
return new Client\Admin($this->getClientMock(true));
}
}

View File

@ -1,60 +0,0 @@
<?php
namespace InfluxDB\Test;
use InfluxDB\Client;
use InfluxDB\Driver\Guzzle;
class ClientTest extends AbstractTest
{
/**
*
*/
public function setUp()
{
parent::setUp();
}
/** @var Client $client */
protected $client = null;
public function testBaseURl()
{
$client = new Client('localhost', 8086);
$this->assertEquals($client->getBaseURI(), 'http://localhost:8086');
}
public function testSelectDbShouldReturnDatabaseInstance()
{
$client = new Client('localhost', 8086);
$dbName = 'test-database';
$database = $client->selectDB($dbName);
$this->assertInstanceOf('\InfluxDB\Database', $database);
$this->assertEquals($dbName, $database->getName());
}
/**
*/
public function testGuzzleQuery()
{
$client = new Client('localhost', 8086);
$query = "some-bad-query";
$bodyResponse = file_get_contents(dirname(__FILE__) . '/result.example.json');
$httpMockClient = $this->buildHttpMockClient($bodyResponse);
$client->setDriver(new Guzzle($httpMockClient));
/** @var \InfluxDB\ResultSet $result */
$result = $client->query(null, $query);
$this->assertInstanceOf('\InfluxDB\ResultSet', $result);
}
}

View File

@ -1,100 +0,0 @@
<?php
namespace InfluxDB\Test;
use InfluxDB\Client;
use InfluxDB\Database;
use InfluxDB\Driver\Guzzle;
use InfluxDB\Point;
use InfluxDB\ResultSet;
use PHPUnit_Framework_MockObject_MockObject;
use PHPUnit_Framework_TestCase;
class DatabaseTest extends AbstractTest
{
/**
* @var string
*/
protected $dataToInsert;
/**
* @var
*/
protected $mockResultSet;
public function setUp()
{
parent::setUp();
$this->resultData = file_get_contents(dirname(__FILE__) . '/result.example.json');
$this->mockClient->expects($this->any())
->method('listDatabases')
->will($this->returnValue(array('test123', 'test')));
$this->dataToInsert = file_get_contents(dirname(__FILE__) . '/input.example.json');
}
/**
*
*/
public function testQuery()
{
$testResultSet = new ResultSet($this->resultData);
$this->assertEquals($this->database->query('SELECT * FROM test_metric'), $testResultSet);
}
public function testCreateRetentionPolicy()
{
$retentionPolicy = new Database\RetentionPolicy('test', '1d', 1, true);
$mockClient = $this->getClientMock(true);
$database = new Database('test', $mockClient);
$this->assertEquals($database->createRetentionPolicy($retentionPolicy), new ResultSet($this->getEmptyResult()));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testEmptyDatabaseName()
{
new Database(null, $this->mockClient);
}
public function testExists()
{
$database = new Database('test', $this->mockClient);
$this->assertEquals($database->exists(), true);
}
public function testNotExists()
{
$database = new Database('test_not_exists', $this->mockClient);
$this->assertEquals($database->exists(), false);
}
public function testWritePointsInASingleCall()
{
$point1 = new Point(
'cpu_load_short',
0.64,
array('host' => 'server01', 'region' => 'us-west'),
array('cpucount' => 10),
1435222310
);
$point2 = new Point(
'cpu_load_short',
0.84
);
$this->assertEquals(true, $this->database->writePoints(array($point1, $point2)));
}
}

View File

@ -1,30 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: dmartinez
* Date: 18-6-15
* Time: 17:39
*/
namespace InfluxDB\Test;
use InfluxDB\Point;
class PointTest extends \PHPUnit_Framework_TestCase
{
public function testPointStringRepresentation()
{
$expected = 'cpu_load_short,host=server01,region=us-west cpucount=10,value=0.64 1435222310';
$point = new Point(
'cpu_load_short',
0.64,
array('host' => 'server01', 'region' => 'us-west'),
array('cpucount' => 10),
1435222310
);
$this->assertEquals($expected, (string) $point);
}
}

View File

@ -1,141 +0,0 @@
<?php
namespace InfluxDB\Test;
use InfluxDB\ResultSet;
class ResultSetTest extends \PHPUnit_Framework_TestCase
{
/** @var ResultSet $resultSet*/
protected $resultSet;
public function setUp()
{
$resultJsonExample = file_get_contents(dirname(__FILE__) . '/result.example.json');
$this->resultSet = new ResultSet($resultJsonExample);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testThrowsExceptionIfJSONisNotValid()
{
$invalidJSON = 'foo';
new ResultSet($invalidJSON);
}
/**
* Throws Exception if something went wrong with influxDB
* @expectedException \InfluxDB\Exception
*/
public function testThrowsInfluxDBException()
{
$errorResult = <<<EOD
{
"series": [],
"error": "Big error, many problems."
}
EOD;
new ResultSet($errorResult);
}
/**
* Throws Exception if something went wrong with influxDB after processing the query
* @expectedException \InfluxDB\Exception
*/
public function testThrowsInfluxDBExceptionIfAnyErrorInSeries()
{
$errorResult = <<<EOD
{
"results": [
{
"series": [],
"error": "There was an error after querying"
}
]
}
EOD;
new ResultSet($errorResult);
}
/**
* We can get points from measurement
*/
public function testGetPointsFromNameWithoudTags()
{
$resultJsonExample = file_get_contents(dirname(__FILE__) . '/result-no-tags.example.json');
$this->resultSet = new ResultSet($resultJsonExample);
$measurementName = 'cpu_load_short';
$expectedNumberOfPoints = 2;
$points = $this->resultSet->getPoints($measurementName);
$this->assertTrue(is_array($points));
$this->assertCount($expectedNumberOfPoints, $points);
}
/**
* We can get points from measurement
*/
public function testGetPoints()
{
$expectedNumberOfPoints = 3;
$points = $this->resultSet->getPoints();
$this->assertTrue(
is_array($points)
);
$this->assertCount($expectedNumberOfPoints, $points);
}
/**
* We can get points from measurement
*/
public function testGetPointsFromMeasurementName()
{
$measurementName = 'cpu_load_short';
$expectedNumberOfPoints = 2;
$expectedValueFromFirstPoint = 0.64;
$points = $this->resultSet->getPoints($measurementName);
$this->assertTrue(
is_array($points)
);
$this->assertCount($expectedNumberOfPoints, $points);
$somePoint = array_shift($points);
$this->assertEquals($expectedValueFromFirstPoint, $somePoint['value']);
}
public function testGetPointsFromTags()
{
$tags = array("host" => "server01");
$expectedNumberOfPoints = 2;
$points = $this->resultSet->getPoints('', $tags);
$this->assertTrue(is_array($points));
$this->assertCount($expectedNumberOfPoints, $points);
}
public function testGetPointsFromNameAndTags()
{
$tags = array("host" => "server01");
$expectedNumberOfPoints = 2;
$points = $this->resultSet->getPoints('', $tags);
$this->assertTrue(is_array($points));
$this->assertCount($expectedNumberOfPoints, $points);
}
}

View File

@ -1,17 +0,0 @@
{
"database": "mydb",
"retentionPolicy": "mypolicy",
"points": [
{
"measurement": "cpu_load_short",
"tags": {
"host": "server01",
"region": "us-west"
},
"time": "2009-11-10T23:00:00Z",
"fields": {
"value": 0.64
}
}
]
}

View File

@ -1,47 +0,0 @@
{
"results": [
{
"series": [
{
"name": "cpu_load_short",
"columns": [
"time",
"value"
],
"values": [
[
"2015-01-29T21:51:28.968422294Z",
0.64
]
]
},
{
"name": "cpu_load_short",
"columns": [
"time",
"value"
],
"values": [
[
"2015-01-29T21:51:28.968422294Z",
0.65
]
]
},
{
"name": "other_serie",
"columns": [
"time",
"value"
],
"values": [
[
"2015-01-29T21:51:28.968422294Z",
0.66
]
]
}
]
}
]
}

View File

@ -1,24 +0,0 @@
{
"results": [
{
"series": [
{
"columns": [
"user",
"admin"
],
"values": [
[
"test1",
true
],
[
"test2",
false
]
]
}
]
}
]
}

View File

@ -1,59 +0,0 @@
{
"results": [
{
"series": [
{
"name": "cpu_load_short",
"tags": {
"host": "server01",
"region": "us-west"
},
"columns": [
"time",
"value"
],
"values": [
[
"2015-01-29T21:51:28.968422294Z",
0.64
]
]
},
{
"name": "cpu_load_short",
"tags": {
"host": "server02",
"region": "us-west"
},
"columns": [
"time",
"value"
],
"values": [
[
"2015-01-29T21:51:28.968422294Z",
0.65
]
]
},
{
"name": "other_serie",
"tags": {
"host": "server01",
"region": "us-west"
},
"columns": [
"time",
"value"
],
"values": [
[
"2015-01-29T21:51:28.968422294Z",
0.66
]
]
}
]
}
]
}

View File

@ -1,7 +0,0 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit834a242029a498370312fbad08ece378::getLoader();

View File

@ -1 +0,0 @@
../satooshi/php-coveralls/composer/bin/coveralls

View File

@ -1 +0,0 @@
../codeclimate/php-test-reporter/composer/bin/test-reporter

@ -1 +0,0 @@
Subproject commit 418ae782307841ac50fe26daa4cfe04520b0de9c

View File

@ -1,413 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0 class loader
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-0 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
if ('\\' == $class[0]) {
$class = substr($class, 1);
}
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative) {
return false;
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if ($file === null && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if ($file === null) {
// Remember that this class does not exist.
return $this->classMap[$class] = false;
}
return $file;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}

View File

@ -1,21 +0,0 @@
Copyright (c) 2015 Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,9 +0,0 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);

View File

@ -1,12 +0,0 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
$vendorDir . '/guzzlehttp/psr7/src/functions.php',
$vendorDir . '/guzzlehttp/promises/src/functions_include.php',
$vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
);

View File

@ -1,16 +0,0 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Psr\\Log\\' => array($vendorDir . '/psr/log'),
'Guzzle\\Tests' => array($vendorDir . '/guzzle/guzzle/tests'),
'Guzzle' => array($vendorDir . '/guzzle/guzzle/src'),
'Contrib\\Component' => array($vendorDir . '/satooshi/php-coveralls/src'),
'Contrib\\Bundle' => array($vendorDir . '/satooshi/php-coveralls/src'),
'CodeClimate\\Component' => array($vendorDir . '/codeclimate/php-test-reporter/src'),
'CodeClimate\\Bundle' => array($vendorDir . '/codeclimate/php-test-reporter/src'),
);

View File

@ -1,21 +0,0 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
'Symfony\\Component\\Stopwatch\\' => array($vendorDir . '/symfony/stopwatch'),
'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
'Symfony\\Component\\Config\\' => array($vendorDir . '/symfony/config'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
'InfluxDB\\Test\\' => array($baseDir . '/tests'),
'InfluxDB\\' => array($baseDir . '/src/InfluxDB'),
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
);

View File

@ -1,55 +0,0 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit834a242029a498370312fbad08ece378
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit834a242029a498370312fbad08ece378', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit834a242029a498370312fbad08ece378', 'loadClassLoader'));
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
$loader->register(true);
$includeFiles = require __DIR__ . '/autoload_files.php';
foreach ($includeFiles as $file) {
composerRequire834a242029a498370312fbad08ece378($file);
}
return $loader;
}
}
function composerRequire834a242029a498370312fbad08ece378($file)
{
require $file;
}

View File

@ -1,821 +0,0 @@
[
{
"name": "psr/http-message",
"version": "dev-master",
"version_normalized": "9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2015-05-04 20:22:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
]
},
{
"name": "guzzlehttp/psr7",
"version": "1.1.0",
"version_normalized": "1.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "af0e1758de355eb113917ad79c3c0e3604bce4bd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/af0e1758de355eb113917ad79c3c0e3604bce4bd",
"reference": "af0e1758de355eb113917ad79c3c0e3604bce4bd",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"time": "2015-06-24 19:55:15",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": [
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "PSR-7 message implementation",
"keywords": [
"http",
"message",
"stream",
"uri"
]
},
{
"name": "guzzlehttp/promises",
"version": "dev-master",
"version_normalized": "9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "f596be052ef429a16b2f640812fcf84392dd38f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/f596be052ef429a16b2f640812fcf84392dd38f7",
"reference": "f596be052ef429a16b2f640812fcf84392dd38f7",
"shasum": ""
},
"require": {
"php": ">=5.5.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"time": "2015-06-30 16:39:54",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
]
},
{
"name": "guzzlehttp/guzzle",
"version": "dev-master",
"version_normalized": "9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "1879fbe853b0c64d109e369c7aeff09849e62d1e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/1879fbe853b0c64d109e369c7aeff09849e62d1e",
"reference": "1879fbe853b0c64d109e369c7aeff09849e62d1e",
"shasum": ""
},
"require": {
"guzzlehttp/promises": "~1.0",
"guzzlehttp/psr7": "~1.1",
"php": ">=5.5.0"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "~4.0",
"psr/log": "~1.0"
},
"time": "2015-07-10 20:04:21",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.0-dev"
}
},
"installation-source": "source",
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle is a PHP HTTP client library",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
]
},
{
"name": "symfony/event-dispatcher",
"version": "2.8.x-dev",
"version_normalized": "2.8.9999999.9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/EventDispatcher.git",
"reference": "d7246885b7fe4cb5a2786bda34362d2f0e40b730"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/d7246885b7fe4cb5a2786bda34362d2f0e40b730",
"reference": "d7246885b7fe4cb5a2786bda34362d2f0e40b730",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~2.0,>=2.0.5|~3.0.0",
"symfony/dependency-injection": "~2.6|~3.0.0",
"symfony/expression-language": "~2.6|~3.0.0",
"symfony/phpunit-bridge": "~2.7|~3.0.0",
"symfony/stopwatch": "~2.3|~3.0.0"
},
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"time": "2015-06-24 15:32:32",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-4": {
"Symfony\\Component\\EventDispatcher\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/console",
"version": "2.8.x-dev",
"version_normalized": "2.8.9999999.9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/Console.git",
"reference": "fd85e7517e79a2bceafcee8f7e8b7bbd0919a90a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Console/zipball/fd85e7517e79a2bceafcee8f7e8b7bbd0919a90a",
"reference": "fd85e7517e79a2bceafcee8f7e8b7bbd0919a90a",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/event-dispatcher": "~2.1|~3.0.0",
"symfony/phpunit-bridge": "~2.7|~3.0.0",
"symfony/process": "~2.1|~3.0.0"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/process": ""
},
"time": "2015-07-16 12:22:14",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/yaml",
"version": "2.8.x-dev",
"version_normalized": "2.8.9999999.9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
"reference": "000e7fc2653335cd42c6d21405dac1c74224a387"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/000e7fc2653335cd42c6d21405dac1c74224a387",
"reference": "000e7fc2653335cd42c6d21405dac1c74224a387",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7|~3.0.0"
},
"time": "2015-07-01 14:16:54",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/stopwatch",
"version": "2.8.x-dev",
"version_normalized": "2.8.9999999.9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/Stopwatch.git",
"reference": "cd5f0dc1d3d0e2c83461dad77e20a9186beb6146"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Stopwatch/zipball/cd5f0dc1d3d0e2c83461dad77e20a9186beb6146",
"reference": "cd5f0dc1d3d0e2c83461dad77e20a9186beb6146",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7|~3.0.0"
},
"time": "2015-07-01 18:24:26",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-4": {
"Symfony\\Component\\Stopwatch\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Stopwatch Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/filesystem",
"version": "2.8.x-dev",
"version_normalized": "2.8.9999999.9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/Filesystem.git",
"reference": "9f70c5625a32b2f1e6fc37222f52b4e0eb437b0e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/9f70c5625a32b2f1e6fc37222f52b4e0eb437b0e",
"reference": "9f70c5625a32b2f1e6fc37222f52b4e0eb437b0e",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7|~3.0.0"
},
"time": "2015-07-09 16:11:14",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/config",
"version": "2.8.x-dev",
"version_normalized": "2.8.9999999.9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/Config.git",
"reference": "358ec929e494b6f12d8508d88357cbd7383a10ca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Config/zipball/358ec929e494b6f12d8508d88357cbd7383a10ca",
"reference": "358ec929e494b6f12d8508d88357cbd7383a10ca",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
"symfony/filesystem": "~2.3|~3.0.0"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7|~3.0.0"
},
"time": "2015-07-09 16:11:14",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-4": {
"Symfony\\Component\\Config\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com"
},
{
"name": "psr/log",
"version": "1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
"shasum": ""
},
"time": "2012-12-21 11:40:51",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Psr\\Log\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"keywords": [
"log",
"psr",
"psr-3"
]
},
{
"name": "guzzle/guzzle",
"version": "dev-master",
"version_normalized": "9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle3.git",
"reference": "b3f5050cb6270c7a728a0b74ac2de50a262b3e02"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle3/zipball/b3f5050cb6270c7a728a0b74ac2de50a262b3e02",
"reference": "b3f5050cb6270c7a728a0b74ac2de50a262b3e02",
"shasum": ""
},
"require": {
"ext-curl": "*",
"php": ">=5.3.3",
"symfony/event-dispatcher": "~2.1"
},
"replace": {
"guzzle/batch": "self.version",
"guzzle/cache": "self.version",
"guzzle/common": "self.version",
"guzzle/http": "self.version",
"guzzle/inflection": "self.version",
"guzzle/iterator": "self.version",
"guzzle/log": "self.version",
"guzzle/parser": "self.version",
"guzzle/plugin": "self.version",
"guzzle/plugin-async": "self.version",
"guzzle/plugin-backoff": "self.version",
"guzzle/plugin-cache": "self.version",
"guzzle/plugin-cookie": "self.version",
"guzzle/plugin-curlauth": "self.version",
"guzzle/plugin-error-response": "self.version",
"guzzle/plugin-history": "self.version",
"guzzle/plugin-log": "self.version",
"guzzle/plugin-md5": "self.version",
"guzzle/plugin-mock": "self.version",
"guzzle/plugin-oauth": "self.version",
"guzzle/service": "self.version",
"guzzle/stream": "self.version"
},
"require-dev": {
"doctrine/cache": "~1.3",
"monolog/monolog": "~1.0",
"phpunit/phpunit": "3.7.*",
"psr/log": "~1.0",
"symfony/class-loader": "~2.1",
"zendframework/zend-cache": "2.*,<2.3",
"zendframework/zend-log": "2.*,<2.3"
},
"suggest": {
"guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated."
},
"time": "2015-04-29 17:06:53",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.9-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"Guzzle": "src/",
"Guzzle\\Tests": "tests/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Guzzle Community",
"homepage": "https://github.com/guzzle/guzzle/contributors"
}
],
"description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
]
},
{
"name": "satooshi/php-coveralls",
"version": "v0.6.1",
"version_normalized": "0.6.1.0",
"source": {
"type": "git",
"url": "https://github.com/satooshi/php-coveralls.git",
"reference": "dd0df95bd37a7cf5c5c50304dfe260ffe4b50760"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/dd0df95bd37a7cf5c5c50304dfe260ffe4b50760",
"reference": "dd0df95bd37a7cf5c5c50304dfe260ffe4b50760",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-simplexml": "*",
"guzzle/guzzle": ">=3.0",
"php": ">=5.3",
"psr/log": "1.0.0",
"symfony/config": ">=2.0",
"symfony/console": ">=2.0",
"symfony/stopwatch": ">=2.2",
"symfony/yaml": ">=2.0"
},
"require-dev": {
"apigen/apigen": "2.8.*@stable",
"pdepend/pdepend": "dev-master",
"phpmd/phpmd": "dev-master",
"phpunit/php-invoker": ">=1.1.0,<1.2.0",
"phpunit/phpunit": "3.7.*@stable",
"sebastian/finder-facade": "dev-master",
"sebastian/phpcpd": "1.4.*@stable",
"squizlabs/php_codesniffer": "1.4.*@stable",
"theseer/fdomdocument": "dev-master"
},
"time": "2013-05-04 08:07:33",
"bin": [
"composer/bin/coveralls"
],
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Contrib\\Component": "src/",
"Contrib\\Bundle": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kitamura Satoshi",
"email": "with.no.parachute@gmail.com",
"homepage": "https://www.facebook.com/satooshi.jp"
}
],
"description": "PHP client library for Coveralls API",
"homepage": "https://github.com/satooshi/php-coveralls",
"keywords": [
"ci",
"coverage",
"github",
"test"
]
},
{
"name": "codeclimate/php-test-reporter",
"version": "dev-master",
"version_normalized": "9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/codeclimate/php-test-reporter.git",
"reference": "418ae782307841ac50fe26daa4cfe04520b0de9c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/codeclimate/php-test-reporter/zipball/418ae782307841ac50fe26daa4cfe04520b0de9c",
"reference": "418ae782307841ac50fe26daa4cfe04520b0de9c",
"shasum": ""
},
"require": {
"ext-curl": "*",
"php": ">=5.3",
"satooshi/php-coveralls": "0.6.*",
"symfony/console": ">=2.0"
},
"require-dev": {
"ext-xdebug": "*",
"phpunit/phpunit": "3.7.*@stable"
},
"time": "2015-04-18 14:43:54",
"bin": [
"composer/bin/test-reporter"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.1.x-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"CodeClimate\\Component": "src/",
"CodeClimate\\Bundle": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Code Climate",
"email": "hello@codeclimate.com",
"homepage": "https://codeclimate.com"
}
],
"description": "PHP client for reporting test coverage to Code Climate",
"homepage": "https://github.com/codeclimate/php-test-reporter",
"keywords": [
"codeclimate",
"coverage"
]
}
]

@ -1 +0,0 @@
Subproject commit b3f5050cb6270c7a728a0b74ac2de50a262b3e02

@ -1 +0,0 @@
Subproject commit 1879fbe853b0c64d109e369c7aeff09849e62d1e

@ -1 +0,0 @@
Subproject commit f596be052ef429a16b2f640812fcf84392dd38f7

View File

@ -1,20 +0,0 @@
language: php
php:
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
sudo: false
install:
- travis_retry composer install --no-interaction --prefer-source
script: make test
matrix:
allow_failures:
- php: hhvm
fast_finish: true

View File

@ -1,19 +0,0 @@
# CHANGELOG
## 1.1.0 - 2015-06-24
* URIs can now be relative.
* `multipart/form-data` headers are now overridden case-insensitively.
* URI paths no longer encode the following characters because they are allowed
in URIs: "(", ")", "*", "!", "'"
* A port is no longer added to a URI when the scheme is missing and no port is
present.
## 1.0.0 - 2015-05-19
Initial release.
Currently unsupported:
- `Psr\Http\Message\ServerRequestInterface`
- `Psr\Http\Message\UploadedFileInterface`

View File

@ -1,19 +0,0 @@
Copyright (c) 2015 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,13 +0,0 @@
all: clean test
test:
vendor/bin/phpunit $(TEST)
coverage:
vendor/bin/phpunit --coverage-html=artifacts/coverage $(TEST)
view-coverage:
open artifacts/coverage/index.html
clean:
rm -rf artifacts/*

View File

@ -1,580 +0,0 @@
# PSR-7 Message Implementation
This repository contains a partial [PSR-7](http://www.php-fig.org/psr/psr-7/)
message implementation, several stream decorators, and some helpful
functionality like query string parsing. Currently missing
ServerRequestInterface and UploadedFileInterface; a pull request for these features is welcome.
# Stream implementation
This package comes with a number of stream implementations and stream
decorators.
## AppendStream
`GuzzleHttp\Psr7\AppendStream`
Reads from multiple streams, one after the other.
```php
use GuzzleHttp\Psr7;
$a = Psr7\stream_for('abc, ');
$b = Psr7\stream_for('123.');
$composed = new Psr7\AppendStream([$a, $b]);
$composed->addStream(Psr7\stream_for(' Above all listen to me').
echo $composed(); // abc, 123. Above all listen to me.
```
## BufferStream
`GuzzleHttp\Psr7\BufferStream`
Provides a buffer stream that can be written to to fill a buffer, and read
from to remove bytes from the buffer.
This stream returns a "hwm" metadata value that tells upstream consumers
what the configured high water mark of the stream is, or the maximum
preferred size of the buffer.
```php
use GuzzleHttp\Psr7;
// When more than 1024 bytes are in the buffer, it will begin returning
// false to writes. This is an indication that writers should slow down.
$buffer = new Psr7\BufferStream(1024);
```
## CachingStream
The CachingStream is used to allow seeking over previously read bytes on
non-seekable streams. This can be useful when transferring a non-seekable
entity body fails due to needing to rewind the stream (for example, resulting
from a redirect). Data that is read from the remote stream will be buffered in
a PHP temp stream so that previously read bytes are cached first in memory,
then on disk.
```php
use GuzzleHttp\Psr7;
$original = Psr7\stream_for(fopen('http://www.google.com', 'r'));
$stream = new Psr7\CachingStream($original);
$stream->read(1024);
echo $stream->tell();
// 1024
$stream->seek(0);
echo $stream->tell();
// 0
```
## DroppingStream
`GuzzleHttp\Psr7\DroppingStream`
Stream decorator that begins dropping data once the size of the underlying
stream becomes too full.
```php
use GuzzleHttp\Psr7;
// Create an empty stream
$stream = Psr7\stream_for();
// Start dropping data when the stream has more than 10 bytes
$dropping = new Psr7\DroppingStream($stream, 10);
$stream->write('01234567890123456789');
echo $stream; // 0123456789
```
## FnStream
`GuzzleHttp\Psr7\FnStream`
Compose stream implementations based on a hash of functions.
Allows for easy testing and extension of a provided stream without needing to
to create a concrete class for a simple extension point.
```php
use GuzzleHttp\Psr7;
$stream = Psr7\stream_for('hi');
$fnStream = Psr7\FnStream::decorate($stream, [
'rewind' => function () use ($stream) {
echo 'About to rewind - ';
$stream->rewind();
echo 'rewound!';
}
]);
$fnStream->rewind();
// Outputs: About to rewind - rewound!
```
## InflateStream
`GuzzleHttp\Psr7\InflateStream`
Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.
This stream decorator skips the first 10 bytes of the given stream to remove
the gzip header, converts the provided stream to a PHP stream resource,
then appends the zlib.inflate filter. The stream is then converted back
to a Guzzle stream resource to be used as a Guzzle stream.
## LazyOpenStream
`GuzzleHttp\Psr7\LazyOpenStream`
Lazily reads or writes to a file that is opened only after an IO operation
take place on the stream.
```php
use GuzzleHttp\Psr7;
$stream = new Psr7\LazyOpenStream('/path/to/file', 'r');
// The file has not yet been opened...
echo $stream->read(10);
// The file is opened and read from only when needed.
```
## LimitStream
`GuzzleHttp\Psr7\LimitStream`
LimitStream can be used to read a subset or slice of an existing stream object.
This can be useful for breaking a large file into smaller pieces to be sent in
chunks (e.g. Amazon S3's multipart upload API).
```php
use GuzzleHttp\Psr7;
$original = Psr7\stream_for(fopen('/tmp/test.txt', 'r+'));
echo $original->getSize();
// >>> 1048576
// Limit the size of the body to 1024 bytes and start reading from byte 2048
$stream = new Psr7\LimitStream($original, 1024, 2048);
echo $stream->getSize();
// >>> 1024
echo $stream->tell();
// >>> 0
```
## MultipartStream
`GuzzleHttp\Psr7\MultipartStream`
Stream that when read returns bytes for a streaming multipart or
multipart/form-data stream.
## NoSeekStream
`GuzzleHttp\Psr7\NoSeekStream`
NoSeekStream wraps a stream and does not allow seeking.
```php
use GuzzleHttp\Psr7;
$original = Psr7\stream_for('foo');
$noSeek = new Psr7\NoSeekStream($original);
echo $noSeek->read(3);
// foo
var_export($noSeek->isSeekable());
// false
$noSeek->seek(0);
var_export($noSeek->read(3));
// NULL
```
## PumpStream
`GuzzleHttp\Psr7\PumpStream`
Provides a read only stream that pumps data from a PHP callable.
When invoking the provided callable, the PumpStream will pass the amount of
data requested to read to the callable. The callable can choose to ignore
this value and return fewer or more bytes than requested. Any extra data
returned by the provided callable is buffered internally until drained using
the read() function of the PumpStream. The provided callable MUST return
false when there is no more data to read.
## Implementing stream decorators
Creating a stream decorator is very easy thanks to the
`GuzzleHttp\Psr7\StreamDecoratorTrait`. This trait provides methods that
implement `Psr\Http\Message\StreamInterface` by proxying to an underlying
stream. Just `use` the `StreamDecoratorTrait` and implement your custom
methods.
For example, let's say we wanted to call a specific function each time the last
byte is read from a stream. This could be implemented by overriding the
`read()` method.
```php
use Psr\Http\Message\StreamInterface;
use GuzzleHttp\Psr7\StreamDecoratorTrait;
class EofCallbackStream implements StreamInterface
{
use StreamDecoratorTrait;
private $callback;
public function __construct(StreamInterface $stream, callable $cb)
{
$this->stream = $stream;
$this->callback = $cb;
}
public function read($length)
{
$result = $this->stream->read($length);
// Invoke the callback when EOF is hit.
if ($this->eof()) {
call_user_func($this->callback);
}
return $result;
}
}
```
This decorator could be added to any existing stream and used like so:
```php
use GuzzleHttp\Psr7;
$original = Psr7\stream_for('foo');
$eofStream = new EofCallbackStream($original, function () {
echo 'EOF!';
});
$eofStream->read(2);
$eofStream->read(1);
// echoes "EOF!"
$eofStream->seek(0);
$eofStream->read(3);
// echoes "EOF!"
```
## PHP StreamWrapper
You can use the `GuzzleHttp\Psr7\StreamWrapper` class if you need to use a
PSR-7 stream as a PHP stream resource.
Use the `GuzzleHttp\Psr7\StreamWrapper::getResource()` method to create a PHP
stream from a PSR-7 stream.
```php
use GuzzleHttp\Psr7\StreamWrapper;
$stream = GuzzleHttp\Psr7\stream_for('hello!');
$resource = StreamWrapper::getResource($stream);
echo fread($resource, 6); // outputs hello!
```
# Function API
There are various functions available under the `GuzzleHttp\Psr7` namespace.
## `function str`
`function str(MessageInterface $message)`
Returns the string representation of an HTTP message.
```php
$request = new GuzzleHttp\Psr7\Request('GET', 'http://example.com');
echo GuzzleHttp\Psr7\str($request);
```
## `function uri_for`
`function uri_for($uri)`
This function accepts a string or `Psr\Http\Message\UriInterface` and returns a
UriInterface for the given value. If the value is already a `UriInterface`, it
is returned as-is.
```php
$uri = GuzzleHttp\Psr7\uri_for('http://example.com');
assert($uri === GuzzleHttp\Psr7\uri_for($uri));
```
## `function stream_for`
`function stream_for($resource = '', array $options = [])`
Create a new stream based on the input type.
Options is an associative array that can contain the following keys:
* - metadata: Array of custom metadata.
* - size: Size of the stream.
This method accepts the following `$resource` types:
- `Psr\Http\Message\StreamInterface`: Returns the value as-is.
- `string`: Creates a stream object that uses the given string as the contents.
- `resource`: Creates a stream object that wraps the given PHP stream resource.
- `Iterator`: If the provided value implements `Iterator`, then a read-only
stream object will be created that wraps the given iterable. Each time the
stream is read from, data from the iterator will fill a buffer and will be
continuously called until the buffer is equal to the requested read size.
Subsequent read calls will first read from the buffer and then call `next`
on the underlying iterator until it is exhausted.
- `object` with `__toString()`: If the object has the `__toString()` method,
the object will be cast to a string and then a stream will be returned that
uses the string value.
- `NULL`: When `null` is passed, an empty stream object is returned.
- `callable` When a callable is passed, a read-only stream object will be
created that invokes the given callable. The callable is invoked with the
number of suggested bytes to read. The callable can return any number of
bytes, but MUST return `false` when there is no more data to return. The
stream object that wraps the callable will invoke the callable until the
number of requested bytes are available. Any additional bytes will be
buffered and used in subsequent reads.
```php
$stream = GuzzleHttp\Psr7\stream_for('foo');
$stream = GuzzleHttp\Psr7\stream_for(fopen('/path/to/file', 'r'));
$generator function ($bytes) {
for ($i = 0; $i < $bytes; $i++) {
yield ' ';
}
}
$stream = GuzzleHttp\Psr7\stream_for($generator(100));
```
## `function parse_header`
`function parse_header($header)`
Parse an array of header values containing ";" separated data into an array of
associative arrays representing the header key value pair data of the header.
When a parameter does not contain a value, but just contains a key, this
function will inject a key with a '' string value.
## `function normalize_header`
`function normalize_header($header)`
Converts an array of header values that may contain comma separated headers
into an array of headers with no comma separated values.
## `function modify_request`
`function modify_request(RequestInterface $request, array $changes)`
Clone and modify a request with the given changes. This method is useful for
reducing the number of clones needed to mutate a message.
The changes can be one of:
- method: (string) Changes the HTTP method.
- set_headers: (array) Sets the given headers.
- remove_headers: (array) Remove the given headers.
- body: (mixed) Sets the given body.
- uri: (UriInterface) Set the URI.
- query: (string) Set the query string value of the URI.
- version: (string) Set the protocol version.
## `function rewind_body`
`function rewind_body(MessageInterface $message)`
Attempts to rewind a message body and throws an exception on failure. The body
of the message will only be rewound if a call to `tell()` returns a value other
than `0`.
## `function try_fopen`
`function try_fopen($filename, $mode)`
Safely opens a PHP stream resource using a filename.
When fopen fails, PHP normally raises a warning. This function adds an error
handler that checks for errors and throws an exception instead.
## `function copy_to_string`
`function copy_to_string(StreamInterface $stream, $maxLen = -1)`
Copy the contents of a stream into a string until the given number of bytes
have been read.
## `function copy_to_stream`
`function copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)`
Copy the contents of a stream into another stream until the given number of
bytes have been read.
## `function hash`
`function hash(StreamInterface $stream, $algo, $rawOutput = false)`
Calculate a hash of a Stream. This method reads the entire stream to calculate
a rolling hash (based on PHP's hash_init functions).
## `function readline`
`function readline(StreamInterface $stream, $maxLength = null)`
Read a line from the stream up to the maximum allowed buffer length.
## `function parse_request`
`function parse_request($message)`
Parses a request message string into a request object.
## `function parse_response`
`function parse_response($message)`
Parses a response message string into a response object.
## `function parse_query`
`function parse_query($str, $urlEncoding = true)`
Parse a query string into an associative array.
If multiple values are found for the same key, the value of that key value pair
will become an array. This function does not parse nested PHP style arrays into
an associative array (e.g., `foo[a]=1&foo[b]=2` will be parsed into
`['foo[a]' => '1', 'foo[b]' => '2']`).
## `function build_query`
`function build_query(array $params, $encoding = PHP_QUERY_RFC3986)`
Build a query string from an array of key value pairs.
This function can use the return value of parseQuery() to build a query string.
This function does not modify the provided keys when an array is encountered
(like http_build_query would).
## `function mimetype_from_filename`
`function mimetype_from_filename($filename)`
Determines the mimetype of a file by looking at its extension.
## `function mimetype_from_extension`
`function mimetype_from_extension($extension)`
Maps a file extensions to a mimetype.
# Static URI methods
The `GuzzleHttp\Psr7\Uri` class has several static methods to manipulate URIs.
## `GuzzleHttp\Psr7\Uri::removeDotSegments`
`public static function removeDotSegments($path) -> UriInterface`
Removes dot segments from a path and returns the new path.
See http://tools.ietf.org/html/rfc3986#section-5.2.4
## `GuzzleHttp\Psr7\Uri::resolve`
`public static function resolve(UriInterface $base, $rel) -> UriInterface`
Resolve a base URI with a relative URI and return a new URI.
See http://tools.ietf.org/html/rfc3986#section-5
## `GuzzleHttp\Psr7\Uri::withQueryValue`
`public static function withQueryValue(UriInterface $uri, $key, $value) -> UriInterface`
Create a new URI with a specific query string value.
Any existing query string values that exactly match the provided key are
removed and replaced with the given key value pair.
Note: this function will convert "=" to "%3D" and "&" to "%26".
## `GuzzleHttp\Psr7\Uri::withoutQueryValue`
`public static function withoutQueryValue(UriInterface $uri, $key, $value) -> UriInterface`
Create a new URI with a specific query string value removed.
Any existing query string values that exactly match the provided key are
removed.
Note: this function will convert "=" to "%3D" and "&" to "%26".
## `GuzzleHttp\Psr7\Uri::fromParts`
`public static function fromParts(array $parts) -> UriInterface`
Create a `GuzzleHttp\Psr7\Uri` object from a hash of `parse_url` parts.
# Not Implemented
A few aspects of PSR-7 are not implemented in this project. A pull request for
any of these features is welcome:
- `Psr\Http\Message\ServerRequestInterface`
- `Psr\Http\Message\UploadedFileInterface`

View File

@ -1,35 +0,0 @@
{
"name": "guzzlehttp/psr7",
"type": "library",
"description": "PSR-7 message implementation",
"keywords": ["message", "stream", "http", "uri"],
"license": "MIT",
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": ["src/functions.php"]
},
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
}
}

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="./tests/bootstrap.php"
colors="true">
<testsuites>
<testsuite>
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src</directory>
<exclude>
<directory suffix="Interface.php">src/</directory>
</exclude>
</whitelist>
</filter>
</phpunit>

View File

@ -1,233 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Reads from multiple streams, one after the other.
*
* This is a read-only stream decorator.
*/
class AppendStream implements StreamInterface
{
/** @var StreamInterface[] Streams being decorated */
private $streams = [];
private $seekable = true;
private $current = 0;
private $pos = 0;
private $detached = false;
/**
* @param StreamInterface[] $streams Streams to decorate. Each stream must
* be readable.
*/
public function __construct(array $streams = [])
{
foreach ($streams as $stream) {
$this->addStream($stream);
}
}
public function __toString()
{
try {
$this->rewind();
return $this->getContents();
} catch (\Exception $e) {
return '';
}
}
/**
* Add a stream to the AppendStream
*
* @param StreamInterface $stream Stream to append. Must be readable.
*
* @throws \InvalidArgumentException if the stream is not readable
*/
public function addStream(StreamInterface $stream)
{
if (!$stream->isReadable()) {
throw new \InvalidArgumentException('Each stream must be readable');
}
// The stream is only seekable if all streams are seekable
if (!$stream->isSeekable()) {
$this->seekable = false;
}
$this->streams[] = $stream;
}
public function getContents()
{
return copy_to_string($this);
}
/**
* Closes each attached stream.
*
* {@inheritdoc}
*/
public function close()
{
$this->pos = $this->current = 0;
foreach ($this->streams as $stream) {
$stream->close();
}
$this->streams = [];
}
/**
* Detaches each attached stream
*
* {@inheritdoc}
*/
public function detach()
{
$this->close();
$this->detached = true;
}
public function tell()
{
return $this->pos;
}
/**
* Tries to calculate the size by adding the size of each stream.
*
* If any of the streams do not return a valid number, then the size of the
* append stream cannot be determined and null is returned.
*
* {@inheritdoc}
*/
public function getSize()
{
$size = 0;
foreach ($this->streams as $stream) {
$s = $stream->getSize();
if ($s === null) {
return null;
}
$size += $s;
}
return $size;
}
public function eof()
{
return !$this->streams ||
($this->current >= count($this->streams) - 1 &&
$this->streams[$this->current]->eof());
}
public function rewind()
{
$this->seek(0);
}
/**
* Attempts to seek to the given position. Only supports SEEK_SET.
*
* {@inheritdoc}
*/
public function seek($offset, $whence = SEEK_SET)
{
if (!$this->seekable) {
throw new \RuntimeException('This AppendStream is not seekable');
} elseif ($whence !== SEEK_SET) {
throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
}
$this->pos = $this->current = 0;
// Rewind each stream
foreach ($this->streams as $i => $stream) {
try {
$stream->rewind();
} catch (\Exception $e) {
throw new \RuntimeException('Unable to seek stream '
. $i . ' of the AppendStream', 0, $e);
}
}
// Seek to the actual position by reading from each stream
while ($this->pos < $offset && !$this->eof()) {
$result = $this->read(min(8096, $offset - $this->pos));
if ($result === '') {
break;
}
}
}
/**
* Reads from all of the appended streams until the length is met or EOF.
*
* {@inheritdoc}
*/
public function read($length)
{
$buffer = '';
$total = count($this->streams) - 1;
$remaining = $length;
$progressToNext = false;
while ($remaining > 0) {
// Progress to the next stream if needed.
if ($progressToNext || $this->streams[$this->current]->eof()) {
$progressToNext = false;
if ($this->current === $total) {
break;
}
$this->current++;
}
$result = $this->streams[$this->current]->read($remaining);
// Using a loose comparison here to match on '', false, and null
if ($result == null) {
$progressToNext = true;
continue;
}
$buffer .= $result;
$remaining = $length - strlen($buffer);
}
$this->pos += strlen($buffer);
return $buffer;
}
public function isReadable()
{
return true;
}
public function isWritable()
{
return false;
}
public function isSeekable()
{
return $this->seekable;
}
public function write($string)
{
throw new \RuntimeException('Cannot write to an AppendStream');
}
public function getMetadata($key = null)
{
return $key ? null : [];
}
}

View File

@ -1,137 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Provides a buffer stream that can be written to to fill a buffer, and read
* from to remove bytes from the buffer.
*
* This stream returns a "hwm" metadata value that tells upstream consumers
* what the configured high water mark of the stream is, or the maximum
* preferred size of the buffer.
*/
class BufferStream implements StreamInterface
{
private $hwm;
private $buffer = '';
/**
* @param int $hwm High water mark, representing the preferred maximum
* buffer size. If the size of the buffer exceeds the high
* water mark, then calls to write will continue to succeed
* but will return false to inform writers to slow down
* until the buffer has been drained by reading from it.
*/
public function __construct($hwm = 16384)
{
$this->hwm = $hwm;
}
public function __toString()
{
return $this->getContents();
}
public function getContents()
{
$buffer = $this->buffer;
$this->buffer = '';
return $buffer;
}
public function close()
{
$this->buffer = '';
}
public function detach()
{
$this->close();
}
public function getSize()
{
return strlen($this->buffer);
}
public function isReadable()
{
return true;
}
public function isWritable()
{
return true;
}
public function isSeekable()
{
return false;
}
public function rewind()
{
$this->seek(0);
}
public function seek($offset, $whence = SEEK_SET)
{
throw new \RuntimeException('Cannot seek a BufferStream');
}
public function eof()
{
return strlen($this->buffer) === 0;
}
public function tell()
{
throw new \RuntimeException('Cannot determine the position of a BufferStream');
}
/**
* Reads data from the buffer.
*/
public function read($length)
{
$currentLength = strlen($this->buffer);
if ($length >= $currentLength) {
// No need to slice the buffer because we don't have enough data.
$result = $this->buffer;
$this->buffer = '';
} else {
// Slice up the result to provide a subset of the buffer.
$result = substr($this->buffer, 0, $length);
$this->buffer = substr($this->buffer, $length);
}
return $result;
}
/**
* Writes data to the buffer.
*/
public function write($string)
{
$this->buffer .= $string;
// TODO: What should happen here?
if (strlen($this->buffer) >= $this->hwm) {
return false;
}
return strlen($string);
}
public function getMetadata($key = null)
{
if ($key == 'hwm') {
return $this->hwm;
}
return $key ? null : [];
}
}

View File

@ -1,125 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Stream decorator that can cache previously read bytes from a sequentially
* read stream.
*/
class CachingStream implements StreamInterface
{
use StreamDecoratorTrait;
/** @var StreamInterface Stream being wrapped */
private $remoteStream;
/** @var int Number of bytes to skip reading due to a write on the buffer */
private $skipReadBytes = 0;
/**
* We will treat the buffer object as the body of the stream
*
* @param StreamInterface $stream Stream to cache
* @param StreamInterface $target Optionally specify where data is cached
*/
public function __construct(
StreamInterface $stream,
StreamInterface $target = null
) {
$this->remoteStream = $stream;
$this->stream = $target ?: new Stream(fopen('php://temp', 'r+'));
}
public function getSize()
{
return max($this->stream->getSize(), $this->remoteStream->getSize());
}
public function rewind()
{
$this->seek(0);
}
/**
* {@inheritdoc}
* @throws \RuntimeException When seeking with SEEK_END or when seeking
* past the total size of the buffer stream
*/
public function seek($offset, $whence = SEEK_SET)
{
if ($whence == SEEK_SET) {
$byte = $offset;
} elseif ($whence == SEEK_CUR) {
$byte = $offset + $this->tell();
} else {
throw new \RuntimeException('CachingStream::seek() supports SEEK_SET and SEEK_CUR');
}
// You cannot skip ahead past where you've read from the remote stream
if ($byte > $this->stream->getSize()) {
throw new \RuntimeException(
sprintf('Cannot seek to byte %d when the buffered stream only'
. ' contains %d bytes', $byte, $this->stream->getSize())
);
}
$this->stream->seek($byte);
}
public function read($length)
{
// Perform a regular read on any previously read data from the buffer
$data = $this->stream->read($length);
$remaining = $length - strlen($data);
// More data was requested so read from the remote stream
if ($remaining) {
// If data was written to the buffer in a position that would have
// been filled from the remote stream, then we must skip bytes on
// the remote stream to emulate overwriting bytes from that
// position. This mimics the behavior of other PHP stream wrappers.
$remoteData = $this->remoteStream->read(
$remaining + $this->skipReadBytes
);
if ($this->skipReadBytes) {
$len = strlen($remoteData);
$remoteData = substr($remoteData, $this->skipReadBytes);
$this->skipReadBytes = max(0, $this->skipReadBytes - $len);
}
$data .= $remoteData;
$this->stream->write($remoteData);
}
return $data;
}
public function write($string)
{
// When appending to the end of the currently read stream, you'll want
// to skip bytes from being read from the remote stream to emulate
// other stream wrappers. Basically replacing bytes of data of a fixed
// length.
$overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
if ($overflow > 0) {
$this->skipReadBytes += $overflow;
}
return $this->stream->write($string);
}
public function eof()
{
return $this->stream->eof() && $this->remoteStream->eof();
}
/**
* Close both the remote stream and buffer stream
*/
public function close()
{
$this->remoteStream->close() && $this->stream->close();
}
}

View File

@ -1,42 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Stream decorator that begins dropping data once the size of the underlying
* stream becomes too full.
*/
class DroppingStream implements StreamInterface
{
use StreamDecoratorTrait;
private $maxLength;
/**
* @param StreamInterface $stream Underlying stream to decorate.
* @param int $maxLength Maximum size before dropping data.
*/
public function __construct(StreamInterface $stream, $maxLength)
{
$this->stream = $stream;
$this->maxLength = $maxLength;
}
public function write($string)
{
$diff = $this->maxLength - $this->stream->getSize();
// Begin returning 0 when the underlying stream is too large.
if ($diff <= 0) {
return 0;
}
// Write the stream or a subset of the stream if needed.
if (strlen($string) < $diff) {
return $this->stream->write($string);
}
return $this->stream->write(substr($string, 0, $diff));
}
}

View File

@ -1,149 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Compose stream implementations based on a hash of functions.
*
* Allows for easy testing and extension of a provided stream without needing
* to create a concrete class for a simple extension point.
*/
class FnStream implements StreamInterface
{
/** @var array */
private $methods;
/** @var array Methods that must be implemented in the given array */
private static $slots = ['__toString', 'close', 'detach', 'rewind',
'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
'isReadable', 'read', 'getContents', 'getMetadata'];
/**
* @param array $methods Hash of method name to a callable.
*/
public function __construct(array $methods)
{
$this->methods = $methods;
// Create the functions on the class
foreach ($methods as $name => $fn) {
$this->{'_fn_' . $name} = $fn;
}
}
/**
* Lazily determine which methods are not implemented.
* @throws \BadMethodCallException
*/
public function __get($name)
{
throw new \BadMethodCallException(str_replace('_fn_', '', $name)
. '() is not implemented in the FnStream');
}
/**
* The close method is called on the underlying stream only if possible.
*/
public function __destruct()
{
if (isset($this->_fn_close)) {
call_user_func($this->_fn_close);
}
}
/**
* Adds custom functionality to an underlying stream by intercepting
* specific method calls.
*
* @param StreamInterface $stream Stream to decorate
* @param array $methods Hash of method name to a closure
*
* @return FnStream
*/
public static function decorate(StreamInterface $stream, array $methods)
{
// If any of the required methods were not provided, then simply
// proxy to the decorated stream.
foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
$methods[$diff] = [$stream, $diff];
}
return new self($methods);
}
public function __toString()
{
return call_user_func($this->_fn___toString);
}
public function close()
{
return call_user_func($this->_fn_close);
}
public function detach()
{
return call_user_func($this->_fn_detach);
}
public function getSize()
{
return call_user_func($this->_fn_getSize);
}
public function tell()
{
return call_user_func($this->_fn_tell);
}
public function eof()
{
return call_user_func($this->_fn_eof);
}
public function isSeekable()
{
return call_user_func($this->_fn_isSeekable);
}
public function rewind()
{
call_user_func($this->_fn_rewind);
}
public function seek($offset, $whence = SEEK_SET)
{
call_user_func($this->_fn_seek, $offset, $whence);
}
public function isWritable()
{
return call_user_func($this->_fn_isWritable);
}
public function write($string)
{
return call_user_func($this->_fn_write, $string);
}
public function isReadable()
{
return call_user_func($this->_fn_isReadable);
}
public function read($length)
{
return call_user_func($this->_fn_read, $length);
}
public function getContents()
{
return call_user_func($this->_fn_getContents);
}
public function getMetadata($key = null)
{
return call_user_func($this->_fn_getMetadata, $key);
}
}

View File

@ -1,29 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.
*
* This stream decorator skips the first 10 bytes of the given stream to remove
* the gzip header, converts the provided stream to a PHP stream resource,
* then appends the zlib.inflate filter. The stream is then converted back
* to a Guzzle stream resource to be used as a Guzzle stream.
*
* @link http://tools.ietf.org/html/rfc1952
* @link http://php.net/manual/en/filters.compression.php
*/
class InflateStream implements StreamInterface
{
use StreamDecoratorTrait;
public function __construct(StreamInterface $stream)
{
// Skip the first 10 bytes
$stream = new LimitStream($stream, -1, 10);
$resource = StreamWrapper::getResource($stream);
stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);
$this->stream = new Stream($resource);
}
}

View File

@ -1,39 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Lazily reads or writes to a file that is opened only after an IO operation
* take place on the stream.
*/
class LazyOpenStream implements StreamInterface
{
use StreamDecoratorTrait;
/** @var string File to open */
private $filename;
/** @var string $mode */
private $mode;
/**
* @param string $filename File to lazily open
* @param string $mode fopen mode to use when opening the stream
*/
public function __construct($filename, $mode)
{
$this->filename = $filename;
$this->mode = $mode;
}
/**
* Creates the underlying stream lazily when required.
*
* @return StreamInterface
*/
protected function createStream()
{
return stream_for(try_fopen($this->filename, $this->mode));
}
}

View File

@ -1,155 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Decorator used to return only a subset of a stream
*/
class LimitStream implements StreamInterface
{
use StreamDecoratorTrait;
/** @var int Offset to start reading from */
private $offset;
/** @var int Limit the number of bytes that can be read */
private $limit;
/**
* @param StreamInterface $stream Stream to wrap
* @param int $limit Total number of bytes to allow to be read
* from the stream. Pass -1 for no limit.
* @param int|null $offset Position to seek to before reading (only
* works on seekable streams).
*/
public function __construct(
StreamInterface $stream,
$limit = -1,
$offset = 0
) {
$this->stream = $stream;
$this->setLimit($limit);
$this->setOffset($offset);
}
public function eof()
{
// Always return true if the underlying stream is EOF
if ($this->stream->eof()) {
return true;
}
// No limit and the underlying stream is not at EOF
if ($this->limit == -1) {
return false;
}
return $this->stream->tell() >= $this->offset + $this->limit;
}
/**
* Returns the size of the limited subset of data
* {@inheritdoc}
*/
public function getSize()
{
if (null === ($length = $this->stream->getSize())) {
return null;
} elseif ($this->limit == -1) {
return $length - $this->offset;
} else {
return min($this->limit, $length - $this->offset);
}
}
/**
* Allow for a bounded seek on the read limited stream
* {@inheritdoc}
*/
public function seek($offset, $whence = SEEK_SET)
{
if ($whence !== SEEK_SET || $offset < 0) {
throw new \RuntimeException(sprintf(
'Cannot seek to offset % with whence %s',
$offset,
$whence
));
}
$offset += $this->offset;
if ($this->limit !== -1) {
if ($offset > $this->offset + $this->limit) {
$offset = $this->offset + $this->limit;
}
}
$this->stream->seek($offset);
}
/**
* Give a relative tell()
* {@inheritdoc}
*/
public function tell()
{
return $this->stream->tell() - $this->offset;
}
/**
* Set the offset to start limiting from
*
* @param int $offset Offset to seek to and begin byte limiting from
*
* @throws \RuntimeException if the stream cannot be seeked.
*/
public function setOffset($offset)
{
$current = $this->stream->tell();
if ($current !== $offset) {
// If the stream cannot seek to the offset position, then read to it
if ($this->stream->isSeekable()) {
$this->stream->seek($offset);
} elseif ($current > $offset) {
throw new \RuntimeException("Could not seek to stream offset $offset");
} else {
$this->stream->read($offset - $current);
}
}
$this->offset = $offset;
}
/**
* Set the limit of bytes that the decorator allows to be read from the
* stream.
*
* @param int $limit Number of bytes to allow to be read from the stream.
* Use -1 for no limit.
*/
public function setLimit($limit)
{
$this->limit = $limit;
}
public function read($length)
{
if ($this->limit == -1) {
return $this->stream->read($length);
}
// Check if the current position is less than the total allowed
// bytes + original offset
$remaining = ($this->offset + $this->limit) - $this->stream->tell();
if ($remaining > 0) {
// Only return the amount of requested data, ensuring that the byte
// limit is not exceeded
return $this->stream->read(min($remaining, $length));
}
return '';
}
}

View File

@ -1,158 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Trait implementing functionality common to requests and responses.
*/
trait MessageTrait
{
/** @var array Cached HTTP header collection with lowercase key to values */
private $headers = [];
/** @var array Actual key to list of values per header. */
private $headerLines = [];
/** @var string */
private $protocol = '1.1';
/** @var StreamInterface */
private $stream;
public function getProtocolVersion()
{
return $this->protocol;
}
public function withProtocolVersion($version)
{
if ($this->protocol === $version) {
return $this;
}
$new = clone $this;
$new->protocol = $version;
return $new;
}
public function getHeaders()
{
return $this->headerLines;
}
public function hasHeader($header)
{
return isset($this->headers[strtolower($header)]);
}
public function getHeader($header)
{
$name = strtolower($header);
return isset($this->headers[$name]) ? $this->headers[$name] : [];
}
public function getHeaderLine($header)
{
return implode(', ', $this->getHeader($header));
}
public function withHeader($header, $value)
{
$new = clone $this;
$header = trim($header);
$name = strtolower($header);
if (!is_array($value)) {
$new->headers[$name] = [trim($value)];
} else {
$new->headers[$name] = $value;
foreach ($new->headers[$name] as &$v) {
$v = trim($v);
}
}
// Remove the header lines.
foreach (array_keys($new->headerLines) as $key) {
if (strtolower($key) === $name) {
unset($new->headerLines[$key]);
}
}
// Add the header line.
$new->headerLines[$header] = $new->headers[$name];
return $new;
}
public function withAddedHeader($header, $value)
{
if (!$this->hasHeader($header)) {
return $this->withHeader($header, $value);
}
$new = clone $this;
$new->headers[strtolower($header)][] = $value;
$new->headerLines[$header][] = $value;
return $new;
}
public function withoutHeader($header)
{
if (!$this->hasHeader($header)) {
return $this;
}
$new = clone $this;
$name = strtolower($header);
unset($new->headers[$name]);
foreach (array_keys($new->headerLines) as $key) {
if (strtolower($key) === $name) {
unset($new->headerLines[$key]);
}
}
return $new;
}
public function getBody()
{
if (!$this->stream) {
$this->stream = stream_for('');
}
return $this->stream;
}
public function withBody(StreamInterface $body)
{
if ($body === $this->stream) {
return $this;
}
$new = clone $this;
$new->stream = $body;
return $new;
}
private function setHeaders(array $headers)
{
$this->headerLines = $this->headers = [];
foreach ($headers as $header => $value) {
$header = trim($header);
$name = strtolower($header);
if (!is_array($value)) {
$value = trim($value);
$this->headers[$name][] = $value;
$this->headerLines[$header][] = $value;
} else {
foreach ($value as $v) {
$v = trim($v);
$this->headers[$name][] = $v;
$this->headerLines[$header][] = $v;
}
}
}
}
}

View File

@ -1,153 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Stream that when read returns bytes for a streaming multipart or
* multipart/form-data stream.
*/
class MultipartStream implements StreamInterface
{
use StreamDecoratorTrait;
private $boundary;
/**
* @param array $elements Array of associative arrays, each containing a
* required "name" key mapping to the form field,
* name, a required "contents" key mapping to a
* StreamInterface/resource/string, an optional
* "headers" associative array of custom headers,
* and an optional "filename" key mapping to a
* string to send as the filename in the part.
* @param string $boundary You can optionally provide a specific boundary
*
* @throws \InvalidArgumentException
*/
public function __construct(array $elements = [], $boundary = null)
{
$this->boundary = $boundary ?: uniqid();
$this->stream = $this->createStream($elements);
}
/**
* Get the boundary
*
* @return string
*/
public function getBoundary()
{
return $this->boundary;
}
public function isWritable()
{
return false;
}
/**
* Get the headers needed before transferring the content of a POST file
*/
private function getHeaders(array $headers)
{
$str = '';
foreach ($headers as $key => $value) {
$str .= "{$key}: {$value}\r\n";
}
return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n";
}
/**
* Create the aggregate stream that will be used to upload the POST data
*/
protected function createStream(array $elements)
{
$stream = new AppendStream();
foreach ($elements as $element) {
$this->addElement($stream, $element);
}
// Add the trailing boundary with CRLF
$stream->addStream(stream_for("--{$this->boundary}--\r\n"));
return $stream;
}
private function addElement(AppendStream $stream, array $element)
{
foreach (['contents', 'name'] as $key) {
if (!array_key_exists($key, $element)) {
throw new \InvalidArgumentException("A '{$key}' key is required");
}
}
$element['contents'] = stream_for($element['contents']);
if (empty($element['filename'])) {
$uri = $element['contents']->getMetadata('uri');
if (substr($uri, 0, 6) !== 'php://') {
$element['filename'] = $uri;
}
}
list($body, $headers) = $this->createElement(
$element['name'],
$element['contents'],
isset($element['filename']) ? $element['filename'] : null,
isset($element['headers']) ? $element['headers'] : []
);
$stream->addStream(stream_for($this->getHeaders($headers)));
$stream->addStream($body);
$stream->addStream(stream_for("\r\n"));
}
/**
* @return array
*/
private function createElement($name, $stream, $filename, array $headers)
{
// Set a default content-disposition header if one was no provided
$disposition = $this->getHeader($headers, 'content-disposition');
if (!$disposition) {
$headers['Content-Disposition'] = $filename
? sprintf('form-data; name="%s"; filename="%s"',
$name,
basename($filename))
: "form-data; name=\"{$name}\"";
}
// Set a default content-length header if one was no provided
$length = $this->getHeader($headers, 'content-length');
if (!$length) {
if ($length = $stream->getSize()) {
$headers['Content-Length'] = (string) $length;
}
}
// Set a default Content-Type if one was not supplied
$type = $this->getHeader($headers, 'content-type');
if (!$type && $filename) {
if ($type = mimetype_from_filename($filename)) {
$headers['Content-Type'] = $type;
}
}
return [$stream, $headers];
}
private function getHeader(array $headers, $key)
{
$lowercaseHeader = strtolower($key);
foreach ($headers as $k => $v) {
if (strtolower($k) === $lowercaseHeader) {
return $v;
}
}
return null;
}
}

View File

@ -1,22 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Stream decorator that prevents a stream from being seeked
*/
class NoSeekStream implements StreamInterface
{
use StreamDecoratorTrait;
public function seek($offset, $whence = SEEK_SET)
{
throw new \RuntimeException('Cannot seek a NoSeekStream');
}
public function isSeekable()
{
return false;
}
}

View File

@ -1,165 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Provides a read only stream that pumps data from a PHP callable.
*
* When invoking the provided callable, the PumpStream will pass the amount of
* data requested to read to the callable. The callable can choose to ignore
* this value and return fewer or more bytes than requested. Any extra data
* returned by the provided callable is buffered internally until drained using
* the read() function of the PumpStream. The provided callable MUST return
* false when there is no more data to read.
*/
class PumpStream implements StreamInterface
{
/** @var callable */
private $source;
/** @var int */
private $size;
/** @var int */
private $tellPos = 0;
/** @var array */
private $metadata;
/** @var BufferStream */
private $buffer;
/**
* @param callable $source Source of the stream data. The callable MAY
* accept an integer argument used to control the
* amount of data to return. The callable MUST
* return a string when called, or false on error
* or EOF.
* @param array $options Stream options:
* - metadata: Hash of metadata to use with stream.
* - size: Size of the stream, if known.
*/
public function __construct(callable $source, array $options = [])
{
$this->source = $source;
$this->size = isset($options['size']) ? $options['size'] : null;
$this->metadata = isset($options['metadata']) ? $options['metadata'] : [];
$this->buffer = new BufferStream();
}
public function __toString()
{
try {
return copy_to_string($this);
} catch (\Exception $e) {
return '';
}
}
public function close()
{
$this->detach();
}
public function detach()
{
$this->tellPos = false;
$this->source = null;
}
public function getSize()
{
return $this->size;
}
public function tell()
{
return $this->tellPos;
}
public function eof()
{
return !$this->source;
}
public function isSeekable()
{
return false;
}
public function rewind()
{
$this->seek(0);
}
public function seek($offset, $whence = SEEK_SET)
{
throw new \RuntimeException('Cannot seek a PumpStream');
}
public function isWritable()
{
return false;
}
public function write($string)
{
throw new \RuntimeException('Cannot write to a PumpStream');
}
public function isReadable()
{
return true;
}
public function read($length)
{
$data = $this->buffer->read($length);
$readLen = strlen($data);
$this->tellPos += $readLen;
$remaining = $length - $readLen;
if ($remaining) {
$this->pump($remaining);
$data .= $this->buffer->read($remaining);
$this->tellPos += strlen($data) - $readLen;
}
return $data;
}
public function getContents()
{
$result = '';
while (!$this->eof()) {
$result .= $this->read(1000000);
}
return $result;
}
public function getMetadata($key = null)
{
if (!$key) {
return $this->metadata;
}
return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
}
private function pump($length)
{
if ($this->source) {
do {
$data = call_user_func($this->source, $length);
if ($data === false || $data === null) {
$this->source = null;
return;
}
$this->buffer->write($data);
$length -= strlen($data);
} while ($length > 0);
}
}
}

View File

@ -1,149 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use InvalidArgumentException;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;
/**
* PSR-7 request implementation.
*/
class Request implements RequestInterface
{
use MessageTrait {
withHeader as protected withParentHeader;
}
/** @var string */
private $method;
/** @var null|string */
private $requestTarget;
/** @var null|UriInterface */
private $uri;
/**
* @param null|string $method HTTP method for the request.
* @param null|string $uri URI for the request.
* @param array $headers Headers for the message.
* @param string|resource|StreamInterface $body Message body.
* @param string $protocolVersion HTTP protocol version.
*
* @throws InvalidArgumentException for an invalid URI
*/
public function __construct(
$method,
$uri,
array $headers = [],
$body = null,
$protocolVersion = '1.1'
) {
if (is_string($uri)) {
$uri = new Uri($uri);
} elseif (!($uri instanceof UriInterface)) {
throw new \InvalidArgumentException(
'URI must be a string or Psr\Http\Message\UriInterface'
);
}
$this->method = strtoupper($method);
$this->uri = $uri;
$this->setHeaders($headers);
$this->protocol = $protocolVersion;
$host = $uri->getHost();
if ($host && !$this->hasHeader('Host')) {
$this->updateHostFromUri($host);
}
if ($body) {
$this->stream = stream_for($body);
}
}
public function getRequestTarget()
{
if ($this->requestTarget !== null) {
return $this->requestTarget;
}
$target = $this->uri->getPath();
if ($target == null) {
$target = '/';
}
if ($this->uri->getQuery()) {
$target .= '?' . $this->uri->getQuery();
}
return $target;
}
public function withRequestTarget($requestTarget)
{
if (preg_match('#\s#', $requestTarget)) {
throw new InvalidArgumentException(
'Invalid request target provided; cannot contain whitespace'
);
}
$new = clone $this;
$new->requestTarget = $requestTarget;
return $new;
}
public function getMethod()
{
return $this->method;
}
public function withMethod($method)
{
$new = clone $this;
$new->method = strtoupper($method);
return $new;
}
public function getUri()
{
return $this->uri;
}
public function withUri(UriInterface $uri, $preserveHost = false)
{
if ($uri === $this->uri) {
return $this;
}
$new = clone $this;
$new->uri = $uri;
if (!$preserveHost) {
if ($host = $uri->getHost()) {
$new->updateHostFromUri($host);
}
}
return $new;
}
public function withHeader($header, $value)
{
/** @var Request $newInstance */
$newInstance = $this->withParentHeader($header, $value);
return $newInstance;
}
private function updateHostFromUri($host)
{
// Ensure Host is the first header.
// See: http://tools.ietf.org/html/rfc7230#section-5.4
if ($port = $this->uri->getPort()) {
$host .= ':' . $port;
}
$this->headerLines = ['Host' => [$host]] + $this->headerLines;
$this->headers = ['host' => [$host]] + $this->headers;
}
}

View File

@ -1,130 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\ResponseInterface;
/**
* PSR-7 response implementation.
*/
class Response implements ResponseInterface
{
use MessageTrait;
/** @var array Map of standard HTTP status code/reason phrases */
private static $phrases = [
100 => 'Continue',
101 => 'Switching Protocols',
102 => 'Processing',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
207 => 'Multi-status',
208 => 'Already Reported',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
306 => 'Switch Proxy',
307 => 'Temporary Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Time-out',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Large',
415 => 'Unsupported Media Type',
416 => 'Requested range not satisfiable',
417 => 'Expectation Failed',
418 => 'I\'m a teapot',
422 => 'Unprocessable Entity',
423 => 'Locked',
424 => 'Failed Dependency',
425 => 'Unordered Collection',
426 => 'Upgrade Required',
428 => 'Precondition Required',
429 => 'Too Many Requests',
431 => 'Request Header Fields Too Large',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Time-out',
505 => 'HTTP Version not supported',
506 => 'Variant Also Negotiates',
507 => 'Insufficient Storage',
508 => 'Loop Detected',
511 => 'Network Authentication Required',
];
/** @var null|string */
private $reasonPhrase = '';
/** @var int */
private $statusCode = 200;
/**
* @param int $status Status code for the response, if any.
* @param array $headers Headers for the response, if any.
* @param mixed $body Stream body.
* @param string $version Protocol version.
* @param string $reason Reason phrase (a default will be used if possible).
*/
public function __construct(
$status = 200,
array $headers = [],
$body = null,
$version = '1.1',
$reason = null
) {
$this->statusCode = (int) $status;
if ($body) {
$this->stream = stream_for($body);
}
$this->setHeaders($headers);
if (!$reason && isset(self::$phrases[$this->statusCode])) {
$this->reasonPhrase = self::$phrases[$status];
} else {
$this->reasonPhrase = (string) $reason;
}
$this->protocol = $version;
}
public function getStatusCode()
{
return $this->statusCode;
}
public function getReasonPhrase()
{
return $this->reasonPhrase;
}
public function withStatus($code, $reasonPhrase = '')
{
$new = clone $this;
$new->statusCode = (int) $code;
if (!$reasonPhrase && isset(self::$phrases[$new->statusCode])) {
$reasonPhrase = self::$phrases[$new->statusCode];
}
$new->reasonPhrase = $reasonPhrase;
return $new;
}
}

View File

@ -1,245 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* PHP stream implementation.
*
* @var $stream
*/
class Stream implements StreamInterface
{
private $stream;
private $size;
private $seekable;
private $readable;
private $writable;
private $uri;
private $customMetadata;
/** @var array Hash of readable and writable stream types */
private static $readWriteHash = [
'read' => [
'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
'x+t' => true, 'c+t' => true, 'a+' => true
],
'write' => [
'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
]
];
/**
* This constructor accepts an associative array of options.
*
* - size: (int) If a read stream would otherwise have an indeterminate
* size, but the size is known due to foreknownledge, then you can
* provide that size, in bytes.
* - metadata: (array) Any additional metadata to return when the metadata
* of the stream is accessed.
*
* @param resource $stream Stream resource to wrap.
* @param array $options Associative array of options.
*
* @throws \InvalidArgumentException if the stream is not a stream resource
*/
public function __construct($stream, $options = [])
{
if (!is_resource($stream)) {
throw new \InvalidArgumentException('Stream must be a resource');
}
if (isset($options['size'])) {
$this->size = $options['size'];
}
$this->customMetadata = isset($options['metadata'])
? $options['metadata']
: [];
$this->stream = $stream;
$meta = stream_get_meta_data($this->stream);
$this->seekable = $meta['seekable'];
$this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
$this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
$this->uri = $this->getMetadata('uri');
}
public function __get($name)
{
if ($name == 'stream') {
throw new \RuntimeException('The stream is detached');
}
throw new \BadMethodCallException('No value for ' . $name);
}
/**
* Closes the stream when the destructed
*/
public function __destruct()
{
$this->close();
}
public function __toString()
{
try {
$this->seek(0);
return (string) stream_get_contents($this->stream);
} catch (\Exception $e) {
return '';
}
}
public function getContents()
{
$contents = stream_get_contents($this->stream);
if ($contents === false) {
throw new \RuntimeException('Unable to read stream contents');
}
return $contents;
}
public function close()
{
if (isset($this->stream)) {
if (is_resource($this->stream)) {
fclose($this->stream);
}
$this->detach();
}
}
public function detach()
{
if (!isset($this->stream)) {
return null;
}
$result = $this->stream;
unset($this->stream);
$this->size = $this->uri = null;
$this->readable = $this->writable = $this->seekable = false;
return $result;
}
public function getSize()
{
if ($this->size !== null) {
return $this->size;
}
if (!isset($this->stream)) {
return null;
}
// Clear the stat cache if the stream has a URI
if ($this->uri) {
clearstatcache(true, $this->uri);
}
$stats = fstat($this->stream);
if (isset($stats['size'])) {
$this->size = $stats['size'];
return $this->size;
}
return null;
}
public function isReadable()
{
return $this->readable;
}
public function isWritable()
{
return $this->writable;
}
public function isSeekable()
{
return $this->seekable;
}
public function eof()
{
return !$this->stream || feof($this->stream);
}
public function tell()
{
$result = ftell($this->stream);
if ($result === false) {
throw new \RuntimeException('Unable to determine stream position');
}
return $result;
}
public function rewind()
{
$this->seek(0);
}
public function seek($offset, $whence = SEEK_SET)
{
if (!$this->seekable) {
throw new \RuntimeException('Stream is not seekable');
} elseif (fseek($this->stream, $offset, $whence) === -1) {
throw new \RuntimeException('Unable to seek to stream position '
. $offset . ' with whence ' . var_export($whence, true));
}
}
public function read($length)
{
if (!$this->readable) {
throw new \RuntimeException('Cannot read from non-readable stream');
}
return fread($this->stream, $length);
}
public function write($string)
{
if (!$this->writable) {
throw new \RuntimeException('Cannot write to a non-writable stream');
}
// We can't know the size after writing anything
$this->size = null;
$result = fwrite($this->stream, $string);
if ($result === false) {
throw new \RuntimeException('Unable to write to stream');
}
return $result;
}
public function getMetadata($key = null)
{
if (!isset($this->stream)) {
return $key ? null : [];
} elseif (!$key) {
return $this->customMetadata + stream_get_meta_data($this->stream);
} elseif (isset($this->customMetadata[$key])) {
return $this->customMetadata[$key];
}
$meta = stream_get_meta_data($this->stream);
return isset($meta[$key]) ? $meta[$key] : null;
}
}

View File

@ -1,149 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Stream decorator trait
* @property StreamInterface stream
*/
trait StreamDecoratorTrait
{
/**
* @param StreamInterface $stream Stream to decorate
*/
public function __construct(StreamInterface $stream)
{
$this->stream = $stream;
}
/**
* Magic method used to create a new stream if streams are not added in
* the constructor of a decorator (e.g., LazyOpenStream).
*
* @param string $name Name of the property (allows "stream" only).
*
* @return StreamInterface
*/
public function __get($name)
{
if ($name == 'stream') {
$this->stream = $this->createStream();
return $this->stream;
}
throw new \UnexpectedValueException("$name not found on class");
}
public function __toString()
{
try {
if ($this->isSeekable()) {
$this->seek(0);
}
return $this->getContents();
} catch (\Exception $e) {
// Really, PHP? https://bugs.php.net/bug.php?id=53648
trigger_error('StreamDecorator::__toString exception: '
. (string) $e, E_USER_ERROR);
return '';
}
}
public function getContents()
{
return copy_to_string($this);
}
/**
* Allow decorators to implement custom methods
*
* @param string $method Missing method name
* @param array $args Method arguments
*
* @return mixed
*/
public function __call($method, array $args)
{
$result = call_user_func_array([$this->stream, $method], $args);
// Always return the wrapped object if the result is a return $this
return $result === $this->stream ? $this : $result;
}
public function close()
{
$this->stream->close();
}
public function getMetadata($key = null)
{
return $this->stream->getMetadata($key);
}
public function detach()
{
return $this->stream->detach();
}
public function getSize()
{
return $this->stream->getSize();
}
public function eof()
{
return $this->stream->eof();
}
public function tell()
{
return $this->stream->tell();
}
public function isReadable()
{
return $this->stream->isReadable();
}
public function isWritable()
{
return $this->stream->isWritable();
}
public function isSeekable()
{
return $this->stream->isSeekable();
}
public function rewind()
{
$this->seek(0);
}
public function seek($offset, $whence = SEEK_SET)
{
$this->stream->seek($offset, $whence);
}
public function read($length)
{
return $this->stream->read($length);
}
public function write($string)
{
return $this->stream->write($string);
}
/**
* Implement in subclasses to dynamically create streams when requested.
*
* @return StreamInterface
* @throws \BadMethodCallException
*/
protected function createStream()
{
throw new \BadMethodCallException('Not implemented');
}
}

View File

@ -1,121 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
/**
* Converts Guzzle streams into PHP stream resources.
*/
class StreamWrapper
{
/** @var resource */
public $context;
/** @var StreamInterface */
private $stream;
/** @var string r, r+, or w */
private $mode;
/**
* Returns a resource representing the stream.
*
* @param StreamInterface $stream The stream to get a resource for
*
* @return resource
* @throws \InvalidArgumentException if stream is not readable or writable
*/
public static function getResource(StreamInterface $stream)
{
self::register();
if ($stream->isReadable()) {
$mode = $stream->isWritable() ? 'r+' : 'r';
} elseif ($stream->isWritable()) {
$mode = 'w';
} else {
throw new \InvalidArgumentException('The stream must be readable, '
. 'writable, or both.');
}
return fopen('guzzle://stream', $mode, null, stream_context_create([
'guzzle' => ['stream' => $stream]
]));
}
/**
* Registers the stream wrapper if needed
*/
public static function register()
{
if (!in_array('guzzle', stream_get_wrappers())) {
stream_wrapper_register('guzzle', __CLASS__);
}
}
public function stream_open($path, $mode, $options, &$opened_path)
{
$options = stream_context_get_options($this->context);
if (!isset($options['guzzle']['stream'])) {
return false;
}
$this->mode = $mode;
$this->stream = $options['guzzle']['stream'];
return true;
}
public function stream_read($count)
{
return $this->stream->read($count);
}
public function stream_write($data)
{
return (int) $this->stream->write($data);
}
public function stream_tell()
{
return $this->stream->tell();
}
public function stream_eof()
{
return $this->stream->eof();
}
public function stream_seek($offset, $whence)
{
$this->stream->seek($offset, $whence);
return true;
}
public function stream_stat()
{
static $modeMap = [
'r' => 33060,
'r+' => 33206,
'w' => 33188
];
return [
'dev' => 0,
'ino' => 0,
'mode' => $modeMap[$this->mode],
'nlink' => 0,
'uid' => 0,
'gid' => 0,
'rdev' => 0,
'size' => $this->stream->getSize() ?: 0,
'atime' => 0,
'mtime' => 0,
'ctime' => 0,
'blksize' => 0,
'blocks' => 0
];
}
}

View File

@ -1,604 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\UriInterface;
/**
* Basic PSR-7 URI implementation.
*
* @link https://github.com/phly/http This class is based upon
* Matthew Weier O'Phinney's URI implementation in phly/http.
*/
class Uri implements UriInterface
{
private static $schemes = [
'http' => 80,
'https' => 443,
];
private static $charUnreserved = 'a-zA-Z0-9_\-\.~';
private static $charSubDelims = '!\$&\'\(\)\*\+,;=';
private static $replaceQuery = ['=' => '%3D', '&' => '%26'];
/** @var string Uri scheme. */
private $scheme = '';
/** @var string Uri user info. */
private $userInfo = '';
/** @var string Uri host. */
private $host = '';
/** @var int|null Uri port. */
private $port;
/** @var string Uri path. */
private $path = '';
/** @var string Uri query string. */
private $query = '';
/** @var string Uri fragment. */
private $fragment = '';
/**
* @param string $uri URI to parse and wrap.
*/
public function __construct($uri = '')
{
if ($uri != null) {
$parts = parse_url($uri);
if ($parts === false) {
throw new \InvalidArgumentException("Unable to parse URI: $uri");
}
$this->applyParts($parts);
}
}
public function __toString()
{
return self::createUriString(
$this->scheme,
$this->getAuthority(),
$this->getPath(),
$this->query,
$this->fragment
);
}
/**
* Removes dot segments from a path and returns the new path.
*
* @param string $path
*
* @return string
* @link http://tools.ietf.org/html/rfc3986#section-5.2.4
*/
public static function removeDotSegments($path)
{
static $noopPaths = ['' => true, '/' => true, '*' => true];
static $ignoreSegments = ['.' => true, '..' => true];
if (isset($noopPaths[$path])) {
return $path;
}
$results = [];
$segments = explode('/', $path);
foreach ($segments as $segment) {
if ($segment == '..') {
array_pop($results);
} elseif (!isset($ignoreSegments[$segment])) {
$results[] = $segment;
}
}
$newPath = implode('/', $results);
// Add the leading slash if necessary
if (substr($path, 0, 1) === '/' &&
substr($newPath, 0, 1) !== '/'
) {
$newPath = '/' . $newPath;
}
// Add the trailing slash if necessary
if ($newPath != '/' && isset($ignoreSegments[end($segments)])) {
$newPath .= '/';
}
return $newPath;
}
/**
* Resolve a base URI with a relative URI and return a new URI.
*
* @param UriInterface $base Base URI
* @param string $rel Relative URI
*
* @return UriInterface
*/
public static function resolve(UriInterface $base, $rel)
{
if ($rel === null || $rel === '') {
return $base;
}
if ($rel instanceof UriInterface) {
$relParts = [
'scheme' => $rel->getScheme(),
'host' => $rel->getHost(),
'port' => $rel->getPort(),
'path' => $rel->getPath(),
'query' => $rel->getQuery(),
'fragment' => $rel->getFragment()
];
} else {
$relParts = parse_url($rel) + [
'scheme' => '',
'host' => '',
'port' => '',
'path' => '',
'query' => '',
'fragment' => ''
];
}
if (!empty($relParts['scheme']) && !empty($relParts['host'])) {
return $rel instanceof UriInterface
? $rel
: self::fromParts($relParts);
}
$parts = [
'scheme' => $base->getScheme(),
'host' => $base->getHost(),
'port' => $base->getPort(),
'path' => $base->getPath(),
'query' => $base->getQuery(),
'fragment' => $base->getFragment()
];
if (!empty($relParts['host'])) {
$parts['host'] = $relParts['host'];
$parts['port'] = $relParts['port'];
$parts['path'] = self::removeDotSegments($relParts['path']);
$parts['query'] = $relParts['query'];
$parts['fragment'] = $relParts['fragment'];
} elseif (!empty($relParts['path'])) {
if (substr($relParts['path'], 0, 1) == '/') {
$parts['path'] = self::removeDotSegments($relParts['path']);
$parts['query'] = $relParts['query'];
$parts['fragment'] = $relParts['fragment'];
} else {
if (!empty($parts['host']) && empty($parts['path'])) {
$mergedPath = '/';
} else {
$mergedPath = substr($parts['path'], 0, strrpos($parts['path'], '/') + 1);
}
$parts['path'] = self::removeDotSegments($mergedPath . $relParts['path']);
$parts['query'] = $relParts['query'];
$parts['fragment'] = $relParts['fragment'];
}
} elseif (!empty($relParts['query'])) {
$parts['query'] = $relParts['query'];
} elseif ($relParts['fragment'] != null) {
$parts['fragment'] = $relParts['fragment'];
}
return static::fromParts($parts);
}
/**
* Create a new URI with a specific query string value removed.
*
* Any existing query string values that exactly match the provided key are
* removed.
*
* Note: this function will convert "=" to "%3D" and "&" to "%26".
*
* @param UriInterface $uri URI to use as a base.
* @param string $key Query string key value pair to remove.
*
* @return UriInterface
*/
public static function withoutQueryValue(UriInterface $uri, $key)
{
$current = $uri->getQuery();
if (!$current) {
return $uri;
}
$result = [];
foreach (explode('&', $current) as $part) {
if (explode('=', $part)[0] !== $key) {
$result[] = $part;
};
}
return $uri->withQuery(implode('&', $result));
}
/**
* Create a new URI with a specific query string value.
*
* Any existing query string values that exactly match the provided key are
* removed and replaced with the given key value pair.
*
* Note: this function will convert "=" to "%3D" and "&" to "%26".
*
* @param UriInterface $uri URI to use as a base.
* @param string $key Key to set.
* @param string $value Value to set.
*
* @return UriInterface
*/
public static function withQueryValue(UriInterface $uri, $key, $value)
{
$current = $uri->getQuery();
$key = strtr($key, self::$replaceQuery);
if (!$current) {
$result = [];
} else {
$result = [];
foreach (explode('&', $current) as $part) {
if (explode('=', $part)[0] !== $key) {
$result[] = $part;
};
}
}
if ($value !== null) {
$result[] = $key . '=' . strtr($value, self::$replaceQuery);
} else {
$result[] = $key;
}
return $uri->withQuery(implode('&', $result));
}
/**
* Create a URI from a hash of parse_url parts.
*
* @param array $parts
*
* @return self
*/
public static function fromParts(array $parts)
{
$uri = new self();
$uri->applyParts($parts);
return $uri;
}
public function getScheme()
{
return $this->scheme;
}
public function getAuthority()
{
if (empty($this->host)) {
return '';
}
$authority = $this->host;
if (!empty($this->userInfo)) {
$authority = $this->userInfo . '@' . $authority;
}
if ($this->isNonStandardPort($this->scheme, $this->host, $this->port)) {
$authority .= ':' . $this->port;
}
return $authority;
}
public function getUserInfo()
{
return $this->userInfo;
}
public function getHost()
{
return $this->host;
}
public function getPort()
{
return $this->port;
}
public function getPath()
{
return $this->path == null ? '' : $this->path;
}
public function getQuery()
{
return $this->query;
}
public function getFragment()
{
return $this->fragment;
}
public function withScheme($scheme)
{
$scheme = $this->filterScheme($scheme);
if ($this->scheme === $scheme) {
return $this;
}
$new = clone $this;
$new->scheme = $scheme;
$new->port = $new->filterPort($new->scheme, $new->host, $new->port);
return $new;
}
public function withUserInfo($user, $password = null)
{
$info = $user;
if ($password) {
$info .= ':' . $password;
}
if ($this->userInfo === $info) {
return $this;
}
$new = clone $this;
$new->userInfo = $info;
return $new;
}
public function withHost($host)
{
if ($this->host === $host) {
return $this;
}
$new = clone $this;
$new->host = $host;
return $new;
}
public function withPort($port)
{
$port = $this->filterPort($this->scheme, $this->host, $port);
if ($this->port === $port) {
return $this;
}
$new = clone $this;
$new->port = $port;
return $new;
}
public function withPath($path)
{
if (!is_string($path)) {
throw new \InvalidArgumentException(
'Invalid path provided; must be a string'
);
}
$path = $this->filterPath($path);
if ($this->path === $path) {
return $this;
}
$new = clone $this;
$new->path = $path;
return $new;
}
public function withQuery($query)
{
if (!is_string($query) && !method_exists($query, '__toString')) {
throw new \InvalidArgumentException(
'Query string must be a string'
);
}
$query = (string) $query;
if (substr($query, 0, 1) === '?') {
$query = substr($query, 1);
}
$query = $this->filterQueryAndFragment($query);
if ($this->query === $query) {
return $this;
}
$new = clone $this;
$new->query = $query;
return $new;
}
public function withFragment($fragment)
{
if (substr($fragment, 0, 1) === '#') {
$fragment = substr($fragment, 1);
}
$fragment = $this->filterQueryAndFragment($fragment);
if ($this->fragment === $fragment) {
return $this;
}
$new = clone $this;
$new->fragment = $fragment;
return $new;
}
/**
* Apply parse_url parts to a URI.
*
* @param $parts Array of parse_url parts to apply.
*/
private function applyParts(array $parts)
{
$this->scheme = isset($parts['scheme'])
? $this->filterScheme($parts['scheme'])
: '';
$this->userInfo = isset($parts['user']) ? $parts['user'] : '';
$this->host = isset($parts['host']) ? $parts['host'] : '';
$this->port = !empty($parts['port'])
? $this->filterPort($this->scheme, $this->host, $parts['port'])
: null;
$this->path = isset($parts['path'])
? $this->filterPath($parts['path'])
: '';
$this->query = isset($parts['query'])
? $this->filterQueryAndFragment($parts['query'])
: '';
$this->fragment = isset($parts['fragment'])
? $this->filterQueryAndFragment($parts['fragment'])
: '';
if (isset($parts['pass'])) {
$this->userInfo .= ':' . $parts['pass'];
}
}
/**
* Create a URI string from its various parts
*
* @param string $scheme
* @param string $authority
* @param string $path
* @param string $query
* @param string $fragment
* @return string
*/
private static function createUriString($scheme, $authority, $path, $query, $fragment)
{
$uri = '';
if (!empty($scheme)) {
$uri .= $scheme . '://';
}
if (!empty($authority)) {
$uri .= $authority;
}
if ($path != null) {
// Add a leading slash if necessary.
if ($uri && substr($path, 0, 1) !== '/') {
$uri .= '/';
}
$uri .= $path;
}
if ($query != null) {
$uri .= '?' . $query;
}
if ($fragment != null) {
$uri .= '#' . $fragment;
}
return $uri;
}
/**
* Is a given port non-standard for the current scheme?
*
* @param string $scheme
* @param string $host
* @param int $port
* @return bool
*/
private static function isNonStandardPort($scheme, $host, $port)
{
if (!$scheme && $port) {
return true;
}
if (!$host || !$port) {
return false;
}
return !isset(static::$schemes[$scheme]) || $port !== static::$schemes[$scheme];
}
/**
* @param string $scheme
*
* @return string
*/
private function filterScheme($scheme)
{
$scheme = strtolower($scheme);
$scheme = rtrim($scheme, ':/');
return $scheme;
}
/**
* @param string $scheme
* @param string $host
* @param int $port
*
* @return int|null
*
* @throws \InvalidArgumentException If the port is invalid.
*/
private function filterPort($scheme, $host, $port)
{
if (null !== $port) {
$port = (int) $port;
if (1 > $port || 0xffff < $port) {
throw new \InvalidArgumentException(
sprintf('Invalid port: %d. Must be between 1 and 65535', $port)
);
}
}
return $this->isNonStandardPort($scheme, $host, $port) ? $port : null;
}
/**
* Filters the path of a URI
*
* @param $path
*
* @return string
*/
private function filterPath($path)
{
return preg_replace_callback(
'/(?:[^' . self::$charUnreserved . self::$charSubDelims . ':@\/%]+|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'],
$path
);
}
/**
* Filters the query string or fragment of a URI.
*
* @param $str
*
* @return string
*/
private function filterQueryAndFragment($str)
{
return preg_replace_callback(
'/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'],
$str
);
}
private function rawurlencodeMatchZero(array $match)
{
return rawurlencode($match[0]);
}
}

View File

@ -1,799 +0,0 @@
<?php
namespace GuzzleHttp\Psr7;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;
/**
* Returns the string representation of an HTTP message.
*
* @param MessageInterface $message Message to convert to a string.
*
* @return string
*/
function str(MessageInterface $message)
{
if ($message instanceof RequestInterface) {
$msg = trim($message->getMethod() . ' '
. $message->getRequestTarget())
. ' HTTP/' . $message->getProtocolVersion();
if (!$message->hasHeader('host')) {
$msg .= "\r\nHost: " . $message->getUri()->getHost();
}
} elseif ($message instanceof ResponseInterface) {
$msg = 'HTTP/' . $message->getProtocolVersion() . ' '
. $message->getStatusCode() . ' '
. $message->getReasonPhrase();
} else {
throw new \InvalidArgumentException('Unknown message type');
}
foreach ($message->getHeaders() as $name => $values) {
$msg .= "\r\n{$name}: " . implode(', ', $values);
}
return "{$msg}\r\n\r\n" . $message->getBody();
}
/**
* Returns a UriInterface for the given value.
*
* This function accepts a string or {@see Psr\Http\Message\UriInterface} and
* returns a UriInterface for the given value. If the value is already a
* `UriInterface`, it is returned as-is.
*
* @param string|UriInterface $uri
*
* @return UriInterface
* @throws \InvalidArgumentException
*/
function uri_for($uri)
{
if ($uri instanceof UriInterface) {
return $uri;
} elseif (is_string($uri)) {
return new Uri($uri);
}
throw new \InvalidArgumentException('URI must be a string or UriInterface');
}
/**
* Create a new stream based on the input type.
*
* Options is an associative array that can contain the following keys:
* - metadata: Array of custom metadata.
* - size: Size of the stream.
*
* @param resource|string|StreamInterface $resource Entity body data
* @param array $options Additional options
*
* @return Stream
* @throws \InvalidArgumentException if the $resource arg is not valid.
*/
function stream_for($resource = '', array $options = [])
{
switch (gettype($resource)) {
case 'string':
$stream = fopen('php://temp', 'r+');
if ($resource !== '') {
fwrite($stream, $resource);
fseek($stream, 0);
}
return new Stream($stream, $options);
case 'resource':
return new Stream($resource, $options);
case 'object':
if ($resource instanceof StreamInterface) {
return $resource;
} elseif ($resource instanceof \Iterator) {
return new PumpStream(function () use ($resource) {
if (!$resource->valid()) {
return false;
}
$result = $resource->current();
$resource->next();
return $result;
}, $options);
} elseif (method_exists($resource, '__toString')) {
return stream_for((string) $resource, $options);
}
break;
case 'NULL':
return new Stream(fopen('php://temp', 'r+'), $options);
}
if (is_callable($resource)) {
return new PumpStream($resource, $options);
}
throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource));
}
/**
* Parse an array of header values containing ";" separated data into an
* array of associative arrays representing the header key value pair
* data of the header. When a parameter does not contain a value, but just
* contains a key, this function will inject a key with a '' string value.
*
* @param string|array $header Header to parse into components.
*
* @return array Returns the parsed header values.
*/
function parse_header($header)
{
static $trimmed = "\"' \n\t\r";
$params = $matches = [];
foreach (normalize_header($header) as $val) {
$part = [];
foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
$m = $matches[0];
if (isset($m[1])) {
$part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
} else {
$part[] = trim($m[0], $trimmed);
}
}
}
if ($part) {
$params[] = $part;
}
}
return $params;
}
/**
* Converts an array of header values that may contain comma separated
* headers into an array of headers with no comma separated values.
*
* @param string|array $header Header to normalize.
*
* @return array Returns the normalized header field values.
*/
function normalize_header($header)
{
if (!is_array($header)) {
return array_map('trim', explode(',', $header));
}
$result = [];
foreach ($header as $value) {
foreach ((array) $value as $v) {
if (strpos($v, ',') === false) {
$result[] = $v;
continue;
}
foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) {
$result[] = trim($vv);
}
}
}
return $result;
}
/**
* Clone and modify a request with the given changes.
*
* The changes can be one of:
* - method: (string) Changes the HTTP method.
* - set_headers: (array) Sets the given headers.
* - remove_headers: (array) Remove the given headers.
* - body: (mixed) Sets the given body.
* - uri: (UriInterface) Set the URI.
* - query: (string) Set the query string value of the URI.
* - version: (string) Set the protocol version.
*
* @param RequestInterface $request Request to clone and modify.
* @param array $changes Changes to apply.
*
* @return RequestInterface
*/
function modify_request(RequestInterface $request, array $changes)
{
if (!$changes) {
return $request;
}
$headers = $request->getHeaders();
if (!isset($changes['uri'])) {
$uri = $request->getUri();
} else {
// Remove the host header if one is on the URI
if ($host = $changes['uri']->getHost()) {
$changes['set_headers']['Host'] = $host;
}
$uri = $changes['uri'];
}
if (!empty($changes['remove_headers'])) {
$headers = _caseless_remove($changes['remove_headers'], $headers);
}
if (!empty($changes['set_headers'])) {
$headers = _caseless_remove(array_keys($changes['set_headers']), $headers);
$headers = $changes['set_headers'] + $headers;
}
if (isset($changes['query'])) {
$uri = $uri->withQuery($changes['query']);
}
return new Request(
isset($changes['method']) ? $changes['method'] : $request->getMethod(),
$uri,
$headers,
isset($changes['body']) ? $changes['body'] : $request->getBody(),
isset($changes['version'])
? $changes['version']
: $request->getProtocolVersion()
);
}
/**
* Attempts to rewind a message body and throws an exception on failure.
*
* The body of the message will only be rewound if a call to `tell()` returns a
* value other than `0`.
*
* @param MessageInterface $message Message to rewind
*
* @throws \RuntimeException
*/
function rewind_body(MessageInterface $message)
{
$body = $message->getBody();
if ($body->tell()) {
$body->rewind();
}
}
/**
* Safely opens a PHP stream resource using a filename.
*
* When fopen fails, PHP normally raises a warning. This function adds an
* error handler that checks for errors and throws an exception instead.
*
* @param string $filename File to open
* @param string $mode Mode used to open the file
*
* @return resource
* @throws \RuntimeException if the file cannot be opened
*/
function try_fopen($filename, $mode)
{
$ex = null;
set_error_handler(function () use ($filename, $mode, &$ex) {
$ex = new \RuntimeException(sprintf(
'Unable to open %s using mode %s: %s',
$filename,
$mode,
func_get_args()[1]
));
});
$handle = fopen($filename, $mode);
restore_error_handler();
if ($ex) {
/** @var $ex \RuntimeException */
throw $ex;
}
return $handle;
}
/**
* Copy the contents of a stream into a string until the given number of
* bytes have been read.
*
* @param StreamInterface $stream Stream to read
* @param int $maxLen Maximum number of bytes to read. Pass -1
* to read the entire stream.
* @return string
* @throws \RuntimeException on error.
*/
function copy_to_string(StreamInterface $stream, $maxLen = -1)
{
$buffer = '';
if ($maxLen === -1) {
while (!$stream->eof()) {
$buf = $stream->read(1048576);
// Using a loose equality here to match on '' and false.
if ($buf == null) {
break;
}
$buffer .= $buf;
}
return $buffer;
}
$len = 0;
while (!$stream->eof() && $len < $maxLen) {
$buf = $stream->read($maxLen - $len);
// Using a loose equality here to match on '' and false.
if ($buf == null) {
break;
}
$buffer .= $buf;
$len = strlen($buffer);
}
return $buffer;
}
/**
* Copy the contents of a stream into another stream until the given number
* of bytes have been read.
*
* @param StreamInterface $source Stream to read from
* @param StreamInterface $dest Stream to write to
* @param int $maxLen Maximum number of bytes to read. Pass -1
* to read the entire stream.
*
* @throws \RuntimeException on error.
*/
function copy_to_stream(
StreamInterface $source,
StreamInterface $dest,
$maxLen = -1
) {
if ($maxLen === -1) {
while (!$source->eof()) {
if (!$dest->write($source->read(1048576))) {
break;
}
}
return;
}
$bytes = 0;
while (!$source->eof()) {
$buf = $source->read($maxLen - $bytes);
if (!($len = strlen($buf))) {
break;
}
$bytes += $len;
$dest->write($buf);
if ($bytes == $maxLen) {
break;
}
}
}
/**
* Calculate a hash of a Stream
*
* @param StreamInterface $stream Stream to calculate the hash for
* @param string $algo Hash algorithm (e.g. md5, crc32, etc)
* @param bool $rawOutput Whether or not to use raw output
*
* @return string Returns the hash of the stream
* @throws \RuntimeException on error.
*/
function hash(
StreamInterface $stream,
$algo,
$rawOutput = false
) {
$pos = $stream->tell();
if ($pos > 0) {
$stream->rewind();
}
$ctx = hash_init($algo);
while (!$stream->eof()) {
hash_update($ctx, $stream->read(1048576));
}
$out = hash_final($ctx, (bool) $rawOutput);
$stream->seek($pos);
return $out;
}
/**
* Read a line from the stream up to the maximum allowed buffer length
*
* @param StreamInterface $stream Stream to read from
* @param int $maxLength Maximum buffer length
*
* @return string|bool
*/
function readline(StreamInterface $stream, $maxLength = null)
{
$buffer = '';
$size = 0;
while (!$stream->eof()) {
// Using a loose equality here to match on '' and false.
if (null == ($byte = $stream->read(1))) {
return $buffer;
}
$buffer .= $byte;
// Break when a new line is found or the max length - 1 is reached
if ($byte == PHP_EOL || ++$size == $maxLength - 1) {
break;
}
}
return $buffer;
}
/**
* Parses a request message string into a request object.
*
* @param string $message Request message string.
*
* @return Request
*/
function parse_request($message)
{
$data = _parse_message($message);
if (!preg_match('/^[a-zA-Z]+\s+\/.*/', $data['start-line'])) {
throw new \InvalidArgumentException('Invalid request string');
}
$parts = explode(' ', $data['start-line'], 3);
$version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';
return new Request(
$parts[0],
_parse_request_uri($parts[1], $data['headers']),
$data['headers'],
$data['body'],
$version
);
}
/**
* Parses a response message string into a response object.
*
* @param string $message Response message string.
*
* @return Response
*/
function parse_response($message)
{
$data = _parse_message($message);
if (!preg_match('/^HTTP\/.* [0-9]{3} .*/', $data['start-line'])) {
throw new \InvalidArgumentException('Invalid response string');
}
$parts = explode(' ', $data['start-line'], 3);
return new Response(
$parts[1],
$data['headers'],
$data['body'],
explode('/', $parts[0])[1],
isset($parts[2]) ? $parts[2] : null
);
}
/**
* Parse a query string into an associative array.
*
* If multiple values are found for the same key, the value of that key
* value pair will become an array. This function does not parse nested
* PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2 will
* be parsed into ['foo[a]' => '1', 'foo[b]' => '2']).
*
* @param string $str Query string to parse
* @param bool|string $urlEncoding How the query string is encoded
*
* @return array
*/
function parse_query($str, $urlEncoding = true)
{
$result = [];
if ($str === '') {
return $result;
}
if ($urlEncoding === true) {
$decoder = function ($value) {
return rawurldecode(str_replace('+', ' ', $value));
};
} elseif ($urlEncoding == PHP_QUERY_RFC3986) {
$decoder = 'rawurldecode';
} elseif ($urlEncoding == PHP_QUERY_RFC1738) {
$decoder = 'urldecode';
} else {
$decoder = function ($str) { return $str; };
}
foreach (explode('&', $str) as $kvp) {
$parts = explode('=', $kvp, 2);
$key = $decoder($parts[0]);
$value = isset($parts[1]) ? $decoder($parts[1]) : null;
if (!isset($result[$key])) {
$result[$key] = $value;
} else {
if (!is_array($result[$key])) {
$result[$key] = [$result[$key]];
}
$result[$key][] = $value;
}
}
return $result;
}
/**
* Build a query string from an array of key value pairs.
*
* This function can use the return value of parseQuery() to build a query
* string. This function does not modify the provided keys when an array is
* encountered (like http_build_query would).
*
* @param array $params Query string parameters.
* @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
* to encode using RFC3986, or PHP_QUERY_RFC1738
* to encode using RFC1738.
* @return string
*/
function build_query(array $params, $encoding = PHP_QUERY_RFC3986)
{
if (!$params) {
return '';
}
if ($encoding === false) {
$encoder = function ($str) { return $str; };
} elseif ($encoding == PHP_QUERY_RFC3986) {
$encoder = 'rawurlencode';
} elseif ($encoding == PHP_QUERY_RFC1738) {
$encoder = 'urlencode';
} else {
throw new \InvalidArgumentException('Invalid type');
}
$qs = '';
foreach ($params as $k => $v) {
$k = $encoder($k);
if (!is_array($v)) {
$qs .= $k;
if ($v !== null) {
$qs .= '=' . $encoder($v);
}
$qs .= '&';
} else {
foreach ($v as $vv) {
$qs .= $k;
if ($vv !== null) {
$qs .= '=' . $encoder($vv);
}
$qs .= '&';
}
}
}
return $qs ? (string) substr($qs, 0, -1) : '';
}
/**
* Determines the mimetype of a file by looking at its extension.
*
* @param $filename
*
* @return null|string
*/
function mimetype_from_filename($filename)
{
return mimetype_from_extension(pathinfo($filename, PATHINFO_EXTENSION));
}
/**
* Maps a file extensions to a mimetype.
*
* @param $extension string The file extension.
*
* @return string|null
* @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
*/
function mimetype_from_extension($extension)
{
static $mimetypes = [
'7z' => 'application/x-7z-compressed',
'aac' => 'audio/x-aac',
'ai' => 'application/postscript',
'aif' => 'audio/x-aiff',
'asc' => 'text/plain',
'asf' => 'video/x-ms-asf',
'atom' => 'application/atom+xml',
'avi' => 'video/x-msvideo',
'bmp' => 'image/bmp',
'bz2' => 'application/x-bzip2',
'cer' => 'application/pkix-cert',
'crl' => 'application/pkix-crl',
'crt' => 'application/x-x509-ca-cert',
'css' => 'text/css',
'csv' => 'text/csv',
'cu' => 'application/cu-seeme',
'deb' => 'application/x-debian-package',
'doc' => 'application/msword',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'dvi' => 'application/x-dvi',
'eot' => 'application/vnd.ms-fontobject',
'eps' => 'application/postscript',
'epub' => 'application/epub+zip',
'etx' => 'text/x-setext',
'flac' => 'audio/flac',
'flv' => 'video/x-flv',
'gif' => 'image/gif',
'gz' => 'application/gzip',
'htm' => 'text/html',
'html' => 'text/html',
'ico' => 'image/x-icon',
'ics' => 'text/calendar',
'ini' => 'text/plain',
'iso' => 'application/x-iso9660-image',
'jar' => 'application/java-archive',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'js' => 'text/javascript',
'json' => 'application/json',
'latex' => 'application/x-latex',
'log' => 'text/plain',
'm4a' => 'audio/mp4',
'm4v' => 'video/mp4',
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'mov' => 'video/quicktime',
'mp3' => 'audio/mpeg',
'mp4' => 'video/mp4',
'mp4a' => 'audio/mp4',
'mp4v' => 'video/mp4',
'mpe' => 'video/mpeg',
'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg',
'mpg4' => 'video/mp4',
'oga' => 'audio/ogg',
'ogg' => 'audio/ogg',
'ogv' => 'video/ogg',
'ogx' => 'application/ogg',
'pbm' => 'image/x-portable-bitmap',
'pdf' => 'application/pdf',
'pgm' => 'image/x-portable-graymap',
'png' => 'image/png',
'pnm' => 'image/x-portable-anymap',
'ppm' => 'image/x-portable-pixmap',
'ppt' => 'application/vnd.ms-powerpoint',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'ps' => 'application/postscript',
'qt' => 'video/quicktime',
'rar' => 'application/x-rar-compressed',
'ras' => 'image/x-cmu-raster',
'rss' => 'application/rss+xml',
'rtf' => 'application/rtf',
'sgm' => 'text/sgml',
'sgml' => 'text/sgml',
'svg' => 'image/svg+xml',
'swf' => 'application/x-shockwave-flash',
'tar' => 'application/x-tar',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'torrent' => 'application/x-bittorrent',
'ttf' => 'application/x-font-ttf',
'txt' => 'text/plain',
'wav' => 'audio/x-wav',
'webm' => 'video/webm',
'wma' => 'audio/x-ms-wma',
'wmv' => 'video/x-ms-wmv',
'woff' => 'application/x-font-woff',
'wsdl' => 'application/wsdl+xml',
'xbm' => 'image/x-xbitmap',
'xls' => 'application/vnd.ms-excel',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xml' => 'application/xml',
'xpm' => 'image/x-xpixmap',
'xwd' => 'image/x-xwindowdump',
'yaml' => 'text/yaml',
'yml' => 'text/yaml',
'zip' => 'application/zip',
];
$extension = strtolower($extension);
return isset($mimetypes[$extension])
? $mimetypes[$extension]
: null;
}
/**
* Parses an HTTP message into an associative array.
*
* The array contains the "start-line" key containing the start line of
* the message, "headers" key containing an associative array of header
* array values, and a "body" key containing the body of the message.
*
* @param string $message HTTP request or response to parse.
*
* @return array
* @internal
*/
function _parse_message($message)
{
if (!$message) {
throw new \InvalidArgumentException('Invalid message');
}
// Iterate over each line in the message, accounting for line endings
$lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
$result = ['start-line' => array_shift($lines), 'headers' => [], 'body' => ''];
array_shift($lines);
for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {
$line = $lines[$i];
// If two line breaks were encountered, then this is the end of body
if (empty($line)) {
if ($i < $totalLines - 1) {
$result['body'] = implode('', array_slice($lines, $i + 2));
}
break;
}
if (strpos($line, ':')) {
$parts = explode(':', $line, 2);
$key = trim($parts[0]);
$value = isset($parts[1]) ? trim($parts[1]) : '';
$result['headers'][$key][] = $value;
}
}
return $result;
}
/**
* Constructs a URI for an HTTP request message.
*
* @param string $path Path from the start-line
* @param array $headers Array of headers (each value an array).
*
* @return string
* @internal
*/
function _parse_request_uri($path, array $headers)
{
$hostKey = array_filter(array_keys($headers), function ($k) {
return strtolower($k) === 'host';
});
// If no host is found, then a full URI cannot be constructed.
if (!$hostKey) {
return $path;
}
$host = $headers[reset($hostKey)][0];
$scheme = substr($host, -4) === ':443' ? 'https' : 'http';
return $scheme . '://' . $host . '/' . ltrim($path, '/');
}
/** @internal */
function _caseless_remove($keys, array $data)
{
$result = [];
foreach ($keys as &$key) {
$key = strtolower($key);
}
foreach ($data as $k => $v) {
if (!in_array(strtolower($k), $keys)) {
$result[$k] = $v;
}
}
return $result;
}

View File

@ -1,186 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\AppendStream;
use GuzzleHttp\Psr7;
class AppendStreamTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Each stream must be readable
*/
public function testValidatesStreamsAreReadable()
{
$a = new AppendStream();
$s = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isReadable'])
->getMockForAbstractClass();
$s->expects($this->once())
->method('isReadable')
->will($this->returnValue(false));
$a->addStream($s);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage The AppendStream can only seek with SEEK_SET
*/
public function testValidatesSeekType()
{
$a = new AppendStream();
$a->seek(100, SEEK_CUR);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Unable to seek stream 0 of the AppendStream
*/
public function testTriesToRewindOnSeek()
{
$a = new AppendStream();
$s = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isReadable', 'rewind', 'isSeekable'])
->getMockForAbstractClass();
$s->expects($this->once())
->method('isReadable')
->will($this->returnValue(true));
$s->expects($this->once())
->method('isSeekable')
->will($this->returnValue(true));
$s->expects($this->once())
->method('rewind')
->will($this->throwException(new \RuntimeException()));
$a->addStream($s);
$a->seek(10);
}
public function testSeeksToPositionByReading()
{
$a = new AppendStream([
Psr7\stream_for('foo'),
Psr7\stream_for('bar'),
Psr7\stream_for('baz'),
]);
$a->seek(3);
$this->assertEquals(3, $a->tell());
$this->assertEquals('bar', $a->read(3));
$a->seek(6);
$this->assertEquals(6, $a->tell());
$this->assertEquals('baz', $a->read(3));
}
public function testDetachesEachStream()
{
$s1 = Psr7\stream_for('foo');
$s2 = Psr7\stream_for('bar');
$a = new AppendStream([$s1, $s2]);
$this->assertSame('foobar', (string) $a);
$a->detach();
$this->assertSame('', (string) $a);
$this->assertSame(0, $a->getSize());
}
public function testClosesEachStream()
{
$s1 = Psr7\stream_for('foo');
$a = new AppendStream([$s1]);
$a->close();
$this->assertSame('', (string) $a);
}
/**
* @expectedExceptionMessage Cannot write to an AppendStream
* @expectedException \RuntimeException
*/
public function testIsNotWritable()
{
$a = new AppendStream([Psr7\stream_for('foo')]);
$this->assertFalse($a->isWritable());
$this->assertTrue($a->isSeekable());
$this->assertTrue($a->isReadable());
$a->write('foo');
}
public function testDoesNotNeedStreams()
{
$a = new AppendStream();
$this->assertEquals('', (string) $a);
}
public function testCanReadFromMultipleStreams()
{
$a = new AppendStream([
Psr7\stream_for('foo'),
Psr7\stream_for('bar'),
Psr7\stream_for('baz'),
]);
$this->assertFalse($a->eof());
$this->assertSame(0, $a->tell());
$this->assertEquals('foo', $a->read(3));
$this->assertEquals('bar', $a->read(3));
$this->assertEquals('baz', $a->read(3));
$this->assertSame('', $a->read(1));
$this->assertTrue($a->eof());
$this->assertSame(9, $a->tell());
$this->assertEquals('foobarbaz', (string) $a);
}
public function testCanDetermineSizeFromMultipleStreams()
{
$a = new AppendStream([
Psr7\stream_for('foo'),
Psr7\stream_for('bar')
]);
$this->assertEquals(6, $a->getSize());
$s = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isSeekable', 'isReadable'])
->getMockForAbstractClass();
$s->expects($this->once())
->method('isSeekable')
->will($this->returnValue(null));
$s->expects($this->once())
->method('isReadable')
->will($this->returnValue(true));
$a->addStream($s);
$this->assertNull($a->getSize());
}
public function testCatchesExceptionsWhenCastingToString()
{
$s = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isSeekable', 'read', 'isReadable', 'eof'])
->getMockForAbstractClass();
$s->expects($this->once())
->method('isSeekable')
->will($this->returnValue(true));
$s->expects($this->once())
->method('read')
->will($this->throwException(new \RuntimeException('foo')));
$s->expects($this->once())
->method('isReadable')
->will($this->returnValue(true));
$s->expects($this->any())
->method('eof')
->will($this->returnValue(false));
$a = new AppendStream([$s]);
$this->assertFalse($a->eof());
$this->assertSame('', (string) $a);
}
public function testCanDetach()
{
$s = new AppendStream();
$s->detach();
}
public function testReturnsEmptyMetadata()
{
$s = new AppendStream();
$this->assertEquals([], $s->getMetadata());
$this->assertNull($s->getMetadata('foo'));
}
}

View File

@ -1,63 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\BufferStream;
class BufferStreamTest extends \PHPUnit_Framework_TestCase
{
public function testHasMetadata()
{
$b = new BufferStream(10);
$this->assertTrue($b->isReadable());
$this->assertTrue($b->isWritable());
$this->assertFalse($b->isSeekable());
$this->assertEquals(null, $b->getMetadata('foo'));
$this->assertEquals(10, $b->getMetadata('hwm'));
$this->assertEquals([], $b->getMetadata());
}
public function testRemovesReadDataFromBuffer()
{
$b = new BufferStream();
$this->assertEquals(3, $b->write('foo'));
$this->assertEquals(3, $b->getSize());
$this->assertFalse($b->eof());
$this->assertEquals('foo', $b->read(10));
$this->assertTrue($b->eof());
$this->assertEquals('', $b->read(10));
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Cannot determine the position of a BufferStream
*/
public function testCanCastToStringOrGetContents()
{
$b = new BufferStream();
$b->write('foo');
$b->write('baz');
$this->assertEquals('foo', $b->read(3));
$b->write('bar');
$this->assertEquals('bazbar', (string) $b);
$b->tell();
}
public function testDetachClearsBuffer()
{
$b = new BufferStream();
$b->write('foo');
$b->detach();
$this->assertTrue($b->eof());
$this->assertEquals(3, $b->write('abc'));
$this->assertEquals('abc', $b->read(10));
}
public function testExceedingHighwaterMarkReturnsFalseButStillBuffers()
{
$b = new BufferStream(5);
$this->assertEquals(3, $b->write('hi '));
$this->assertFalse($b->write('hello'));
$this->assertEquals('hi hello', (string) $b);
$this->assertEquals(4, $b->write('test'));
}
}

View File

@ -1,137 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\CachingStream;
/**
* @covers GuzzleHttp\Psr7\CachingStream
*/
class CachingStreamTest extends \PHPUnit_Framework_TestCase
{
/** @var CachingStream */
protected $body;
protected $decorated;
public function setUp()
{
$this->decorated = Psr7\stream_for('testing');
$this->body = new CachingStream($this->decorated);
}
public function tearDown()
{
$this->decorated->close();
$this->body->close();
}
public function testUsesRemoteSizeIfPossible()
{
$body = Psr7\stream_for('test');
$caching = new CachingStream($body);
$this->assertEquals(4, $caching->getSize());
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Cannot seek to byte 10
*/
public function testCannotSeekPastWhatHasBeenRead()
{
$this->body->seek(10);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage CachingStream::seek() supports SEEK_SET and SEEK_CUR
*/
public function testCannotUseSeekEnd()
{
$this->body->seek(2, SEEK_END);
}
public function testRewindUsesSeek()
{
$a = Psr7\stream_for('foo');
$d = $this->getMockBuilder('GuzzleHttp\Psr7\CachingStream')
->setMethods(array('seek'))
->setConstructorArgs(array($a))
->getMock();
$d->expects($this->once())
->method('seek')
->with(0)
->will($this->returnValue(true));
$d->seek(0);
}
public function testCanSeekToReadBytes()
{
$this->assertEquals('te', $this->body->read(2));
$this->body->seek(0);
$this->assertEquals('test', $this->body->read(4));
$this->assertEquals(4, $this->body->tell());
$this->body->seek(2);
$this->assertEquals(2, $this->body->tell());
$this->body->seek(2, SEEK_CUR);
$this->assertEquals(4, $this->body->tell());
$this->assertEquals('ing', $this->body->read(3));
}
public function testWritesToBufferStream()
{
$this->body->read(2);
$this->body->write('hi');
$this->body->seek(0);
$this->assertEquals('tehiing', (string) $this->body);
}
public function testSkipsOverwrittenBytes()
{
$decorated = Psr7\stream_for(
implode("\n", array_map(function ($n) {
return str_pad($n, 4, '0', STR_PAD_LEFT);
}, range(0, 25)))
);
$body = new CachingStream($decorated);
$this->assertEquals("0000\n", Psr7\readline($body));
$this->assertEquals("0001\n", Psr7\readline($body));
// Write over part of the body yet to be read, so skip some bytes
$this->assertEquals(5, $body->write("TEST\n"));
$this->assertEquals(5, $this->readAttribute($body, 'skipReadBytes'));
// Read, which skips bytes, then reads
$this->assertEquals("0003\n", Psr7\readline($body));
$this->assertEquals(0, $this->readAttribute($body, 'skipReadBytes'));
$this->assertEquals("0004\n", Psr7\readline($body));
$this->assertEquals("0005\n", Psr7\readline($body));
// Overwrite part of the cached body (so don't skip any bytes)
$body->seek(5);
$this->assertEquals(5, $body->write("ABCD\n"));
$this->assertEquals(0, $this->readAttribute($body, 'skipReadBytes'));
$this->assertEquals("TEST\n", Psr7\readline($body));
$this->assertEquals("0003\n", Psr7\readline($body));
$this->assertEquals("0004\n", Psr7\readline($body));
$this->assertEquals("0005\n", Psr7\readline($body));
$this->assertEquals("0006\n", Psr7\readline($body));
$this->assertEquals(5, $body->write("1234\n"));
$this->assertEquals(5, $this->readAttribute($body, 'skipReadBytes'));
// Seek to 0 and ensure the overwritten bit is replaced
$body->seek(0);
$this->assertEquals("0000\nABCD\nTEST\n0003\n0004\n0005\n0006\n1234\n0008\n0009\n", $body->read(50));
// Ensure that casting it to a string does not include the bit that was overwritten
$this->assertContains("0000\nABCD\nTEST\n0003\n0004\n0005\n0006\n1234\n0008\n0009\n", (string) $body);
}
public function testClosesBothStreams()
{
$s = fopen('php://temp', 'r');
$a = Psr7\stream_for($s);
$d = new CachingStream($a);
$d->close();
$this->assertFalse(is_resource($s));
}
}

View File

@ -1,26 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\BufferStream;
use GuzzleHttp\Psr7\DroppingStream;
class DroppingStreamTest extends \PHPUnit_Framework_TestCase
{
public function testBeginsDroppingWhenSizeExceeded()
{
$stream = new BufferStream();
$drop = new DroppingStream($stream, 5);
$this->assertEquals(3, $drop->write('hel'));
$this->assertEquals(2, $drop->write('lo'));
$this->assertEquals(5, $drop->getSize());
$this->assertEquals('hello', $drop->read(5));
$this->assertEquals(0, $drop->getSize());
$drop->write('12345678910');
$this->assertEquals(5, $stream->getSize());
$this->assertEquals(5, $drop->getSize());
$this->assertEquals('12345', (string) $drop);
$this->assertEquals(0, $drop->getSize());
$drop->write('hello');
$this->assertSame(0, $drop->write('test'));
}
}

View File

@ -1,90 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\FnStream;
/**
* @covers GuzzleHttp\Psr7\FnStream
*/
class FnStreamTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException \BadMethodCallException
* @expectedExceptionMessage seek() is not implemented in the FnStream
*/
public function testThrowsWhenNotImplemented()
{
(new FnStream([]))->seek(1);
}
public function testProxiesToFunction()
{
$s = new FnStream([
'read' => function ($len) {
$this->assertEquals(3, $len);
return 'foo';
}
]);
$this->assertEquals('foo', $s->read(3));
}
public function testCanCloseOnDestruct()
{
$called = false;
$s = new FnStream([
'close' => function () use (&$called) {
$called = true;
}
]);
unset($s);
$this->assertTrue($called);
}
public function testDoesNotRequireClose()
{
$s = new FnStream([]);
unset($s);
}
public function testDecoratesStream()
{
$a = Psr7\stream_for('foo');
$b = FnStream::decorate($a, []);
$this->assertEquals(3, $b->getSize());
$this->assertEquals($b->isWritable(), true);
$this->assertEquals($b->isReadable(), true);
$this->assertEquals($b->isSeekable(), true);
$this->assertEquals($b->read(3), 'foo');
$this->assertEquals($b->tell(), 3);
$this->assertEquals($a->tell(), 3);
$this->assertSame('', $a->read(1));
$this->assertEquals($b->eof(), true);
$this->assertEquals($a->eof(), true);
$b->seek(0);
$this->assertEquals('foo', (string) $b);
$b->seek(0);
$this->assertEquals('foo', $b->getContents());
$this->assertEquals($a->getMetadata(), $b->getMetadata());
$b->seek(0, SEEK_END);
$b->write('bar');
$this->assertEquals('foobar', (string) $b);
$this->assertInternalType('resource', $b->detach());
$b->close();
}
public function testDecoratesWithCustomizations()
{
$called = false;
$a = Psr7\stream_for('foo');
$b = FnStream::decorate($a, [
'read' => function ($len) use (&$called, $a) {
$called = true;
return $a->read($len);
}
]);
$this->assertEquals('foo', $b->read(3));
$this->assertTrue($called);
}
}

View File

@ -1,574 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\FnStream;
use GuzzleHttp\Psr7\NoSeekStream;
class FunctionsTest extends \PHPUnit_Framework_TestCase
{
public function testCopiesToString()
{
$s = Psr7\stream_for('foobaz');
$this->assertEquals('foobaz', Psr7\copy_to_string($s));
$s->seek(0);
$this->assertEquals('foo', Psr7\copy_to_string($s, 3));
$this->assertEquals('baz', Psr7\copy_to_string($s, 3));
$this->assertEquals('', Psr7\copy_to_string($s));
}
public function testCopiesToStringStopsWhenReadFails()
{
$s1 = Psr7\stream_for('foobaz');
$s1 = FnStream::decorate($s1, [
'read' => function () { return ''; }
]);
$result = Psr7\copy_to_string($s1);
$this->assertEquals('', $result);
}
public function testCopiesToStream()
{
$s1 = Psr7\stream_for('foobaz');
$s2 = Psr7\stream_for('');
Psr7\copy_to_stream($s1, $s2);
$this->assertEquals('foobaz', (string) $s2);
$s2 = Psr7\stream_for('');
$s1->seek(0);
Psr7\copy_to_stream($s1, $s2, 3);
$this->assertEquals('foo', (string) $s2);
Psr7\copy_to_stream($s1, $s2, 3);
$this->assertEquals('foobaz', (string) $s2);
}
public function testStopsCopyToStreamWhenWriteFails()
{
$s1 = Psr7\stream_for('foobaz');
$s2 = Psr7\stream_for('');
$s2 = FnStream::decorate($s2, ['write' => function () { return 0; }]);
Psr7\copy_to_stream($s1, $s2);
$this->assertEquals('', (string) $s2);
}
public function testStopsCopyToSteamWhenWriteFailsWithMaxLen()
{
$s1 = Psr7\stream_for('foobaz');
$s2 = Psr7\stream_for('');
$s2 = FnStream::decorate($s2, ['write' => function () { return 0; }]);
Psr7\copy_to_stream($s1, $s2, 10);
$this->assertEquals('', (string) $s2);
}
public function testStopsCopyToSteamWhenReadFailsWithMaxLen()
{
$s1 = Psr7\stream_for('foobaz');
$s1 = FnStream::decorate($s1, ['read' => function () { return ''; }]);
$s2 = Psr7\stream_for('');
Psr7\copy_to_stream($s1, $s2, 10);
$this->assertEquals('', (string) $s2);
}
public function testReadsLines()
{
$s = Psr7\stream_for("foo\nbaz\nbar");
$this->assertEquals("foo\n", Psr7\readline($s));
$this->assertEquals("baz\n", Psr7\readline($s));
$this->assertEquals("bar", Psr7\readline($s));
}
public function testReadsLinesUpToMaxLength()
{
$s = Psr7\stream_for("12345\n");
$this->assertEquals("123", Psr7\readline($s, 4));
$this->assertEquals("45\n", Psr7\readline($s));
}
public function testReadsLineUntilFalseReturnedFromRead()
{
$s = $this->getMockBuilder('GuzzleHttp\Psr7\Stream')
->setMethods(['read', 'eof'])
->disableOriginalConstructor()
->getMock();
$s->expects($this->exactly(2))
->method('read')
->will($this->returnCallback(function () {
static $c = false;
if ($c) {
return false;
}
$c = true;
return 'h';
}));
$s->expects($this->exactly(2))
->method('eof')
->will($this->returnValue(false));
$this->assertEquals("h", Psr7\readline($s));
}
public function testCalculatesHash()
{
$s = Psr7\stream_for('foobazbar');
$this->assertEquals(md5('foobazbar'), Psr7\hash($s, 'md5'));
}
/**
* @expectedException \RuntimeException
*/
public function testCalculatesHashThrowsWhenSeekFails()
{
$s = new NoSeekStream(Psr7\stream_for('foobazbar'));
$s->read(2);
Psr7\hash($s, 'md5');
}
public function testCalculatesHashSeeksToOriginalPosition()
{
$s = Psr7\stream_for('foobazbar');
$s->seek(4);
$this->assertEquals(md5('foobazbar'), Psr7\hash($s, 'md5'));
$this->assertEquals(4, $s->tell());
}
public function testOpensFilesSuccessfully()
{
$r = Psr7\try_fopen(__FILE__, 'r');
$this->assertInternalType('resource', $r);
fclose($r);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Unable to open /path/to/does/not/exist using mode r
*/
public function testThrowsExceptionNotWarning()
{
Psr7\try_fopen('/path/to/does/not/exist', 'r');
}
public function parseQueryProvider()
{
return [
// Does not need to parse when the string is empty
['', []],
// Can parse mult-values items
['q=a&q=b', ['q' => ['a', 'b']]],
// Can parse multi-valued items that use numeric indices
['q[0]=a&q[1]=b', ['q[0]' => 'a', 'q[1]' => 'b']],
// Can parse duplicates and does not include numeric indices
['q[]=a&q[]=b', ['q[]' => ['a', 'b']]],
// Ensures that the value of "q" is an array even though one value
['q[]=a', ['q[]' => 'a']],
// Does not modify "." to "_" like PHP's parse_str()
['q.a=a&q.b=b', ['q.a' => 'a', 'q.b' => 'b']],
// Can decode %20 to " "
['q%20a=a%20b', ['q a' => 'a b']],
// Can parse funky strings with no values by assigning each to null
['q&a', ['q' => null, 'a' => null]],
// Does not strip trailing equal signs
['data=abc=', ['data' => 'abc=']],
// Can store duplicates without affecting other values
['foo=a&foo=b&?µ=c', ['foo' => ['a', 'b'], '?µ' => 'c']],
// Sets value to null when no "=" is present
['foo', ['foo' => null]],
// Preserves "0" keys.
['0', ['0' => null]],
// Sets the value to an empty string when "=" is present
['0=', ['0' => '']],
// Preserves falsey keys
['var=0', ['var' => '0']],
['a[b][c]=1&a[b][c]=2', ['a[b][c]' => ['1', '2']]],
['a[b]=c&a[d]=e', ['a[b]' => 'c', 'a[d]' => 'e']],
// Ensure it doesn't leave things behind with repeated values
// Can parse mult-values items
['q=a&q=b&q=c', ['q' => ['a', 'b', 'c']]],
];
}
/**
* @dataProvider parseQueryProvider
*/
public function testParsesQueries($input, $output)
{
$result = Psr7\parse_query($input);
$this->assertSame($output, $result);
}
public function testDoesNotDecode()
{
$str = 'foo%20=bar';
$data = Psr7\parse_query($str, false);
$this->assertEquals(['foo%20' => 'bar'], $data);
}
/**
* @dataProvider parseQueryProvider
*/
public function testParsesAndBuildsQueries($input, $output)
{
$result = Psr7\parse_query($input, false);
$this->assertSame($input, Psr7\build_query($result, false));
}
public function testEncodesWithRfc1738()
{
$str = Psr7\build_query(['foo bar' => 'baz+'], PHP_QUERY_RFC1738);
$this->assertEquals('foo+bar=baz%2B', $str);
}
public function testEncodesWithRfc3986()
{
$str = Psr7\build_query(['foo bar' => 'baz+'], PHP_QUERY_RFC3986);
$this->assertEquals('foo%20bar=baz%2B', $str);
}
public function testDoesNotEncode()
{
$str = Psr7\build_query(['foo bar' => 'baz+'], false);
$this->assertEquals('foo bar=baz+', $str);
}
public function testCanControlDecodingType()
{
$result = Psr7\parse_query('var=foo+bar', PHP_QUERY_RFC3986);
$this->assertEquals('foo+bar', $result['var']);
$result = Psr7\parse_query('var=foo+bar', PHP_QUERY_RFC1738);
$this->assertEquals('foo bar', $result['var']);
}
public function testParsesRequestMessages()
{
$req = "GET /abc HTTP/1.0\r\nHost: foo.com\r\nFoo: Bar\r\nBaz: Bam\r\nBaz: Qux\r\n\r\nTest";
$request = Psr7\parse_request($req);
$this->assertEquals('GET', $request->getMethod());
$this->assertEquals('/abc', $request->getRequestTarget());
$this->assertEquals('1.0', $request->getProtocolVersion());
$this->assertEquals('foo.com', $request->getHeaderLine('Host'));
$this->assertEquals('Bar', $request->getHeaderLine('Foo'));
$this->assertEquals('Bam, Qux', $request->getHeaderLine('Baz'));
$this->assertEquals('Test', (string) $request->getBody());
$this->assertEquals('http://foo.com/abc', (string) $request->getUri());
}
public function testParsesRequestMessagesWithHttpsScheme()
{
$req = "PUT /abc?baz=bar HTTP/1.1\r\nHost: foo.com:443\r\n\r\n";
$request = Psr7\parse_request($req);
$this->assertEquals('PUT', $request->getMethod());
$this->assertEquals('/abc?baz=bar', $request->getRequestTarget());
$this->assertEquals('1.1', $request->getProtocolVersion());
$this->assertEquals('foo.com:443', $request->getHeaderLine('Host'));
$this->assertEquals('', (string) $request->getBody());
$this->assertEquals('https://foo.com/abc?baz=bar', (string) $request->getUri());
}
public function testParsesRequestMessagesWithUriWhenHostIsNotFirst()
{
$req = "PUT / HTTP/1.1\r\nFoo: Bar\r\nHost: foo.com\r\n\r\n";
$request = Psr7\parse_request($req);
$this->assertEquals('PUT', $request->getMethod());
$this->assertEquals('/', $request->getRequestTarget());
$this->assertEquals('http://foo.com/', (string) $request->getUri());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesRequestMessages()
{
Psr7\parse_request("HTTP/1.1 200 OK\r\n\r\n");
}
public function testParsesResponseMessages()
{
$res = "HTTP/1.0 200 OK\r\nFoo: Bar\r\nBaz: Bam\r\nBaz: Qux\r\n\r\nTest";
$response = Psr7\parse_response($res);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('OK', $response->getReasonPhrase());
$this->assertEquals('1.0', $response->getProtocolVersion());
$this->assertEquals('Bar', $response->getHeaderLine('Foo'));
$this->assertEquals('Bam, Qux', $response->getHeaderLine('Baz'));
$this->assertEquals('Test', (string) $response->getBody());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesResponseMessages()
{
Psr7\parse_response("GET / HTTP/1.1\r\n\r\n");
}
public function testDetermineMimetype()
{
$this->assertNull(Psr7\mimetype_from_extension('not-a-real-extension'));
$this->assertEquals(
'application/json',
Psr7\mimetype_from_extension('json')
);
$this->assertEquals(
'image/jpeg',
Psr7\mimetype_from_filename('/tmp/images/IMG034821.JPEG')
);
}
public function testCreatesUriForValue()
{
$this->assertInstanceOf('GuzzleHttp\Psr7\Uri', Psr7\uri_for('/foo'));
$this->assertInstanceOf(
'GuzzleHttp\Psr7\Uri',
Psr7\uri_for(new Psr7\Uri('/foo'))
);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesUri()
{
Psr7\uri_for([]);
}
public function testKeepsPositionOfResource()
{
$h = fopen(__FILE__, 'r');
fseek($h, 10);
$stream = Psr7\stream_for($h);
$this->assertEquals(10, $stream->tell());
$stream->close();
}
public function testCreatesWithFactory()
{
$stream = Psr7\stream_for('foo');
$this->assertInstanceOf('GuzzleHttp\Psr7\Stream', $stream);
$this->assertEquals('foo', $stream->getContents());
$stream->close();
}
public function testFactoryCreatesFromEmptyString()
{
$s = Psr7\stream_for();
$this->assertInstanceOf('GuzzleHttp\Psr7\Stream', $s);
}
public function testFactoryCreatesFromNull()
{
$s = Psr7\stream_for(null);
$this->assertInstanceOf('GuzzleHttp\Psr7\Stream', $s);
}
public function testFactoryCreatesFromResource()
{
$r = fopen(__FILE__, 'r');
$s = Psr7\stream_for($r);
$this->assertInstanceOf('GuzzleHttp\Psr7\Stream', $s);
$this->assertSame(file_get_contents(__FILE__), (string) $s);
}
public function testFactoryCreatesFromObjectWithToString()
{
$r = new HasToString();
$s = Psr7\stream_for($r);
$this->assertInstanceOf('GuzzleHttp\Psr7\Stream', $s);
$this->assertEquals('foo', (string) $s);
}
public function testCreatePassesThrough()
{
$s = Psr7\stream_for('foo');
$this->assertSame($s, Psr7\stream_for($s));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testThrowsExceptionForUnknown()
{
Psr7\stream_for(new \stdClass());
}
public function testReturnsCustomMetadata()
{
$s = Psr7\stream_for('foo', ['metadata' => ['hwm' => 3]]);
$this->assertEquals(3, $s->getMetadata('hwm'));
$this->assertArrayHasKey('hwm', $s->getMetadata());
}
public function testCanSetSize()
{
$s = Psr7\stream_for('', ['size' => 10]);
$this->assertEquals(10, $s->getSize());
}
public function testCanCreateIteratorBasedStream()
{
$a = new \ArrayIterator(['foo', 'bar', '123']);
$p = Psr7\stream_for($a);
$this->assertInstanceOf('GuzzleHttp\Psr7\PumpStream', $p);
$this->assertEquals('foo', $p->read(3));
$this->assertFalse($p->eof());
$this->assertEquals('b', $p->read(1));
$this->assertEquals('a', $p->read(1));
$this->assertEquals('r12', $p->read(3));
$this->assertFalse($p->eof());
$this->assertEquals('3', $p->getContents());
$this->assertTrue($p->eof());
$this->assertEquals(9, $p->tell());
}
public function testConvertsRequestsToStrings()
{
$request = new Psr7\Request('PUT', 'http://foo.com/hi?123', [
'Baz' => 'bar',
'Qux' => ' ipsum'
], 'hello', '1.0');
$this->assertEquals(
"PUT /hi?123 HTTP/1.0\r\nHost: foo.com\r\nBaz: bar\r\nQux: ipsum\r\n\r\nhello",
Psr7\str($request)
);
}
public function testConvertsResponsesToStrings()
{
$response = new Psr7\Response(200, [
'Baz' => 'bar',
'Qux' => ' ipsum'
], 'hello', '1.0', 'FOO');
$this->assertEquals(
"HTTP/1.0 200 FOO\r\nBaz: bar\r\nQux: ipsum\r\n\r\nhello",
Psr7\str($response)
);
}
public function parseParamsProvider()
{
$res1 = array(
array(
'<http:/.../front.jpeg>',
'rel' => 'front',
'type' => 'image/jpeg',
),
array(
'<http://.../back.jpeg>',
'rel' => 'back',
'type' => 'image/jpeg',
),
);
return array(
array(
'<http:/.../front.jpeg>; rel="front"; type="image/jpeg", <http://.../back.jpeg>; rel=back; type="image/jpeg"',
$res1
),
array(
'<http:/.../front.jpeg>; rel="front"; type="image/jpeg",<http://.../back.jpeg>; rel=back; type="image/jpeg"',
$res1
),
array(
'foo="baz"; bar=123, boo, test="123", foobar="foo;bar"',
array(
array('foo' => 'baz', 'bar' => '123'),
array('boo'),
array('test' => '123'),
array('foobar' => 'foo;bar')
)
),
array(
'<http://.../side.jpeg?test=1>; rel="side"; type="image/jpeg",<http://.../side.jpeg?test=2>; rel=side; type="image/jpeg"',
array(
array('<http://.../side.jpeg?test=1>', 'rel' => 'side', 'type' => 'image/jpeg'),
array('<http://.../side.jpeg?test=2>', 'rel' => 'side', 'type' => 'image/jpeg')
)
),
array(
'',
array()
)
);
}
/**
* @dataProvider parseParamsProvider
*/
public function testParseParams($header, $result)
{
$this->assertEquals($result, Psr7\parse_header($header));
}
public function testParsesArrayHeaders()
{
$header = ['a, b', 'c', 'd, e'];
$this->assertEquals(['a', 'b', 'c', 'd', 'e'], Psr7\normalize_header($header));
}
public function testRewindsBody()
{
$body = Psr7\stream_for('abc');
$res = new Psr7\Response(200, [], $body);
Psr7\rewind_body($res);
$this->assertEquals(0, $body->tell());
$body->rewind(1);
Psr7\rewind_body($res);
$this->assertEquals(0, $body->tell());
}
/**
* @expectedException \RuntimeException
*/
public function testThrowsWhenBodyCannotBeRewound()
{
$body = Psr7\stream_for('abc');
$body->read(1);
$body = FnStream::decorate($body, [
'rewind' => function () { throw new \RuntimeException('a'); }
]);
$res = new Psr7\Response(200, [], $body);
Psr7\rewind_body($res);
}
public function testCanModifyRequestWithUri()
{
$r1 = new Psr7\Request('GET', 'http://foo.com');
$r2 = Psr7\modify_request($r1, [
'uri' => new Psr7\Uri('http://www.foo.com')
]);
$this->assertEquals('http://www.foo.com', (string) $r2->getUri());
$this->assertEquals('www.foo.com', (string) $r2->getHeaderLine('host'));
}
public function testCanModifyRequestWithCaseInsensitiveHeader()
{
$r1 = new Psr7\Request('GET', 'http://foo.com', ['User-Agent' => 'foo']);
$r2 = Psr7\modify_request($r1, ['set_headers' => ['User-agent' => 'bar']]);
$this->assertEquals('bar', $r2->getHeaderLine('User-Agent'));
$this->assertEquals('bar', $r2->getHeaderLine('User-agent'));
}
public function testReturnsAsIsWhenNoChanges()
{
$request = new Psr7\Request('GET', 'http://foo.com');
$this->assertSame($request, Psr7\modify_request($request, []));
}
public function testReturnsUriAsIsWhenNoChanges()
{
$r1 = new Psr7\Request('GET', 'http://foo.com');
$r2 = Psr7\modify_request($r1, ['set_headers' => ['foo' => 'bar']]);
$this->assertNotSame($r1, $r2);
$this->assertEquals('bar', $r2->getHeaderLine('foo'));
}
public function testRemovesHeadersFromMessage()
{
$r1 = new Psr7\Request('GET', 'http://foo.com', ['foo' => 'bar']);
$r2 = Psr7\modify_request($r1, ['remove_headers' => ['foo']]);
$this->assertNotSame($r1, $r2);
$this->assertFalse($r2->hasHeader('foo'));
}
public function testAddsQueryToUri()
{
$r1 = new Psr7\Request('GET', 'http://foo.com');
$r2 = Psr7\modify_request($r1, ['query' => 'foo=bar']);
$this->assertNotSame($r1, $r2);
$this->assertEquals('foo=bar', $r2->getUri()->getQuery());
}
}

View File

@ -1,16 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\InflateStream;
class InflateStreamtest extends \PHPUnit_Framework_TestCase
{
public function testInflatesStreams()
{
$content = gzencode('test');
$a = Psr7\stream_for($content);
$b = new InflateStream($a);
$this->assertEquals('test', (string) $b);
}
}

View File

@ -1,64 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\LazyOpenStream;
class LazyOpenStreamTest extends \PHPUnit_Framework_TestCase
{
private $fname;
public function setup()
{
$this->fname = tempnam('/tmp', 'tfile');
if (file_exists($this->fname)) {
unlink($this->fname);
}
}
public function tearDown()
{
if (file_exists($this->fname)) {
unlink($this->fname);
}
}
public function testOpensLazily()
{
$l = new LazyOpenStream($this->fname, 'w+');
$l->write('foo');
$this->assertInternalType('array', $l->getMetadata());
$this->assertFileExists($this->fname);
$this->assertEquals('foo', file_get_contents($this->fname));
$this->assertEquals('foo', (string) $l);
}
public function testProxiesToFile()
{
file_put_contents($this->fname, 'foo');
$l = new LazyOpenStream($this->fname, 'r');
$this->assertEquals('foo', $l->read(4));
$this->assertTrue($l->eof());
$this->assertEquals(3, $l->tell());
$this->assertTrue($l->isReadable());
$this->assertTrue($l->isSeekable());
$this->assertFalse($l->isWritable());
$l->seek(1);
$this->assertEquals('oo', $l->getContents());
$this->assertEquals('foo', (string) $l);
$this->assertEquals(3, $l->getSize());
$this->assertInternalType('array', $l->getMetadata());
$l->close();
}
public function testDetachesUnderlyingStream()
{
file_put_contents($this->fname, 'foo');
$l = new LazyOpenStream($this->fname, 'r');
$r = $l->detach();
$this->assertInternalType('resource', $r);
fseek($r, 0);
$this->assertEquals('foo', stream_get_contents($r));
fclose($r);
}
}

View File

@ -1,166 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\FnStream;
use GuzzleHttp\Psr7\Stream;
use GuzzleHttp\Psr7\LimitStream;
use GuzzleHttp\Psr7\NoSeekStream;
/**
* @covers GuzzleHttp\Psr7\LimitStream
*/
class LimitStreamTest extends \PHPUnit_Framework_TestCase
{
/** @var LimitStream */
protected $body;
/** @var Stream */
protected $decorated;
public function setUp()
{
$this->decorated = Psr7\stream_for(fopen(__FILE__, 'r'));
$this->body = new LimitStream($this->decorated, 10, 3);
}
public function testReturnsSubset()
{
$body = new LimitStream(Psr7\stream_for('foo'), -1, 1);
$this->assertEquals('oo', (string) $body);
$this->assertTrue($body->eof());
$body->seek(0);
$this->assertFalse($body->eof());
$this->assertEquals('oo', $body->read(100));
$this->assertSame('', $body->read(1));
$this->assertTrue($body->eof());
}
public function testReturnsSubsetWhenCastToString()
{
$body = Psr7\stream_for('foo_baz_bar');
$limited = new LimitStream($body, 3, 4);
$this->assertEquals('baz', (string) $limited);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Unable to seek to stream position 10 with whence 0
*/
public function testEnsuresPositionCanBeekSeekedTo()
{
new LimitStream(Psr7\stream_for(''), 0, 10);
}
public function testReturnsSubsetOfEmptyBodyWhenCastToString()
{
$body = Psr7\stream_for('01234567891234');
$limited = new LimitStream($body, 0, 10);
$this->assertEquals('', (string) $limited);
}
public function testReturnsSpecificSubsetOBodyWhenCastToString()
{
$body = Psr7\stream_for('0123456789abcdef');
$limited = new LimitStream($body, 3, 10);
$this->assertEquals('abc', (string) $limited);
}
public function testSeeksWhenConstructed()
{
$this->assertEquals(0, $this->body->tell());
$this->assertEquals(3, $this->decorated->tell());
}
public function testAllowsBoundedSeek()
{
$this->body->seek(100);
$this->assertEquals(10, $this->body->tell());
$this->assertEquals(13, $this->decorated->tell());
$this->body->seek(0);
$this->assertEquals(0, $this->body->tell());
$this->assertEquals(3, $this->decorated->tell());
try {
$this->body->seek(-10);
$this->fail();
} catch (\RuntimeException $e) {}
$this->assertEquals(0, $this->body->tell());
$this->assertEquals(3, $this->decorated->tell());
$this->body->seek(5);
$this->assertEquals(5, $this->body->tell());
$this->assertEquals(8, $this->decorated->tell());
// Fail
try {
$this->body->seek(1000, SEEK_END);
$this->fail();
} catch (\RuntimeException $e) {}
}
public function testReadsOnlySubsetOfData()
{
$data = $this->body->read(100);
$this->assertEquals(10, strlen($data));
$this->assertSame('', $this->body->read(1000));
$this->body->setOffset(10);
$newData = $this->body->read(100);
$this->assertEquals(10, strlen($newData));
$this->assertNotSame($data, $newData);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Could not seek to stream offset 2
*/
public function testThrowsWhenCurrentGreaterThanOffsetSeek()
{
$a = Psr7\stream_for('foo_bar');
$b = new NoSeekStream($a);
$c = new LimitStream($b);
$a->getContents();
$c->setOffset(2);
}
public function testCanGetContentsWithoutSeeking()
{
$a = Psr7\stream_for('foo_bar');
$b = new NoSeekStream($a);
$c = new LimitStream($b);
$this->assertEquals('foo_bar', $c->getContents());
}
public function testClaimsConsumedWhenReadLimitIsReached()
{
$this->assertFalse($this->body->eof());
$this->body->read(1000);
$this->assertTrue($this->body->eof());
}
public function testContentLengthIsBounded()
{
$this->assertEquals(10, $this->body->getSize());
}
public function testGetContentsIsBasedOnSubset()
{
$body = new LimitStream(Psr7\stream_for('foobazbar'), 3, 3);
$this->assertEquals('baz', $body->getContents());
}
public function testReturnsNullIfSizeCannotBeDetermined()
{
$a = new FnStream([
'getSize' => function () { return null; },
'tell' => function () { return 0; },
]);
$b = new LimitStream($a);
$this->assertNull($b->getSize());
}
public function testLengthLessOffsetWhenNoLimitSize()
{
$a = Psr7\stream_for('foo_bar');
$b = new LimitStream($a, -1, 4);
$this->assertEquals(3, $b->getSize());
}
}

View File

@ -1,214 +0,0 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\MultipartStream;
class MultipartStreamTest extends \PHPUnit_Framework_TestCase
{
public function testCreatesDefaultBoundary()
{
$b = new MultipartStream();
$this->assertNotEmpty($b->getBoundary());
}
public function testCanProvideBoundary()
{
$b = new MultipartStream([], 'foo');
$this->assertEquals('foo', $b->getBoundary());
}
public function testIsNotWritable()
{
$b = new MultipartStream();
$this->assertFalse($b->isWritable());
}
public function testCanCreateEmptyStream()
{
$b = new MultipartStream();
$boundary = $b->getBoundary();
$this->assertSame("--{$boundary}--\r\n", $b->getContents());
$this->assertSame(strlen($boundary) + 6, $b->getSize());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesFilesArrayElement()
{
new MultipartStream([['foo' => 'bar']]);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testEnsuresFileHasName()
{
new MultipartStream([['contents' => 'bar']]);
}
public function testSerializesFields()
{
$b = new MultipartStream([
[
'name' => 'foo',
'contents' => 'bar'
],
[
'name' => 'baz',
'contents' => 'bam'
]
], 'boundary');
$this->assertEquals(
"--boundary\r\nContent-Disposition: form-data; name=\"foo\"\r\nContent-Length: 3\r\n\r\n"
. "bar\r\n--boundary\r\nContent-Disposition: form-data; name=\"baz\"\r\nContent-Length: 3"
. "\r\n\r\nbam\r\n--boundary--\r\n", (string) $b);
}
public function testSerializesFiles()
{
$f1 = Psr7\FnStream::decorate(Psr7\stream_for('foo'), [
'getMetadata' => function () {
return '/foo/bar.txt';
}
]);
$f2 = Psr7\FnStream::decorate(Psr7\stream_for('baz'), [
'getMetadata' => function () {
return '/foo/baz.jpg';
}
]);
$f3 = Psr7\FnStream::decorate(Psr7\stream_for('bar'), [
'getMetadata' => function () {
return '/foo/bar.gif';
}
]);
$b = new MultipartStream([
[
'name' => 'foo',
'contents' => $f1
],
[
'name' => 'qux',
'contents' => $f2
],
[
'name' => 'qux',
'contents' => $f3
],
], 'boundary');
$expected = <<<EOT
--boundary
Content-Disposition: form-data; name="foo"; filename="bar.txt"
Content-Length: 3
Content-Type: text/plain
foo
--boundary
Content-Disposition: form-data; name="qux"; filename="baz.jpg"
Content-Length: 3
Content-Type: image/jpeg
baz
--boundary
Content-Disposition: form-data; name="qux"; filename="bar.gif"
Content-Length: 3
Content-Type: image/gif
bar
--boundary--
EOT;
$this->assertEquals($expected, str_replace("\r", '', $b));
}
public function testSerializesFilesWithCustomHeaders()
{
$f1 = Psr7\FnStream::decorate(Psr7\stream_for('foo'), [
'getMetadata' => function () {
return '/foo/bar.txt';
}
]);
$b = new MultipartStream([
[
'name' => 'foo',
'contents' => $f1,
'headers' => [
'x-foo' => 'bar',
'content-disposition' => 'custom'
]
]
], 'boundary');
$expected = <<<EOT
--boundary
x-foo: bar
content-disposition: custom
Content-Length: 3
Content-Type: text/plain
foo
--boundary--
EOT;
$this->assertEquals($expected, str_replace("\r", '', $b));
}
public function testSerializesFilesWithCustomHeadersAndMultipleValues()
{
$f1 = Psr7\FnStream::decorate(Psr7\stream_for('foo'), [
'getMetadata' => function () {
return '/foo/bar.txt';
}
]);
$f2 = Psr7\FnStream::decorate(Psr7\stream_for('baz'), [
'getMetadata' => function () {
return '/foo/baz.jpg';
}
]);
$b = new MultipartStream([
[
'name' => 'foo',
'contents' => $f1,
'headers' => [
'x-foo' => 'bar',
'content-disposition' => 'custom'
]
],
[
'name' => 'foo',
'contents' => $f2,
'headers' => ['cOntenT-Type' => 'custom'],
]
], 'boundary');
$expected = <<<EOT
--boundary
x-foo: bar
content-disposition: custom
Content-Length: 3
Content-Type: text/plain
foo
--boundary
cOntenT-Type: custom
Content-Disposition: form-data; name="foo"; filename="baz.jpg"
Content-Length: 3
baz
--boundary--
EOT;
$this->assertEquals($expected, str_replace("\r", '', $b));
}
}

View File

@ -1,40 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\NoSeekStream;
/**
* @covers GuzzleHttp\Psr7\NoSeekStream
* @covers GuzzleHttp\Psr7\StreamDecoratorTrait
*/
class NoSeekStreamTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Cannot seek a NoSeekStream
*/
public function testCannotSeek()
{
$s = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isSeekable', 'seek'])
->getMockForAbstractClass();
$s->expects($this->never())->method('seek');
$s->expects($this->never())->method('isSeekable');
$wrapped = new NoSeekStream($s);
$this->assertFalse($wrapped->isSeekable());
$wrapped->seek(2);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Cannot write to a non-writable stream
*/
public function testHandlesClose()
{
$s = Psr7\stream_for('foo');
$wrapped = new NoSeekStream($s);
$wrapped->close();
$wrapped->write('foo');
}
}

View File

@ -1,72 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\LimitStream;
use GuzzleHttp\Psr7\PumpStream;
use GuzzleHttp\Psr7;
class PumpStreamTest extends \PHPUnit_Framework_TestCase
{
public function testHasMetadataAndSize()
{
$p = new PumpStream(function () {}, [
'metadata' => ['foo' => 'bar'],
'size' => 100
]);
$this->assertEquals('bar', $p->getMetadata('foo'));
$this->assertEquals(['foo' => 'bar'], $p->getMetadata());
$this->assertEquals(100, $p->getSize());
}
public function testCanReadFromCallable()
{
$p = Psr7\stream_for(function ($size) {
return 'a';
});
$this->assertEquals('a', $p->read(1));
$this->assertEquals(1, $p->tell());
$this->assertEquals('aaaaa', $p->read(5));
$this->assertEquals(6, $p->tell());
}
public function testStoresExcessDataInBuffer()
{
$called = [];
$p = Psr7\stream_for(function ($size) use (&$called) {
$called[] = $size;
return 'abcdef';
});
$this->assertEquals('a', $p->read(1));
$this->assertEquals('b', $p->read(1));
$this->assertEquals('cdef', $p->read(4));
$this->assertEquals('abcdefabc', $p->read(9));
$this->assertEquals([1, 9, 3], $called);
}
public function testInifiniteStreamWrappedInLimitStream()
{
$p = Psr7\stream_for(function () { return 'a'; });
$s = new LimitStream($p, 5);
$this->assertEquals('aaaaa', (string) $s);
}
public function testDescribesCapabilities()
{
$p = Psr7\stream_for(function () {});
$this->assertTrue($p->isReadable());
$this->assertFalse($p->isSeekable());
$this->assertFalse($p->isWritable());
$this->assertNull($p->getSize());
$this->assertEquals('', $p->getContents());
$this->assertEquals('', (string) $p);
$p->close();
$this->assertEquals('', $p->read(10));
$this->assertTrue($p->eof());
try {
$this->assertFalse($p->write('aa'));
$this->fail();
} catch (\RuntimeException $e) {}
}
}

View File

@ -1,157 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Uri;
/**
* @covers GuzzleHttp\Psr7\Request
*/
class RequestTest extends \PHPUnit_Framework_TestCase
{
public function testRequestUriMayBeString()
{
$r = new Request('GET', '/');
$this->assertEquals('/', (string) $r->getUri());
}
public function testRequestUriMayBeUri()
{
$uri = new Uri('/');
$r = new Request('GET', $uri);
$this->assertSame($uri, $r->getUri());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidateRequestUri()
{
new Request('GET', true);
}
public function testCanConstructWithBody()
{
$r = new Request('GET', '/', [], 'baz');
$this->assertEquals('baz', (string) $r->getBody());
}
public function testCapitalizesMethod()
{
$r = new Request('get', '/');
$this->assertEquals('GET', $r->getMethod());
}
public function testCapitalizesWithMethod()
{
$r = new Request('GET', '/');
$this->assertEquals('PUT', $r->withMethod('put')->getMethod());
}
public function testWithUri()
{
$r1 = new Request('GET', '/');
$u1 = $r1->getUri();
$u2 = new Uri('http://www.example.com');
$r2 = $r1->withUri($u2);
$this->assertNotSame($r1, $r2);
$this->assertSame($u2, $r2->getUri());
$this->assertSame($u1, $r1->getUri());
}
public function testSameInstanceWhenSameUri()
{
$r1 = new Request('GET', 'http://foo.com');
$r2 = $r1->withUri($r1->getUri());
$this->assertSame($r1, $r2);
}
public function testWithRequestTarget()
{
$r1 = new Request('GET', '/');
$r2 = $r1->withRequestTarget('*');
$this->assertEquals('*', $r2->getRequestTarget());
$this->assertEquals('/', $r1->getRequestTarget());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testRequestTargetDoesNotAllowSpaces()
{
$r1 = new Request('GET', '/');
$r1->withRequestTarget('/foo bar');
}
public function testRequestTargetDefaultsToSlash()
{
$r1 = new Request('GET', '');
$this->assertEquals('/', $r1->getRequestTarget());
$r2 = new Request('GET', '*');
$this->assertEquals('*', $r2->getRequestTarget());
$r3 = new Request('GET', 'http://foo.com/bar baz/');
$this->assertEquals('/bar%20baz/', $r3->getRequestTarget());
}
public function testBuildsRequestTarget()
{
$r1 = new Request('GET', 'http://foo.com/baz?bar=bam');
$this->assertEquals('/baz?bar=bam', $r1->getRequestTarget());
}
public function testHostIsAddedFirst()
{
$r = new Request('GET', 'http://foo.com/baz?bar=bam', ['Foo' => 'Bar']);
$this->assertEquals([
'Host' => ['foo.com'],
'Foo' => ['Bar']
], $r->getHeaders());
}
public function testCanGetHeaderAsCsv()
{
$r = new Request('GET', 'http://foo.com/baz?bar=bam', [
'Foo' => ['a', 'b', 'c']
]);
$this->assertEquals('a, b, c', $r->getHeaderLine('Foo'));
$this->assertEquals('', $r->getHeaderLine('Bar'));
}
public function testHostIsNotOverwrittenWhenPreservingHost()
{
$r = new Request('GET', 'http://foo.com/baz?bar=bam', ['Host' => 'a.com']);
$this->assertEquals(['Host' => ['a.com']], $r->getHeaders());
$r2 = $r->withUri(new Uri('http://www.foo.com/bar'), true);
$this->assertEquals('a.com', $r2->getHeaderLine('Host'));
}
public function testOverridesHostWithUri()
{
$r = new Request('GET', 'http://foo.com/baz?bar=bam');
$this->assertEquals(['Host' => ['foo.com']], $r->getHeaders());
$r2 = $r->withUri(new Uri('http://www.baz.com/bar'));
$this->assertEquals('www.baz.com', $r2->getHeaderLine('Host'));
}
public function testAggregatesHeaders()
{
$r = new Request('GET', 'http://foo.com', [
'ZOO' => 'zoobar',
'zoo' => ['foobar', 'zoobar']
]);
$this->assertEquals('zoobar, foobar, zoobar', $r->getHeaderLine('zoo'));
}
public function testAddsPortToHeader()
{
$r = new Request('GET', 'http://foo.com:8124/bar');
$this->assertEquals('foo.com:8124', $r->getHeaderLine('host'));
}
public function testAddsPortToHeaderAndReplacePreviousPort()
{
$r = new Request('GET', 'http://foo.com:8124/bar');
$r = $r->withUri(new Uri('http://foo.com:8125/bar'));
$this->assertEquals('foo.com:8125', $r->getHeaderLine('host'));
}
}

View File

@ -1,139 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7;
/**
* @covers GuzzleHttp\Psr7\MessageTrait
* @covers GuzzleHttp\Psr7\Response
*/
class ResponseTest extends \PHPUnit_Framework_TestCase
{
public function testAddsDefaultReason()
{
$r = new Response('200');
$this->assertSame(200, $r->getStatusCode());
$this->assertEquals('OK', $r->getReasonPhrase());
}
public function testCanGiveCustomReason()
{
$r = new Response(200, [], null, '1.1', 'bar');
$this->assertEquals('bar', $r->getReasonPhrase());
}
public function testCanGiveCustomProtocolVersion()
{
$r = new Response(200, [], null, '1000');
$this->assertEquals('1000', $r->getProtocolVersion());
}
public function testCanCreateNewResponseWithStatusAndNoReason()
{
$r = new Response(200);
$r2 = $r->withStatus(201);
$this->assertEquals(200, $r->getStatusCode());
$this->assertEquals('OK', $r->getReasonPhrase());
$this->assertEquals(201, $r2->getStatusCode());
$this->assertEquals('Created', $r2->getReasonPhrase());
}
public function testCanCreateNewResponseWithStatusAndReason()
{
$r = new Response(200);
$r2 = $r->withStatus(201, 'Foo');
$this->assertEquals(200, $r->getStatusCode());
$this->assertEquals('OK', $r->getReasonPhrase());
$this->assertEquals(201, $r2->getStatusCode());
$this->assertEquals('Foo', $r2->getReasonPhrase());
}
public function testCreatesResponseWithAddedHeaderArray()
{
$r = new Response();
$r2 = $r->withAddedHeader('foo', ['baz', 'bar']);
$this->assertFalse($r->hasHeader('foo'));
$this->assertEquals('baz, bar', $r2->getHeaderLine('foo'));
}
public function testReturnsIdentityWhenRemovingMissingHeader()
{
$r = new Response();
$this->assertSame($r, $r->withoutHeader('foo'));
}
public function testAlwaysReturnsBody()
{
$r = new Response();
$this->assertInstanceOf('Psr\Http\Message\StreamInterface', $r->getBody());
}
public function testCanSetHeaderAsArray()
{
$r = new Response(200, [
'foo' => ['baz ', ' bar ']
]);
$this->assertEquals('baz, bar', $r->getHeaderLine('foo'));
$this->assertEquals(['baz', 'bar'], $r->getHeader('foo'));
}
public function testSameInstanceWhenSameBody()
{
$r = new Response(200, [], 'foo');
$b = $r->getBody();
$this->assertSame($r, $r->withBody($b));
}
public function testNewInstanceWhenNewBody()
{
$r = new Response(200, [], 'foo');
$b2 = Psr7\stream_for('abc');
$this->assertNotSame($r, $r->withBody($b2));
}
public function testSameInstanceWhenSameProtocol()
{
$r = new Response(200);
$this->assertSame($r, $r->withProtocolVersion('1.1'));
}
public function testNewInstanceWhenNewProtocol()
{
$r = new Response(200);
$this->assertNotSame($r, $r->withProtocolVersion('1.0'));
}
public function testNewInstanceWhenRemovingHeader()
{
$r = new Response(200, ['Foo' => 'Bar']);
$r2 = $r->withoutHeader('Foo');
$this->assertNotSame($r, $r2);
$this->assertFalse($r2->hasHeader('foo'));
}
public function testNewInstanceWhenAddingHeader()
{
$r = new Response(200, ['Foo' => 'Bar']);
$r2 = $r->withAddedHeader('Foo', 'Baz');
$this->assertNotSame($r, $r2);
$this->assertEquals('Bar, Baz', $r2->getHeaderLine('foo'));
}
public function testNewInstanceWhenAddingHeaderThatWasNotThereBefore()
{
$r = new Response(200, ['Foo' => 'Bar']);
$r2 = $r->withAddedHeader('Baz', 'Bam');
$this->assertNotSame($r, $r2);
$this->assertEquals('Bam', $r2->getHeaderLine('Baz'));
$this->assertEquals('Bar', $r2->getHeaderLine('Foo'));
}
public function testRemovesPreviouslyAddedHeaderOfDifferentCase()
{
$r = new Response(200, ['Foo' => 'Bar']);
$r2 = $r->withHeader('foo', 'Bam');
$this->assertNotSame($r, $r2);
$this->assertEquals('Bam', $r2->getHeaderLine('Foo'));
}
}

View File

@ -1,137 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use Psr\Http\Message\StreamInterface;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\StreamDecoratorTrait;
class Str implements StreamInterface
{
use StreamDecoratorTrait;
}
/**
* @covers GuzzleHttp\Psr7\StreamDecoratorTrait
*/
class StreamDecoratorTraitTest extends \PHPUnit_Framework_TestCase
{
private $a;
private $b;
private $c;
public function setUp()
{
$this->c = fopen('php://temp', 'r+');
fwrite($this->c, 'foo');
fseek($this->c, 0);
$this->a = Psr7\stream_for($this->c);
$this->b = new Str($this->a);
}
public function testCatchesExceptionsWhenCastingToString()
{
$s = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['read'])
->getMockForAbstractClass();
$s->expects($this->once())
->method('read')
->will($this->throwException(new \Exception('foo')));
$msg = '';
set_error_handler(function ($errNo, $str) use (&$msg) { $msg = $str; });
echo new Str($s);
restore_error_handler();
$this->assertContains('foo', $msg);
}
public function testToString()
{
$this->assertEquals('foo', (string) $this->b);
}
public function testHasSize()
{
$this->assertEquals(3, $this->b->getSize());
}
public function testReads()
{
$this->assertEquals('foo', $this->b->read(10));
}
public function testCheckMethods()
{
$this->assertEquals($this->a->isReadable(), $this->b->isReadable());
$this->assertEquals($this->a->isWritable(), $this->b->isWritable());
$this->assertEquals($this->a->isSeekable(), $this->b->isSeekable());
}
public function testSeeksAndTells()
{
$this->b->seek(1);
$this->assertEquals(1, $this->a->tell());
$this->assertEquals(1, $this->b->tell());
$this->b->seek(0);
$this->assertEquals(0, $this->a->tell());
$this->assertEquals(0, $this->b->tell());
$this->b->seek(0, SEEK_END);
$this->assertEquals(3, $this->a->tell());
$this->assertEquals(3, $this->b->tell());
}
public function testGetsContents()
{
$this->assertEquals('foo', $this->b->getContents());
$this->assertEquals('', $this->b->getContents());
$this->b->seek(1);
$this->assertEquals('oo', $this->b->getContents(1));
}
public function testCloses()
{
$this->b->close();
$this->assertFalse(is_resource($this->c));
}
public function testDetaches()
{
$this->b->detach();
$this->assertFalse($this->b->isReadable());
}
public function testWrapsMetadata()
{
$this->assertSame($this->b->getMetadata(), $this->a->getMetadata());
$this->assertSame($this->b->getMetadata('uri'), $this->a->getMetadata('uri'));
}
public function testWrapsWrites()
{
$this->b->seek(0, SEEK_END);
$this->b->write('foo');
$this->assertEquals('foofoo', (string) $this->a);
}
/**
* @expectedException \UnexpectedValueException
*/
public function testThrowsWithInvalidGetter()
{
$this->b->foo;
}
/**
* @expectedException \BadMethodCallException
*/
public function testThrowsWhenGetterNotImplemented()
{
$s = new BadStream();
$s->stream;
}
}
class BadStream
{
use StreamDecoratorTrait;
public function __construct() {}
}

View File

@ -1,161 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\NoSeekStream;
use GuzzleHttp\Psr7\Stream;
/**
* @covers GuzzleHttp\Psr7\Stream
*/
class StreamTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException \InvalidArgumentException
*/
public function testConstructorThrowsExceptionOnInvalidArgument()
{
new Stream(true);
}
public function testConstructorInitializesProperties()
{
$handle = fopen('php://temp', 'r+');
fwrite($handle, 'data');
$stream = new Stream($handle);
$this->assertTrue($stream->isReadable());
$this->assertTrue($stream->isWritable());
$this->assertTrue($stream->isSeekable());
$this->assertEquals('php://temp', $stream->getMetadata('uri'));
$this->assertInternalType('array', $stream->getMetadata());
$this->assertEquals(4, $stream->getSize());
$this->assertFalse($stream->eof());
$stream->close();
}
public function testStreamClosesHandleOnDestruct()
{
$handle = fopen('php://temp', 'r');
$stream = new Stream($handle);
unset($stream);
$this->assertFalse(is_resource($handle));
}
public function testConvertsToString()
{
$handle = fopen('php://temp', 'w+');
fwrite($handle, 'data');
$stream = new Stream($handle);
$this->assertEquals('data', (string) $stream);
$this->assertEquals('data', (string) $stream);
$stream->close();
}
public function testGetsContents()
{
$handle = fopen('php://temp', 'w+');
fwrite($handle, 'data');
$stream = new Stream($handle);
$this->assertEquals('', $stream->getContents());
$stream->seek(0);
$this->assertEquals('data', $stream->getContents());
$this->assertEquals('', $stream->getContents());
}
public function testChecksEof()
{
$handle = fopen('php://temp', 'w+');
fwrite($handle, 'data');
$stream = new Stream($handle);
$this->assertFalse($stream->eof());
$stream->read(4);
$this->assertTrue($stream->eof());
$stream->close();
}
public function testGetSize()
{
$size = filesize(__FILE__);
$handle = fopen(__FILE__, 'r');
$stream = new Stream($handle);
$this->assertEquals($size, $stream->getSize());
// Load from cache
$this->assertEquals($size, $stream->getSize());
$stream->close();
}
public function testEnsuresSizeIsConsistent()
{
$h = fopen('php://temp', 'w+');
$this->assertEquals(3, fwrite($h, 'foo'));
$stream = new Stream($h);
$this->assertEquals(3, $stream->getSize());
$this->assertEquals(4, $stream->write('test'));
$this->assertEquals(7, $stream->getSize());
$this->assertEquals(7, $stream->getSize());
$stream->close();
}
public function testProvidesStreamPosition()
{
$handle = fopen('php://temp', 'w+');
$stream = new Stream($handle);
$this->assertEquals(0, $stream->tell());
$stream->write('foo');
$this->assertEquals(3, $stream->tell());
$stream->seek(1);
$this->assertEquals(1, $stream->tell());
$this->assertSame(ftell($handle), $stream->tell());
$stream->close();
}
public function testCanDetachStream()
{
$r = fopen('php://temp', 'w+');
$stream = new Stream($r);
$stream->write('foo');
$this->assertTrue($stream->isReadable());
$this->assertSame($r, $stream->detach());
$stream->detach();
$this->assertFalse($stream->isReadable());
$this->assertFalse($stream->isWritable());
$this->assertFalse($stream->isSeekable());
$throws = function (callable $fn) use ($stream) {
try {
$fn($stream);
$this->fail();
} catch (\Exception $e) {}
};
$throws(function ($stream) { $stream->read(10); });
$throws(function ($stream) { $stream->write('bar'); });
$throws(function ($stream) { $stream->seek(10); });
$throws(function ($stream) { $stream->tell(); });
$throws(function ($stream) { $stream->eof(); });
$throws(function ($stream) { $stream->getSize(); });
$throws(function ($stream) { $stream->getContents(); });
$this->assertSame('', (string) $stream);
$stream->close();
}
public function testCloseClearProperties()
{
$handle = fopen('php://temp', 'r+');
$stream = new Stream($handle);
$stream->close();
$this->assertFalse($stream->isSeekable());
$this->assertFalse($stream->isReadable());
$this->assertFalse($stream->isWritable());
$this->assertNull($stream->getSize());
$this->assertEmpty($stream->getMetadata());
}
public function testDoesNotThrowInToString()
{
$s = \GuzzleHttp\Psr7\stream_for('foo');
$s = new NoSeekStream($s);
$this->assertEquals('foo', (string) $s);
}
}

View File

@ -1,100 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\StreamWrapper;
use GuzzleHttp\Psr7;
/**
* @covers GuzzleHttp\Psr7\StreamWrapper
*/
class StreamWrapperTest extends \PHPUnit_Framework_TestCase
{
public function testResource()
{
$stream = Psr7\stream_for('foo');
$handle = StreamWrapper::getResource($stream);
$this->assertSame('foo', fread($handle, 3));
$this->assertSame(3, ftell($handle));
$this->assertSame(3, fwrite($handle, 'bar'));
$this->assertSame(0, fseek($handle, 0));
$this->assertSame('foobar', fread($handle, 6));
$this->assertSame('', fread($handle, 1));
$this->assertTrue(feof($handle));
// This fails on HHVM for some reason
if (!defined('HHVM_VERSION')) {
$this->assertEquals([
'dev' => 0,
'ino' => 0,
'mode' => 33206,
'nlink' => 0,
'uid' => 0,
'gid' => 0,
'rdev' => 0,
'size' => 6,
'atime' => 0,
'mtime' => 0,
'ctime' => 0,
'blksize' => 0,
'blocks' => 0,
0 => 0,
1 => 0,
2 => 33206,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 6,
8 => 0,
9 => 0,
10 => 0,
11 => 0,
12 => 0,
], fstat($handle));
}
$this->assertTrue(fclose($handle));
$this->assertSame('foobar', (string) $stream);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesStream()
{
$stream = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isReadable', 'isWritable'])
->getMockForAbstractClass();
$stream->expects($this->once())
->method('isReadable')
->will($this->returnValue(false));
$stream->expects($this->once())
->method('isWritable')
->will($this->returnValue(false));
StreamWrapper::getResource($stream);
}
/**
* @expectedException \PHPUnit_Framework_Error_Warning
*/
public function testReturnsFalseWhenStreamDoesNotExist()
{
fopen('guzzle://foo', 'r');
}
public function testCanOpenReadonlyStream()
{
$stream = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isReadable', 'isWritable'])
->getMockForAbstractClass();
$stream->expects($this->once())
->method('isReadable')
->will($this->returnValue(false));
$stream->expects($this->once())
->method('isWritable')
->will($this->returnValue(true));
$r = StreamWrapper::getResource($stream);
$this->assertInternalType('resource', $r);
fclose($r);
}
}

View File

@ -1,245 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\Uri;
/**
* @covers GuzzleHttp\Psr7\Uri
*/
class UriTest extends \PHPUnit_Framework_TestCase
{
const RFC3986_BASE = "http://a/b/c/d;p?q";
public function testParsesProvidedUrl()
{
$uri = new Uri('https://michael:test@test.com:443/path/123?q=abc#test');
// Standard port 443 for https gets ignored.
$this->assertEquals(
'https://michael:test@test.com/path/123?q=abc#test',
(string) $uri
);
$this->assertEquals('test', $uri->getFragment());
$this->assertEquals('test.com', $uri->getHost());
$this->assertEquals('/path/123', $uri->getPath());
$this->assertEquals(null, $uri->getPort());
$this->assertEquals('q=abc', $uri->getQuery());
$this->assertEquals('https', $uri->getScheme());
$this->assertEquals('michael:test', $uri->getUserInfo());
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Unable to parse URI
*/
public function testValidatesUriCanBeParsed()
{
new Uri('///');
}
public function testCanTransformAndRetrievePartsIndividually()
{
$uri = (new Uri(''))
->withFragment('#test')
->withHost('example.com')
->withPath('path/123')
->withPort(8080)
->withQuery('?q=abc')
->withScheme('http')
->withUserInfo('user', 'pass');
// Test getters.
$this->assertEquals('user:pass@example.com:8080', $uri->getAuthority());
$this->assertEquals('test', $uri->getFragment());
$this->assertEquals('example.com', $uri->getHost());
$this->assertEquals('path/123', $uri->getPath());
$this->assertEquals(8080, $uri->getPort());
$this->assertEquals('q=abc', $uri->getQuery());
$this->assertEquals('http', $uri->getScheme());
$this->assertEquals('user:pass', $uri->getUserInfo());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testPortMustBeValid()
{
(new Uri(''))->withPort(100000);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testPathMustBeValid()
{
(new Uri(''))->withPath([]);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testQueryMustBeValid()
{
(new Uri(''))->withQuery(new \stdClass);
}
public function testAllowsFalseyUrlParts()
{
$url = new Uri('http://a:1/0?0#0');
$this->assertSame('a', $url->getHost());
$this->assertEquals(1, $url->getPort());
$this->assertSame('/0', $url->getPath());
$this->assertEquals('0', (string) $url->getQuery());
$this->assertSame('0', $url->getFragment());
$this->assertEquals('http://a:1/0?0#0', (string) $url);
$url = new Uri('');
$this->assertSame('', (string) $url);
$url = new Uri('0');
$this->assertSame('0', (string) $url);
$url = new Uri('/');
$this->assertSame('/', (string) $url);
}
/**
* @dataProvider getResolveTestCases
*/
public function testResolvesUris($base, $rel, $expected)
{
$uri = new Uri($base);
$actual = Uri::resolve($uri, $rel);
$this->assertEquals($expected, (string) $actual);
}
public function getResolveTestCases()
{
return [
//[self::RFC3986_BASE, 'g:h', 'g:h'],
[self::RFC3986_BASE, 'g', 'http://a/b/c/g'],
[self::RFC3986_BASE, './g', 'http://a/b/c/g'],
[self::RFC3986_BASE, 'g/', 'http://a/b/c/g/'],
[self::RFC3986_BASE, '/g', 'http://a/g'],
[self::RFC3986_BASE, '//g', 'http://g'],
[self::RFC3986_BASE, '?y', 'http://a/b/c/d;p?y'],
[self::RFC3986_BASE, 'g?y', 'http://a/b/c/g?y'],
[self::RFC3986_BASE, '#s', 'http://a/b/c/d;p?q#s'],
[self::RFC3986_BASE, 'g#s', 'http://a/b/c/g#s'],
[self::RFC3986_BASE, 'g?y#s', 'http://a/b/c/g?y#s'],
[self::RFC3986_BASE, ';x', 'http://a/b/c/;x'],
[self::RFC3986_BASE, 'g;x', 'http://a/b/c/g;x'],
[self::RFC3986_BASE, 'g;x?y#s', 'http://a/b/c/g;x?y#s'],
[self::RFC3986_BASE, '', self::RFC3986_BASE],
[self::RFC3986_BASE, '.', 'http://a/b/c/'],
[self::RFC3986_BASE, './', 'http://a/b/c/'],
[self::RFC3986_BASE, '..', 'http://a/b/'],
[self::RFC3986_BASE, '../', 'http://a/b/'],
[self::RFC3986_BASE, '../g', 'http://a/b/g'],
[self::RFC3986_BASE, '../..', 'http://a/'],
[self::RFC3986_BASE, '../../', 'http://a/'],
[self::RFC3986_BASE, '../../g', 'http://a/g'],
[self::RFC3986_BASE, '../../../g', 'http://a/g'],
[self::RFC3986_BASE, '../../../../g', 'http://a/g'],
[self::RFC3986_BASE, '/./g', 'http://a/g'],
[self::RFC3986_BASE, '/../g', 'http://a/g'],
[self::RFC3986_BASE, 'g.', 'http://a/b/c/g.'],
[self::RFC3986_BASE, '.g', 'http://a/b/c/.g'],
[self::RFC3986_BASE, 'g..', 'http://a/b/c/g..'],
[self::RFC3986_BASE, '..g', 'http://a/b/c/..g'],
[self::RFC3986_BASE, './../g', 'http://a/b/g'],
[self::RFC3986_BASE, 'foo////g', 'http://a/b/c/foo////g'],
[self::RFC3986_BASE, './g/.', 'http://a/b/c/g/'],
[self::RFC3986_BASE, 'g/./h', 'http://a/b/c/g/h'],
[self::RFC3986_BASE, 'g/../h', 'http://a/b/c/h'],
[self::RFC3986_BASE, 'g;x=1/./y', 'http://a/b/c/g;x=1/y'],
[self::RFC3986_BASE, 'g;x=1/../y', 'http://a/b/c/y'],
//[self::RFC3986_BASE, 'http:g', 'http:g'],
];
}
public function testAddAndRemoveQueryValues()
{
$uri = new Uri('http://foo.com/bar');
$uri = Uri::withQueryValue($uri, 'a', 'b');
$uri = Uri::withQueryValue($uri, 'c', 'd');
$uri = Uri::withQueryValue($uri, 'e', null);
$this->assertEquals('a=b&c=d&e', $uri->getQuery());
$uri = Uri::withoutQueryValue($uri, 'c');
$uri = Uri::withoutQueryValue($uri, 'e');
$this->assertEquals('a=b', $uri->getQuery());
$uri = Uri::withoutQueryValue($uri, 'a');
$uri = Uri::withoutQueryValue($uri, 'a');
$this->assertEquals('', $uri->getQuery());
}
public function testGetAuthorityReturnsCorrectPort()
{
// HTTPS non-standard port
$uri = new Uri('https://foo.co:99');
$this->assertEquals('foo.co:99', $uri->getAuthority());
// HTTP non-standard port
$uri = new Uri('http://foo.co:99');
$this->assertEquals('foo.co:99', $uri->getAuthority());
// No scheme
$uri = new Uri('foo.co:99');
$this->assertEquals('foo.co:99', $uri->getAuthority());
// No host or port
$uri = new Uri('http:');
$this->assertEquals('', $uri->getAuthority());
// No host or port
$uri = new Uri('http://foo.co');
$this->assertEquals('foo.co', $uri->getAuthority());
}
public function pathTestProvider()
{
return [
// Percent encode spaces.
['http://foo.com/baz bar', 'http://foo.com/baz%20bar'],
// Don't encoding something that's already encoded.
['http://foo.com/baz%20bar', 'http://foo.com/baz%20bar'],
// Percent encode invalid percent encodings
['http://foo.com/baz%2-bar', 'http://foo.com/baz%252-bar'],
// Don't encode path segments
['http://foo.com/baz/bar/bam?a', 'http://foo.com/baz/bar/bam?a'],
['http://foo.com/baz+bar', 'http://foo.com/baz+bar'],
['http://foo.com/baz:bar', 'http://foo.com/baz:bar'],
['http://foo.com/baz@bar', 'http://foo.com/baz@bar'],
['http://foo.com/baz(bar);bam/', 'http://foo.com/baz(bar);bam/'],
['http://foo.com/a-zA-Z0-9.-_~!$&\'()*+,;=:@', 'http://foo.com/a-zA-Z0-9.-_~!$&\'()*+,;=:@'],
];
}
/**
* @dataProvider pathTestProvider
*/
public function testUriEncodesPathProperly($input, $output)
{
$uri = new Uri($input);
$this->assertEquals((string) $uri, $output);
}
public function testDoesNotAddPortWhenNoPort()
{
$this->assertEquals('bar', new Uri('//bar'));
$this->assertEquals('bar', (new Uri('//bar'))->getHost());
}
public function testAllowsForRelativeUri()
{
$uri = (new Uri)->withPath('foo');
$this->assertEquals('foo', $uri->getPath());
$this->assertEquals('foo', (string) $uri);
}
public function testAddsSlashForRelativeUriStringWithHost()
{
$uri = (new Uri)->withPath('foo')->withHost('bar.com');
$this->assertEquals('foo', $uri->getPath());
$this->assertEquals('bar.com/foo', (string) $uri);
}
}

View File

@ -1,11 +0,0 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
require __DIR__ . '/../vendor/autoload.php';
class HasToString
{
public function __toString() {
return 'foo';
}
}

@ -1 +0,0 @@
Subproject commit 85d63699f0dbedb190bbd4b0d2b9dc707ea4c298

View File

@ -1,19 +0,0 @@
Copyright (c) 2012 PHP Framework Interoperability Group
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,120 +0,0 @@
<?php
namespace Psr\Log;
/**
* This is a simple Logger implementation that other Loggers can inherit from.
*
* It simply delegates all log-level-specific methods to the `log` method to
* reduce boilerplate code that a simple Logger that does the same thing with
* messages regardless of the error level has to implement.
*/
abstract class AbstractLogger implements LoggerInterface
{
/**
* System is unusable.
*
* @param string $message
* @param array $context
* @return null
*/
public function emergency($message, array $context = array())
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
* @return null
*/
public function alert($message, array $context = array())
{
$this->log(LogLevel::ALERT, $message, $context);
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
* @return null
*/
public function critical($message, array $context = array())
{
$this->log(LogLevel::CRITICAL, $message, $context);
}
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
* @param array $context
* @return null
*/
public function error($message, array $context = array())
{
$this->log(LogLevel::ERROR, $message, $context);
}
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
* @return null
*/
public function warning($message, array $context = array())
{
$this->log(LogLevel::WARNING, $message, $context);
}
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
* @return null
*/
public function notice($message, array $context = array())
{
$this->log(LogLevel::NOTICE, $message, $context);
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
* @return null
*/
public function info($message, array $context = array())
{
$this->log(LogLevel::INFO, $message, $context);
}
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
* @return null
*/
public function debug($message, array $context = array())
{
$this->log(LogLevel::DEBUG, $message, $context);
}
}

View File

@ -1,7 +0,0 @@
<?php
namespace Psr\Log;
class InvalidArgumentException extends \InvalidArgumentException
{
}

View File

@ -1,18 +0,0 @@
<?php
namespace Psr\Log;
/**
* Describes log levels
*/
class LogLevel
{
const EMERGENCY = 'emergency';
const ALERT = 'alert';
const CRITICAL = 'critical';
const ERROR = 'error';
const WARNING = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
}

View File

@ -1,17 +0,0 @@
<?php
namespace Psr\Log;
/**
* Describes a logger-aware instance
*/
interface LoggerAwareInterface
{
/**
* Sets a logger instance on the object
*
* @param LoggerInterface $logger
* @return null
*/
public function setLogger(LoggerInterface $logger);
}

Some files were not shown because too many files have changed in this diff Show More