Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F1819962
README.md
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Size
15 KB
Subscribers
None
README.md
View Options
sabre
/
http
==========
This
library
provides
a
toolkit
to
make
working
with
the
HTTP
protocol
easier
.
Most
PHP
scripts
run
within
a
HTTP
request
but
accessing
information
about
the
HTTP
request
is
cumbersome
at
least
.
There
'
s
bad
practices
,
inconsistencies
and
confusion
.
This
library
is
effectively
a
wrapper
around
the
following
PHP
constructs
:
For
Input
:
*
`
$
_GET
`
,
*
`
$
_POST
`
,
*
`
$
_SERVER
`
,
*
`
php
:
//input` or `$HTTP_RAW_POST_DATA`.
For
output
:
*
`
php
:
//output` or `echo`,
*
`
header
()
`
.
What
this
library
provides
,
is
a
`
Request
`
object
,
and
a
`
Response
`
object
.
The
objects
are
extendable
and
easily
mockable
.
Build
status
------------
|
branch
|
status
|
|
------
|
------
|
|
master
|
[![
Build
Status
](
https
:
//travis-ci.org/fruux/sabre-http.svg?branch=master)](https://travis-ci.org/fruux/sabre-http) |
|
3.0
|
[![
Build
Status
](
https
:
//travis-ci.org/fruux/sabre-http.svg?branch=3.0)](https://travis-ci.org/fruux/sabre-http) |
Installation
------------
Make
sure
you
have
[
composer
][
1
]
installed
.
In
your
project
directory
,
create
,
or
edit
a
`
composer
.
json
`
file
,
and
make
sure
it
contains
something
like
this
:
```
json
{
"require"
:
{
"sabre/http"
:
"~3.0.0"
}
}
```
After
that
,
just
hit
`
composer
install
`
and
you
should
be
rolling
.
Quick
history
-------------
This
library
came
to
existence
in
2009
,
as
a
part
of
the
[
`
sabre
/
dav
`
][
2
]
project
,
which
uses
it
heavily
.
It
got
split
off
into
a
separate
library
to
make
it
easier
to
manage
releases
and
hopefully
giving
it
use
outside
of
the
scope
of
just
`
sabre
/
dav
`
.
Although
completely
independently
developed
,
this
library
has
a
LOT
of
overlap
with
[
Symfony
'
s
`
HttpFoundation
`
][
3
].
Said
library
does
a
lot
more
stuff
and
is
significantly
more
popular
,
so
if
you
are
looking
for
something
to
fulfill
this
particular
requirement
,
I
'
d
recommend
also
considering
[
`
HttpFoundation
`
][
3
].
Getting
started
---------------
First
and
foremost
,
this
library
wraps
the
superglobals
.
The
easiest
way
to
instantiate
a
request
object
is
as
follows
:
```
php
use
Sabre
\
HTTP
;
include
'
vendor
/
autoload
.
php
'
;
$
request
=
HTTP
\
Sapi
::
getRequest
();
```
This
line
should
only
happen
once
in
your
entire
application
.
Everywhere
else
you
should
pass
this
request
object
around
using
dependency
injection
.
You
should
always
typehint
on
it
'
s
interface
:
```
php
function
handleRequest
(
HTTP
\
RequestInterface
$
request
)
{
// Do something with this request :)
}
```
A
response
object
you
can
just
create
as
such
:
```
php
use
Sabre
\
HTTP
;
include
'
vendor
/
autoload
.
php
'
;
$
response
=
new
HTTP
\
Response
();
$
response
->
setStatus
(
201
);
// created !
$
response
->
setHeader
(
'
X
-
Foo
'
,
'
bar
'
);
$
response
->
setBody
(
'
success
!
'
);
```
After
you
fully
constructed
your
response
,
you
must
call
:
```
php
HTTP
\
Sapi
::
sendResponse
($
response
);
```
This
line
should
generally
also
appear
once
in
your
application
(
at
the
very
end
).
Decorators
----------
It
may
be
useful
to
extend
the
`
Request
`
and
`
Response
`
objects
in
your
application
,
if
you
for
example
would
like
them
to
carry
a
bit
more
information
about
the
current
request
.
For
instance
,
you
may
want
to
add
an
`
isLoggedIn
`
method
to
the
Request
object
.
Simply
extending
Request
and
Response
may
pose
some
problems
:
1
.
You
may
want
to
extend
the
objects
with
new
behaviors
differently
,
in
different
subsystems
of
your
application
,
2
.
The
`
Sapi
::
getRequest
`
factory
always
returns
a
instance
of
`
Request
`
so
you
would
have
to
override
the
factory
method
as
well
,
3
.
By
controlling
the
instantation
and
depend
on
specific
`
Request
`
and
`
Response
`
instances
in
your
library
or
application
,
you
make
it
harder
to
work
with
other
applications
which
also
use
`
sabre
/
http
`
.
In
short
:
it
would
be
bad
design
.
Instead
,
it
'
s
recommended
to
use
the
[
decorator
pattern
][
6
]
to
add
new
behavior
where
you
need
it
.
`
sabre
/
http
`
provides
helper
classes
to
quickly
do
this
.
Example
:
```
php
use
Sabre
\
HTTP
;
class
MyRequest
extends
HTTP
\
RequestDecorator
{
function
isLoggedIn
()
{
return
true
;
}
}
```
Our
application
assumes
that
the
true
`
Request
`
object
was
instantiated
somewhere
else
,
by
some
other
subsystem
.
This
could
simply
be
a
call
like
`
$
request
=
Sapi
::
getRequest
()
`
at
the
top
of
your
application
,
but
could
also
be
somewhere
in
a
unittest
.
All
we
know
in
the
current
subsystem
,
is
that
we
received
a
`
$
request
`
and
that
it
implements
`
Sabre
\
HTTP
\
RequestInterface
`
.
To
decorate
this
object
,
all
we
need
to
do
is
:
```
php
$
request
=
new
MyRequest
($
request
);
```
And
that
'
s
it
,
we
now
have
an
`
isLoggedIn
`
method
,
without
having
to
mess
with
the
core
instances
.
Client
------
This
package
also
contains
a
simple
wrapper
around
[
cURL
][
4
],
which
will
allow
you
to
write
simple
clients
,
using
the
`
Request
`
and
`
Response
`
objects
you
'
re
already
familiar
with
.
It
'
s
by
no
means
a
replacement
for
something
like
[
Guzzle
][
7
],
but
it
provides
a
simple
and
lightweight
API
for
making
the
occasional
API
call
.
###
Usage
```
php
use
Sabre
\
HTTP
;
$
request
=
new
HTTP
\
Request
(
'
GET
'
,
'
http
:
//example.org/');
$
request
->
setHeader
(
'
X
-
Foo
'
,
'
Bar
'
);
$
client
=
new
HTTP
\
Client
();
$
response
=
$
client
->
send
($
request
);
echo
$
response
->
getBodyAsString
();
```
The
client
emits
3
event
using
[
`
sabre
/
event
`
][
5
].
`
beforeRequest
`
,
`
afterRequest
`
and
`
error
`
.
```
php
$
client
=
new
HTTP
\
Client
();
$
client
->
on
(
'
beforeRequest
'
,
function
($
request
)
{
// You could use beforeRequest to for example inject a few extra headers.
// into the Request object.
});
$
client
->
on
(
'
afterRequest
'
,
function
($
request
,
$
response
)
{
// The afterRequest event could be a good time to do some logging, or
// do some rewriting in the response.
});
$
client
->
on
(
'
error
'
,
function
($
request
,
$
response
,
&$
retry
,
$
retryCount
)
{
// The error event is triggered for every response with a HTTP code higher
// than 399.
});
$
client
->
on
(
'
error
:
401
'
,
function
($
request
,
$
response
,
&$
retry
,
$
retryCount
)
{
// You can also listen for specific error codes. This example shows how
// to inject HTTP authentication headers if a 401 was returned.
if
($
retryCount
>
1
)
{
// We're only going to retry exactly once.
}
$
request
->
setHeader
(
'
Authorization
'
,
'
Basic
xxxxxxxxxx
'
);
$
retry
=
true
;
});
```
###
Asynchronous
requests
The
`
Client
`
also
supports
doing
asynchronous
requests
.
This
is
especially
handy
if
you
need
to
perform
a
number
of
requests
,
that
are
allowed
to
be
executed
in
parallel
.
The
underlying
system
for
this
is
simply
[
cURL
'
s
multi
request
handler
][
8
],
but
this
provides
a
much
nicer
API
to
handle
this
.
Sample
usage
:
```
php
use
Sabre
\
HTTP
;
$
request
=
new
Request
(
'
GET
'
,
'
http
:
//localhost/');
$
client
=
new
Client
();
// Executing 1000 requests
for
($
i
=
0
;
$
i
<
1000
;
$
i
++)
{
$
client
->
sendAsync
(
$
request
,
function
(
ResponseInterface
$
response
)
{
// Success handler
},
function
($
error
)
{
// Error handler
}
);
}
// Wait for all requests to get a result.
$
client
->
wait
();
```
Check
out
`
examples
/
asyncclient
.
php
`
for
more
information
.
Writing
a
reverse
proxy
-----------------------
With
all
these
tools
combined
,
it
becomes
very
easy
to
write
a
simple
reverse
http
proxy
.
```
php
use
Sabre
\
HTTP
\
Sapi
,
Sabre
\
HTTP
\
Client
;
// The url we're proxying to.
$
remoteUrl
=
'
http
:
//example.org/';
// The url we're proxying from. Please note that this must be a relative url,
// and basically acts as the base url.
//
// If youre $remoteUrl doesn't end with a slash, this one probably shouldn't
// either.
$
myBaseUrl
=
'
/
reverseproxy
.
php
'
;
// $myBaseUrl = '/~evert/sabre/http/examples/reverseproxy.php/';
$
request
=
Sapi
::
getRequest
();
$
request
->
setBaseUrl
($
myBaseUrl
);
$
subRequest
=
clone
$
request
;
// Removing the Host header.
$
subRequest
->
removeHeader
(
'
Host
'
);
// Rewriting the url.
$
subRequest
->
setUrl
($
remoteUrl
.
$
request
->
getPath
());
$
client
=
new
Client
();
// Sends the HTTP request to the server
$
response
=
$
client
->
send
($
subRequest
);
// Sends the response back to the client that connected to the proxy.
Sapi
::
sendResponse
($
response
);
```
The
Request
and
Response
API
'
s
------------------------------
###
Request
```
php
/**
* Creates the request object
*
* @param string $method
* @param string $url
* @param array $headers
* @param resource $body
*/
public
function
__construct
($
method
=
null
,
$
url
=
null
,
array
$
headers
=
null
,
$
body
=
null
);
/**
* Returns the current HTTP method
*
* @return string
*/
function
getMethod
();
/**
* Sets the HTTP method
*
* @param string $method
* @return void
*/
function
setMethod
($
method
);
/**
* Returns the request url.
*
* @return string
*/
function
getUrl
();
/**
* Sets the request url.
*
* @param string $url
* @return void
*/
function
setUrl
($
url
);
/**
* Returns the absolute url.
*
* @return string
*/
function
getAbsoluteUrl
();
/**
* Sets the absolute url.
*
* @param string $url
* @return void
*/
function
setAbsoluteUrl
($
url
);
/**
* Returns the current base url.
*
* @return string
*/
function
getBaseUrl
();
/**
* Sets a base url.
*
* This url is used for relative path calculations.
*
* The base url should default to /
*
* @param string $url
* @return void
*/
function
setBaseUrl
($
url
);
/**
* Returns the relative path.
*
* This is being calculated using the base url. This path will not start
* with a slash, so it will always return something like
* 'example/path.html'.
*
* If the full path is equal to the base url, this method will return an
* empty string.
*
* This method will also urldecode the path, and if the url was incoded as
* ISO-8859-1, it will convert it to UTF-8.
*
* If the path is outside of the base url, a LogicException will be thrown.
*
* @return string
*/
function
getPath
();
/**
* Returns the list of query parameters.
*
* This is equivalent to PHP's $_GET superglobal.
*
* @return array
*/
function
getQueryParameters
();
/**
* Returns the POST data.
*
* This is equivalent to PHP's $_POST superglobal.
*
* @return array
*/
function
getPostData
();
/**
* Sets the post data.
*
* This is equivalent to PHP's $_POST superglobal.
*
* This would not have been needed, if POST data was accessible as
* php://input, but unfortunately we need to special case it.
*
* @param array $postData
* @return void
*/
function
setPostData
(
array
$
postData
);
/**
* Returns an item from the _SERVER array.
*
* If the value does not exist in the array, null is returned.
*
* @param string $valueName
* @return string|null
*/
function
getRawServerValue
($
valueName
);
/**
* Sets the _SERVER array.
*
* @param array $data
* @return void
*/
function
setRawServerData
(
array
$
data
);
/**
* Returns the body as a readable stream resource.
*
* Note that the stream may not be rewindable, and therefore may only be
* read once.
*
* @return resource
*/
function
getBodyAsStream
();
/**
* Returns the body as a string.
*
* Note that because the underlying data may be based on a stream, this
* method could only work correctly the first time.
*
* @return string
*/
function
getBodyAsString
();
/**
* Returns the message body, as it's internal representation.
*
* This could be either a string or a stream.
*
* @return resource|string
*/
function
getBody
();
/**
* Updates the body resource with a new stream.
*
* @param resource $body
* @return void
*/
function
setBody
($
body
);
/**
* Returns all the HTTP headers as an array.
*
* @return array
*/
function
getHeaders
();
/**
* Returns a specific HTTP header, based on it's name.
*
* The name must be treated as case-insensitive.
*
* If the header does not exist, this method must return null.
*
* @param string $name
* @return string|null
*/
function
getHeader
($
name
);
/**
* Updates a HTTP header.
*
* The case-sensitity of the name value must be retained as-is.
*
* @param string $name
* @param string $value
* @return void
*/
function
setHeader
($
name
,
$
value
);
/**
* Resets HTTP headers
*
* This method overwrites all existing HTTP headers
*
* @param array $headers
* @return void
*/
function
setHeaders
(
array
$
headers
);
/**
* Adds a new set of HTTP headers.
*
* Any header specified in the array that already exists will be
* overwritten, but any other existing headers will be retained.
*
* @param array $headers
* @return void
*/
function
addHeaders
(
array
$
headers
);
/**
* Removes a HTTP header.
*
* The specified header name must be treated as case-insenstive.
* This method should return true if the header was successfully deleted,
* and false if the header did not exist.
*
* @return bool
*/
function
removeHeader
($
name
);
/**
* Sets the HTTP version.
*
* Should be 1.0 or 1.1.
*
* @param string $version
* @return void
*/
function
setHttpVersion
($
version
);
/**
* Returns the HTTP version.
*
* @return string
*/
function
getHttpVersion
();
```
###
Response
```
php
/**
* Returns the current HTTP status.
*
* This is the status-code as well as the human readable string.
*
* @return string
*/
function
getStatus
();
/**
* Sets the HTTP status code.
*
* This can be either the full HTTP status code with human readable string,
* for example: "403 I can't let you do that, Dave".
*
* Or just the code, in which case the appropriate default message will be
* added.
*
* @param string|int $status
* @throws \InvalidArgumentExeption
* @return void
*/
function
setStatus
($
status
);
/**
* Returns the body as a readable stream resource.
*
* Note that the stream may not be rewindable, and therefore may only be
* read once.
*
* @return resource
*/
function
getBodyAsStream
();
/**
* Returns the body as a string.
*
* Note that because the underlying data may be based on a stream, this
* method could only work correctly the first time.
*
* @return string
*/
function
getBodyAsString
();
/**
* Returns the message body, as it's internal representation.
*
* This could be either a string or a stream.
*
* @return resource|string
*/
function
getBody
();
/**
* Updates the body resource with a new stream.
*
* @param resource $body
* @return void
*/
function
setBody
($
body
);
/**
* Returns all the HTTP headers as an array.
*
* @return array
*/
function
getHeaders
();
/**
* Returns a specific HTTP header, based on it's name.
*
* The name must be treated as case-insensitive.
*
* If the header does not exist, this method must return null.
*
* @param string $name
* @return string|null
*/
function
getHeader
($
name
);
/**
* Updates a HTTP header.
*
* The case-sensitity of the name value must be retained as-is.
*
* @param string $name
* @param string $value
* @return void
*/
function
setHeader
($
name
,
$
value
);
/**
* Resets HTTP headers
*
* This method overwrites all existing HTTP headers
*
* @param array $headers
* @return void
*/
function
setHeaders
(
array
$
headers
);
/**
* Adds a new set of HTTP headers.
*
* Any header specified in the array that already exists will be
* overwritten, but any other existing headers will be retained.
*
* @param array $headers
* @return void
*/
function
addHeaders
(
array
$
headers
);
/**
* Removes a HTTP header.
*
* The specified header name must be treated as case-insenstive.
* This method should return true if the header was successfully deleted,
* and false if the header did not exist.
*
* @return bool
*/
function
removeHeader
($
name
);
/**
* Sets the HTTP version.
*
* Should be 1.0 or 1.1.
*
* @param string $version
* @return void
*/
function
setHttpVersion
($
version
);
/**
* Returns the HTTP version.
*
* @return string
*/
function
getHttpVersion
();
```
Made
at
fruux
-------------
This
library
is
being
developed
by
[
fruux
](
https
:
//fruux.com/). Drop us a line for commercial services or enterprise support.
[
1
]:
http
:
//getcomposer.org/
[
2
]:
http
:
//sabre.io/
[
3
]:
https
:
//github.com/symfony/HttpFoundation
[
4
]:
http
:
//php.net/curl
[
5
]:
https
:
//github.com/fruux/sabre-event
[
6
]:
http
:
//en.wikipedia.org/wiki/Decorator_pattern
[
7
]:
http
:
//guzzlephp.org/
[
8
]:
http
:
//php.net/curl_multi_init
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Dec 21, 3:41 PM (2 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
905784
Default Alt Text
README.md (15 KB)
Attached To
rDAVCAL DokuWiki DAVCal PlugIn
Event Timeline
Log In to Comment