1<?php 2/** 3 * Copyright 2017 Facebook, Inc. 4 * 5 * You are hereby granted a non-exclusive, worldwide, royalty-free license to 6 * use, copy, modify, and distribute this software in source code or binary 7 * form for use in connection with the web services and APIs provided by 8 * Facebook. 9 * 10 * As with any software that integrates with the Facebook platform, your use 11 * of this software is subject to the Facebook Developer Principles and 12 * Policies [http://developers.facebook.com/policy/]. This copyright notice 13 * shall be included in all copies or substantial portions of the software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 */ 24namespace Facebook; 25 26use Facebook\GraphNodes\GraphNodeFactory; 27use Facebook\Exceptions\FacebookResponseException; 28use Facebook\Exceptions\FacebookSDKException; 29 30/** 31 * Class FacebookResponse 32 * 33 * @package Facebook 34 */ 35class FacebookResponse 36{ 37 /** 38 * @var int The HTTP status code response from Graph. 39 */ 40 protected $httpStatusCode; 41 42 /** 43 * @var array The headers returned from Graph. 44 */ 45 protected $headers; 46 47 /** 48 * @var string The raw body of the response from Graph. 49 */ 50 protected $body; 51 52 /** 53 * @var array The decoded body of the Graph response. 54 */ 55 protected $decodedBody = []; 56 57 /** 58 * @var FacebookRequest The original request that returned this response. 59 */ 60 protected $request; 61 62 /** 63 * @var FacebookSDKException The exception thrown by this request. 64 */ 65 protected $thrownException; 66 67 /** 68 * Creates a new Response entity. 69 * 70 * @param FacebookRequest $request 71 * @param string|null $body 72 * @param int|null $httpStatusCode 73 * @param array|null $headers 74 */ 75 public function __construct(FacebookRequest $request, $body = null, $httpStatusCode = null, array $headers = []) 76 { 77 $this->request = $request; 78 $this->body = $body; 79 $this->httpStatusCode = $httpStatusCode; 80 $this->headers = $headers; 81 82 $this->decodeBody(); 83 } 84 85 /** 86 * Return the original request that returned this response. 87 * 88 * @return FacebookRequest 89 */ 90 public function getRequest() 91 { 92 return $this->request; 93 } 94 95 /** 96 * Return the FacebookApp entity used for this response. 97 * 98 * @return FacebookApp 99 */ 100 public function getApp() 101 { 102 return $this->request->getApp(); 103 } 104 105 /** 106 * Return the access token that was used for this response. 107 * 108 * @return string|null 109 */ 110 public function getAccessToken() 111 { 112 return $this->request->getAccessToken(); 113 } 114 115 /** 116 * Return the HTTP status code for this response. 117 * 118 * @return int 119 */ 120 public function getHttpStatusCode() 121 { 122 return $this->httpStatusCode; 123 } 124 125 /** 126 * Return the HTTP headers for this response. 127 * 128 * @return array 129 */ 130 public function getHeaders() 131 { 132 return $this->headers; 133 } 134 135 /** 136 * Return the raw body response. 137 * 138 * @return string 139 */ 140 public function getBody() 141 { 142 return $this->body; 143 } 144 145 /** 146 * Return the decoded body response. 147 * 148 * @return array 149 */ 150 public function getDecodedBody() 151 { 152 return $this->decodedBody; 153 } 154 155 /** 156 * Get the app secret proof that was used for this response. 157 * 158 * @return string|null 159 */ 160 public function getAppSecretProof() 161 { 162 return $this->request->getAppSecretProof(); 163 } 164 165 /** 166 * Get the ETag associated with the response. 167 * 168 * @return string|null 169 */ 170 public function getETag() 171 { 172 return isset($this->headers['ETag']) ? $this->headers['ETag'] : null; 173 } 174 175 /** 176 * Get the version of Graph that returned this response. 177 * 178 * @return string|null 179 */ 180 public function getGraphVersion() 181 { 182 return isset($this->headers['Facebook-API-Version']) ? $this->headers['Facebook-API-Version'] : null; 183 } 184 185 /** 186 * Returns true if Graph returned an error message. 187 * 188 * @return boolean 189 */ 190 public function isError() 191 { 192 return isset($this->decodedBody['error']); 193 } 194 195 /** 196 * Throws the exception. 197 * 198 * @throws FacebookSDKException 199 */ 200 public function throwException() 201 { 202 throw $this->thrownException; 203 } 204 205 /** 206 * Instantiates an exception to be thrown later. 207 */ 208 public function makeException() 209 { 210 $this->thrownException = FacebookResponseException::create($this); 211 } 212 213 /** 214 * Returns the exception that was thrown for this request. 215 * 216 * @return FacebookResponseException|null 217 */ 218 public function getThrownException() 219 { 220 return $this->thrownException; 221 } 222 223 /** 224 * Convert the raw response into an array if possible. 225 * 226 * Graph will return 2 types of responses: 227 * - JSON(P) 228 * Most responses from Graph are JSON(P) 229 * - application/x-www-form-urlencoded key/value pairs 230 * Happens on the `/oauth/access_token` endpoint when exchanging 231 * a short-lived access token for a long-lived access token 232 * - And sometimes nothing :/ but that'd be a bug. 233 */ 234 public function decodeBody() 235 { 236 $this->decodedBody = json_decode($this->body, true); 237 238 if ($this->decodedBody === null) { 239 $this->decodedBody = []; 240 parse_str($this->body, $this->decodedBody); 241 } elseif (is_bool($this->decodedBody)) { 242 // Backwards compatibility for Graph < 2.1. 243 // Mimics 2.1 responses. 244 // @TODO Remove this after Graph 2.0 is no longer supported 245 $this->decodedBody = ['success' => $this->decodedBody]; 246 } elseif (is_numeric($this->decodedBody)) { 247 $this->decodedBody = ['id' => $this->decodedBody]; 248 } 249 250 if (!is_array($this->decodedBody)) { 251 $this->decodedBody = []; 252 } 253 254 if ($this->isError()) { 255 $this->makeException(); 256 } 257 } 258 259 /** 260 * Instantiate a new GraphObject from response. 261 * 262 * @param string|null $subclassName The GraphNode subclass to cast to. 263 * 264 * @return \Facebook\GraphNodes\GraphObject 265 * 266 * @throws FacebookSDKException 267 * 268 * @deprecated 5.0.0 getGraphObject() has been renamed to getGraphNode() 269 * @todo v6: Remove this method 270 */ 271 public function getGraphObject($subclassName = null) 272 { 273 return $this->getGraphNode($subclassName); 274 } 275 276 /** 277 * Instantiate a new GraphNode from response. 278 * 279 * @param string|null $subclassName The GraphNode subclass to cast to. 280 * 281 * @return \Facebook\GraphNodes\GraphNode 282 * 283 * @throws FacebookSDKException 284 */ 285 public function getGraphNode($subclassName = null) 286 { 287 $factory = new GraphNodeFactory($this); 288 289 return $factory->makeGraphNode($subclassName); 290 } 291 292 /** 293 * Convenience method for creating a GraphAlbum collection. 294 * 295 * @return \Facebook\GraphNodes\GraphAlbum 296 * 297 * @throws FacebookSDKException 298 */ 299 public function getGraphAlbum() 300 { 301 $factory = new GraphNodeFactory($this); 302 303 return $factory->makeGraphAlbum(); 304 } 305 306 /** 307 * Convenience method for creating a GraphPage collection. 308 * 309 * @return \Facebook\GraphNodes\GraphPage 310 * 311 * @throws FacebookSDKException 312 */ 313 public function getGraphPage() 314 { 315 $factory = new GraphNodeFactory($this); 316 317 return $factory->makeGraphPage(); 318 } 319 320 /** 321 * Convenience method for creating a GraphSessionInfo collection. 322 * 323 * @return \Facebook\GraphNodes\GraphSessionInfo 324 * 325 * @throws FacebookSDKException 326 */ 327 public function getGraphSessionInfo() 328 { 329 $factory = new GraphNodeFactory($this); 330 331 return $factory->makeGraphSessionInfo(); 332 } 333 334 /** 335 * Convenience method for creating a GraphUser collection. 336 * 337 * @return \Facebook\GraphNodes\GraphUser 338 * 339 * @throws FacebookSDKException 340 */ 341 public function getGraphUser() 342 { 343 $factory = new GraphNodeFactory($this); 344 345 return $factory->makeGraphUser(); 346 } 347 348 /** 349 * Convenience method for creating a GraphEvent collection. 350 * 351 * @return \Facebook\GraphNodes\GraphEvent 352 * 353 * @throws FacebookSDKException 354 */ 355 public function getGraphEvent() 356 { 357 $factory = new GraphNodeFactory($this); 358 359 return $factory->makeGraphEvent(); 360 } 361 362 /** 363 * Convenience method for creating a GraphGroup collection. 364 * 365 * @return \Facebook\GraphNodes\GraphGroup 366 * 367 * @throws FacebookSDKException 368 */ 369 public function getGraphGroup() 370 { 371 $factory = new GraphNodeFactory($this); 372 373 return $factory->makeGraphGroup(); 374 } 375 376 /** 377 * Instantiate a new GraphList from response. 378 * 379 * @param string|null $subclassName The GraphNode subclass to cast list items to. 380 * @param boolean $auto_prefix Toggle to auto-prefix the subclass name. 381 * 382 * @return \Facebook\GraphNodes\GraphList 383 * 384 * @throws FacebookSDKException 385 * 386 * @deprecated 5.0.0 getGraphList() has been renamed to getGraphEdge() 387 * @todo v6: Remove this method 388 */ 389 public function getGraphList($subclassName = null, $auto_prefix = true) 390 { 391 return $this->getGraphEdge($subclassName, $auto_prefix); 392 } 393 394 /** 395 * Instantiate a new GraphEdge from response. 396 * 397 * @param string|null $subclassName The GraphNode subclass to cast list items to. 398 * @param boolean $auto_prefix Toggle to auto-prefix the subclass name. 399 * 400 * @return \Facebook\GraphNodes\GraphEdge 401 * 402 * @throws FacebookSDKException 403 */ 404 public function getGraphEdge($subclassName = null, $auto_prefix = true) 405 { 406 $factory = new GraphNodeFactory($this); 407 408 return $factory->makeGraphEdge($subclassName, $auto_prefix); 409 } 410} 411