Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
<?php
2
 
3
namespace Guzzle\Http;
4
 
5
use Guzzle\Common\Collection;
6
use Guzzle\Common\Exception\RuntimeException;
7
use Guzzle\Http\QueryAggregator\DuplicateAggregator;
8
use Guzzle\Http\QueryAggregator\QueryAggregatorInterface;
9
use Guzzle\Http\QueryAggregator\PhpAggregator;
10
 
11
/**
12
 * Query string object to handle managing query string parameters and aggregating those parameters together as a string.
13
 */
14
class QueryString extends Collection
15
{
16
    /** @var string Used to URL encode with rawurlencode */
17
    const RFC_3986 = 'RFC 3986';
18
 
19
    /** @var string Used to encode with urlencode */
20
    const FORM_URLENCODED = 'application/x-www-form-urlencoded';
21
 
22
    /** @var string Constant used to create blank query string values (e.g. ?foo) */
23
    const BLANK = "_guzzle_blank_";
24
 
25
    /** @var string The query string field separator (e.g. '&') */
26
    protected $fieldSeparator = '&';
27
 
28
    /** @var string The query string value separator (e.g. '=') */
29
    protected $valueSeparator = '=';
30
 
31
    /** @var bool URL encode fields and values */
32
    protected $urlEncode = 'RFC 3986';
33
 
34
    /** @var QueryAggregatorInterface */
35
    protected $aggregator;
36
 
37
    /** @var array Cached PHP aggregator */
38
    private static $defaultAggregator = null;
39
 
40
    /**
41
     * Parse a query string into a QueryString object
42
     *
43
     * @param string $query Query string to parse
44
     *
45
     * @return self
46
     */
47
    public static function fromString($query)
48
    {
49
        $q = new static();
50
        if ($query === '') {
51
            return $q;
52
        }
53
 
54
        $foundDuplicates = $foundPhpStyle = false;
55
 
56
        foreach (explode('&', $query) as $kvp) {
57
            $parts = explode('=', $kvp, 2);
58
            $key = rawurldecode($parts[0]);
59
            if ($paramIsPhpStyleArray = substr($key, -2) == '[]') {
60
                $foundPhpStyle = true;
61
                $key = substr($key, 0, -2);
62
            }
63
            if (isset($parts[1])) {
64
                $value = rawurldecode(str_replace('+', '%20', $parts[1]));
65
                if (isset($q[$key])) {
66
                    $q->add($key, $value);
67
                    $foundDuplicates = true;
68
                } elseif ($paramIsPhpStyleArray) {
69
                    $q[$key] = array($value);
70
                } else {
71
                    $q[$key] = $value;
72
                }
73
            } else {
74
                // Uses false by default to represent keys with no trailing "=" sign.
75
                $q->add($key, false);
76
            }
77
        }
78
 
79
        // Use the duplicate aggregator if duplicates were found and not using PHP style arrays
80
        if ($foundDuplicates && !$foundPhpStyle) {
81
            $q->setAggregator(new DuplicateAggregator());
82
        }
83
 
84
        return $q;
85
    }
86
 
87
    /**
88
     * Convert the query string parameters to a query string string
89
     *
90
     * @return string
91
     * @throws RuntimeException
92
     */
93
    public function __toString()
94
    {
95
        if (!$this->data) {
96
            return '';
97
        }
98
 
99
        $queryList = array();
100
        foreach ($this->prepareData($this->data) as $name => $value) {
101
            $queryList[] = $this->convertKvp($name, $value);
102
        }
103
 
104
        return implode($this->fieldSeparator, $queryList);
105
    }
106
 
107
    /**
108
     * Get the query string field separator
109
     *
110
     * @return string
111
     */
112
    public function getFieldSeparator()
113
    {
114
        return $this->fieldSeparator;
115
    }
116
 
117
    /**
118
     * Get the query string value separator
119
     *
120
     * @return string
121
     */
122
    public function getValueSeparator()
123
    {
124
        return $this->valueSeparator;
125
    }
126
 
127
    /**
128
     * Returns the type of URL encoding used by the query string
129
     *
130
     * One of: false, "RFC 3986", or "application/x-www-form-urlencoded"
131
     *
132
     * @return bool|string
133
     */
134
    public function getUrlEncoding()
135
    {
136
        return $this->urlEncode;
137
    }
138
 
139
    /**
140
     * Returns true or false if using URL encoding
141
     *
142
     * @return bool
143
     */
144
    public function isUrlEncoding()
145
    {
146
        return $this->urlEncode !== false;
147
    }
148
 
149
    /**
150
     * Provide a function for combining multi-valued query string parameters into a single or multiple fields
151
     *
152
     * @param null|QueryAggregatorInterface $aggregator Pass in a QueryAggregatorInterface object to handle converting
153
     *                                                  deeply nested query string variables into a flattened array.
154
     *                                                  Pass null to use the default PHP style aggregator. For legacy
155
     *                                                  reasons, this function accepts a callable that must accepts a
156
     *                                                  $key, $value, and query object.
157
     * @return self
158
     * @see \Guzzle\Http\QueryString::aggregateUsingComma()
159
     */
160
    public function setAggregator(QueryAggregatorInterface $aggregator = null)
161
    {
162
        // Use the default aggregator if none was set
163
        if (!$aggregator) {
164
            if (!self::$defaultAggregator) {
165
                self::$defaultAggregator = new PhpAggregator();
166
            }
167
            $aggregator = self::$defaultAggregator;
168
        }
169
 
170
        $this->aggregator = $aggregator;
171
 
172
        return $this;
173
    }
174
 
175
    /**
176
     * Set whether or not field names and values should be rawurlencoded
177
     *
178
     * @param bool|string $encode Set to TRUE to use RFC 3986 encoding (rawurlencode), false to disable encoding, or
179
     *                            form_urlencoding to use application/x-www-form-urlencoded encoding (urlencode)
180
     * @return self
181
     */
182
    public function useUrlEncoding($encode)
183
    {
184
        $this->urlEncode = ($encode === true) ? self::RFC_3986 : $encode;
185
 
186
        return $this;
187
    }
188
 
189
    /**
190
     * Set the query string separator
191
     *
192
     * @param string $separator The query string separator that will separate fields
193
     *
194
     * @return self
195
     */
196
    public function setFieldSeparator($separator)
197
    {
198
        $this->fieldSeparator = $separator;
199
 
200
        return $this;
201
    }
202
 
203
    /**
204
     * Set the query string value separator
205
     *
206
     * @param string $separator The query string separator that will separate values from fields
207
     *
208
     * @return self
209
     */
210
    public function setValueSeparator($separator)
211
    {
212
        $this->valueSeparator = $separator;
213
 
214
        return $this;
215
    }
216
 
217
    /**
218
     * Returns an array of url encoded field names and values
219
     *
220
     * @return array
221
     */
222
    public function urlEncode()
223
    {
224
        return $this->prepareData($this->data);
225
    }
226
 
227
    /**
228
     * URL encodes a value based on the url encoding type of the query string object
229
     *
230
     * @param string $value Value to encode
231
     *
232
     * @return string
233
     */
234
    public function encodeValue($value)
235
    {
236
        if ($this->urlEncode == self::RFC_3986) {
237
            return rawurlencode($value);
238
        } elseif ($this->urlEncode == self::FORM_URLENCODED) {
239
            return urlencode($value);
240
        } else {
241
            return (string) $value;
242
        }
243
    }
244
 
245
    /**
246
     * Url encode parameter data and convert nested query strings into a flattened hash.
247
     *
248
     * @param array $data The data to encode
249
     *
250
     * @return array Returns an array of encoded values and keys
251
     */
252
    protected function prepareData(array $data)
253
    {
254
        // If no aggregator is present then set the default
255
        if (!$this->aggregator) {
256
            $this->setAggregator(null);
257
        }
258
 
259
        $temp = array();
260
        foreach ($data as $key => $value) {
261
            if ($value === false || $value === null) {
262
                // False and null will not include the "=". Use an empty string to include the "=".
263
                $temp[$this->encodeValue($key)] = $value;
264
            } elseif (is_array($value)) {
265
                $temp = array_merge($temp, $this->aggregator->aggregate($key, $value, $this));
266
            } else {
267
                $temp[$this->encodeValue($key)] = $this->encodeValue($value);
268
            }
269
        }
270
 
271
        return $temp;
272
    }
273
 
274
    /**
275
     * Converts a key value pair that can contain strings, nulls, false, or arrays
276
     * into a single string.
277
     *
278
     * @param string $name  Name of the field
279
     * @param mixed  $value Value of the field
280
     * @return string
281
     */
282
    private function convertKvp($name, $value)
283
    {
284
        if ($value === self::BLANK || $value === null || $value === false) {
285
            return $name;
286
        } elseif (!is_array($value)) {
287
            return $name . $this->valueSeparator . $value;
288
        }
289
 
290
        $result = '';
291
        foreach ($value as $v) {
292
            $result .= $this->convertKvp($name, $v) . $this->fieldSeparator;
293
        }
294
 
295
        return rtrim($result, $this->fieldSeparator);
296
    }
297
}