Completed
Pull Request — master (#20)
by Auke
02:48
created

ClientStream::headers()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 6
Bugs 3 Features 2
Metric Value
c 6
b 3
f 2
dl 0
loc 16
ccs 0
cts 2
cp 0
rs 9.2
cc 4
eloc 9
nc 6
nop 1
crap 20
1
<?php
2
3
/*
4
 * This file is part of the Ariadne Component Library.
5
 *
6
 * (c) Muze <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace arc\http;
13
14
/**
15
 * Class ClientStream
16
 * Implements a HTTP client using PHP's stream handling.
17
 * @package arc\http
18
 */
19
class ClientStream implements Client
20
{
21
    private $options = [
22
        'headers'          => [],
23
        'timeout'          => 5,
24
        'ignore_errors'    => true,
25
        'protocol_version' => 1.1
26
    ];
27
28
    /**
29
     */
30 8
    public $responseHeaders = null;
31 8
    /**
32 8
     */
33 8
    public $requestHeaders  = null;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 2 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
34 8
    /**
35 1
     */
36 1
    public $verbs           = [
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 11 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
37 1
        'GET'     => true,
38 1
        'POST'    => true,
39 8
        'PUT'     => true,
40
        'DELETE'  => true,
41 8
        'OPTIONS' => true,
42 8
        'HEAD'    => true,
43 8
        'TRACE'   => true
44 8
    ];
45 8
    /**
46
     * Merges header string and headers array to single string with all headers
47
     * @return string
48
     */
49
    private function mergeHeaders() {
50
        $args   = func_get_args();
51
        $result = '';
52
        foreach ( $args as $headers ) {
53
            if (is_array($headers) || $headers instanceof \ArrayObject ) {
54
                $result .= array_reduce( (array) $headers, function($carry, $entry) {
55
                    return $carry . "\r\n" . $entry;
56 8
                }, '');
57
            } else {
58 8
                $result .= (string) $headers;
59 8
            }
60 1
        }
61 1
        if (substr($result, -2)!="\r\n") {
62 1
            $result .= "\r\n";
63
        }
64
        return $result;
65 8
    }
66
67 8
    /**
68
     * Send a HTTP request and return the response
69 8
     * @param string       $type    The method to use, GET, POST, etc.
70 8
     * @param string       $url     The URL to request
71 8
     * @param array|string $request The query string
72 8
     * @param array        $options Any of the HTTP stream context options, e.g. extra headers.
73 8
     * @return string
74 8
     */
75
    public function request( $type, $url, $request = null, $options = [] )
76 8
    {
77
        $url = \arc\url::url( (string) $url);
78 8
        if ($type == 'GET' && $request) {
79 8
            $url->query->import( $request);
80 8
            $request = null;
81 8
        }
82
        $options = [
83 8
            'method'  => $type,
84
            'content' => $request
85
        ] + (array) $options;
86
87
        $options['headers'] = $this->mergeHeaders(
88
            \arc\hash::get('header', $this->options),
89 10
            \arc\hash::get('headers', $this->options),
90
            \arc\hash::get('header', $options),
91 10
            \arc\hash::get('headers', $options)
92 10
        );
93
94
        $options += (array) $this->options;
95
96
        $context = stream_context_create( [ 'http' => $options ] );
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 15 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
97
        $result  = @file_get_contents( (string) $url, false, $context );
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 16 spaces but found 2 spaces

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
98
        $this->responseHeaders = isset($http_response_header) ? $http_response_header : null; //magic php variable set by file_get_contents.
99
        $this->requestHeaders  = isset($options['headers']) ? explode("\r\n",$options['headers']) : [];
100
101 7
        return $result;
102
    }
103 7
104
    /**
105
     * @param array $options Any of the HTTP stream context options, e.g. extra headers.
106
     */
107
    public function __construct( $options = [] )
108
    {
109
        $this->options = $options;
110
    }
111
112
    public function __call( $name, $args )
113
    {
114
        $name = strtoupper($name);
115
        if ( isset($this->verbs[$name]) && $this->verbs[$name] ) {
116
            @list($url, $request, $options) = $args;
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
117
            return $this->request( $name, $url, $request, $options );
118
        } else {
119
            throw new \arc\MethodNotFound("'$name' is not a valid http client method", \arc\exceptions::OBJECT_NOT_FOUND );
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $name instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
120
        }
121
    }
122
123
124
    /**
125
     * Adds headers for subsequent requests
126
     * @param mixed $headers The headers to add, either as a string or an array of headers.
127
     * @return $this
128
     */
129
    public function headers($headers)
130
    {
131
        if (!isset($this->options['headers'])) {
132
            $this->options['headers'] = [];
133
        }
134
        if ( !is_array($headers) ) {
135
            $headers = explode("\r\n",$headers);
136
            if (end($headers) == '') {
137
                array_pop($headers);
138
            }
139
        }
140
141
        $this->options['headers'] = array_merge($this->options['headers'], $headers);
142
143
        return $this;
144
    }
145
}
146