-
Notifications
You must be signed in to change notification settings - Fork 15
/
oauth_helper.php
221 lines (194 loc) · 6.46 KB
/
oauth_helper.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
<?php
/**
* Helper functions for OAuth
*/
/**
* Build a query parameter string according to OAuth Spec.
* @param array $params an array of query parameters
* @return string all the query parameters properly sorted and encoded
* according to the OAuth spec, or an empty string if params is empty.
* @link http://oauth.net/core/1.0/#rfc.section.9.1.1
*/
function oauth_http_build_query($params, $excludeOauthParams=false)
{
$query_string = '';
if (! empty($params)) {
// rfc3986 encode both keys and values
$keys = rfc3986_encode(array_keys($params));
$values = rfc3986_encode(array_values($params));
$params = array_combine($keys, $values);
// Parameters are sorted by name, using lexicographical byte value ordering.
// http://oauth.net/core/1.0/#rfc.section.9.1.1
uksort($params, 'strcmp');
// Turn params array into an array of "key=value" strings
$kvpairs = array();
foreach ($params as $k => $v) {
if ($excludeOauthParams && substr($k, 0, 5) == 'oauth') {
continue;
}
if (is_array($v)) {
// If two or more parameters share the same name,
// they are sorted by their value. OAuth Spec: 9.1.1 (1)
natsort($v);
foreach ($v as $value_for_same_key) {
array_push($kvpairs, ($k . '=' . $value_for_same_key));
}
} else {
// For each parameter, the name is separated from the corresponding
// value by an '=' character (ASCII code 61). OAuth Spec: 9.1.1 (2)
array_push($kvpairs, ($k . '=' . $v));
}
}
// Each name-value pair is separated by an '&' character, ASCII code 38.
// OAuth Spec: 9.1.1 (2)
$query_string = implode('&', $kvpairs);
}
return $query_string;
}
/**
* Parse a query string into an array.
* @param string $query_string an OAuth query parameter string
* @return array an array of query parameters
* @link http://oauth.net/core/1.0/#rfc.section.9.1.1
*/
function oauth_parse_str($query_string)
{
$query_array = array();
if (isset($query_string)) {
// Separate single string into an array of "key=value" strings
$kvpairs = explode('&', $query_string);
// Separate each "key=value" string into an array[key] = value
foreach ($kvpairs as $pair) {
list($k, $v) = explode('=', $pair, 2);
// Handle the case where multiple values map to the same key
// by pulling those values into an array themselves
if (isset($query_array[$k])) {
// If the existing value is a scalar, turn it into an array
if (is_scalar($query_array[$k])) {
$query_array[$k] = array($query_array[$k]);
}
array_push($query_array[$k], $v);
} else {
$query_array[$k] = $v;
}
}
}
return $query_array;
}
/**
* Build an OAuth header for API calls
* @param array $params an array of query parameters
* @return string encoded for insertion into HTTP header of API call
*/
function build_oauth_header($params, $realm='')
{
$header = 'Authorization: OAuth realm="' . $realm . '"';
foreach ($params as $k => $v) {
if (substr($k, 0, 5) == 'oauth') {
$header .= ',' . rfc3986_encode($k) . '="' . rfc3986_encode($v) . '"';
}
}
return $header;
}
/**
* Compute an OAuth PLAINTEXT signature
* @param string $consumer_secret
* @param string $token_secret
*/
function oauth_compute_plaintext_sig($consumer_secret, $token_secret)
{
return ($consumer_secret . '&' . $token_secret);
}
/**
* Compute an OAuth HMAC-SHA1 signature
* @param string $http_method GET, POST, etc.
* @param string $url
* @param array $params an array of query parameters for the request
* @param string $consumer_secret
* @param string $token_secret
* @return string a base64_encoded hmac-sha1 signature
* @see http://oauth.net/core/1.0/#rfc.section.A.5.1
*/
function oauth_compute_hmac_sig($http_method, $url, $params, $consumer_secret, $token_secret)
{
global $debug;
$base_string = signature_base_string($http_method, $url, $params);
$signature_key = rfc3986_encode($consumer_secret) . '&' . rfc3986_encode($token_secret);
$sig = base64_encode(hash_hmac('sha1', $base_string, $signature_key, true));
if ($debug) {
logit("oauth_compute_hmac_sig:DBG:sig:$sig");
}
return $sig;
}
/**
* Make the URL conform to the format scheme://host/path
* @param string $url
* @return string the url in the form of scheme://host/path
*/
function normalize_url($url)
{
$parts = parse_url($url);
$scheme = $parts['scheme'];
$host = $parts['host'];
$port = $parts['port'];
$path = $parts['path'];
if (! $port) {
$port = ($scheme == 'https') ? '443' : '80';
}
if (($scheme == 'https' && $port != '443')
|| ($scheme == 'http' && $port != '80')) {
$host = "$host:$port";
}
return "$scheme://$host$path";
}
/**
* Returns the normalized signature base string of this request
* @param string $http_method
* @param string $url
* @param array $params
* The base string is defined as the method, the url and the
* parameters (normalized), each urlencoded and the concated with &.
* @see http://oauth.net/core/1.0/#rfc.section.A.5.1
*/
function signature_base_string($http_method, $url, $params)
{
// Decompose and pull query params out of the url
$query_str = parse_url($url, PHP_URL_QUERY);
if ($query_str) {
$parsed_query = oauth_parse_str($query_str);
// merge params from the url with params array from caller
$params = array_merge($params, $parsed_query);
}
// Remove oauth_signature from params array if present
if (isset($params['oauth_signature'])) {
unset($params['oauth_signature']);
}
// Create the signature base string. Yes, the $params are double encoded.
$base_string = rfc3986_encode(strtoupper($http_method)) . '&' .
rfc3986_encode(normalize_url($url)) . '&' .
rfc3986_encode(oauth_http_build_query($params));
logit("signature_base_string:INFO:normalized_base_string:$base_string");
return $base_string;
}
/**
* Encode input per RFC 3986
* @param string|array $raw_input
* @return string|array properly rfc3986 encoded raw_input
* If an array is passed in, rfc3896 encode all elements of the array.
* @link http://oauth.net/core/1.0/#encoding_parameters
*/
function rfc3986_encode($raw_input)
{
if (is_array($raw_input)) {
return array_map('rfc3986_encode', $raw_input);
} else if (is_scalar($raw_input)) {
return str_replace('%7E', '~', rawurlencode($raw_input));
} else {
return '';
}
}
function rfc3986_decode($raw_input)
{
return rawurldecode($raw_input);
}
?>