facebook /
facebook-php-sdk-v4
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Copyright 2016 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 | */ |
||
| 24 | namespace Facebook\GraphNodes; |
||
| 25 | |||
| 26 | use Facebook\FacebookResponse; |
||
| 27 | use Facebook\Exceptions\FacebookSDKException; |
||
| 28 | |||
| 29 | /** |
||
| 30 | * Class GraphNodeFactory |
||
| 31 | * |
||
| 32 | * @package Facebook |
||
| 33 | * |
||
| 34 | * ## Assumptions ## |
||
| 35 | * GraphEdge - is ALWAYS a numeric array |
||
| 36 | * GraphEdge - is ALWAYS an array of GraphNode types |
||
| 37 | * GraphNode - is ALWAYS an associative array |
||
| 38 | * GraphNode - MAY contain GraphNode's "recurrable" |
||
| 39 | * GraphNode - MAY contain GraphEdge's "recurrable" |
||
| 40 | * GraphNode - MAY contain DateTime's "primitives" |
||
| 41 | * GraphNode - MAY contain string's "primitives" |
||
| 42 | */ |
||
| 43 | class GraphNodeFactory |
||
| 44 | { |
||
| 45 | /** |
||
| 46 | * @const string The base graph object class. |
||
| 47 | */ |
||
| 48 | const BASE_GRAPH_NODE_CLASS = '\Facebook\GraphNodes\GraphNode'; |
||
| 49 | |||
| 50 | /** |
||
| 51 | * @const string The base graph edge class. |
||
| 52 | */ |
||
| 53 | const BASE_GRAPH_EDGE_CLASS = '\Facebook\GraphNodes\GraphEdge'; |
||
| 54 | |||
| 55 | /** |
||
| 56 | * @const string The graph object prefix. |
||
| 57 | */ |
||
| 58 | const BASE_GRAPH_OBJECT_PREFIX = '\Facebook\GraphNodes\\'; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * @var FacebookResponse The response entity from Graph. |
||
| 62 | */ |
||
| 63 | protected $response; |
||
| 64 | |||
| 65 | /** |
||
| 66 | * @var array The decoded body of the FacebookResponse entity from Graph. |
||
| 67 | */ |
||
| 68 | protected $decodedBody; |
||
| 69 | |||
| 70 | /** |
||
| 71 | * Init this Graph object. |
||
| 72 | * |
||
| 73 | * @param FacebookResponse $response The response entity from Graph. |
||
| 74 | */ |
||
| 75 | public function __construct(FacebookResponse $response) |
||
| 76 | { |
||
| 77 | $this->response = $response; |
||
| 78 | $this->decodedBody = $response->getDecodedBody(); |
||
| 79 | } |
||
| 80 | |||
| 81 | /** |
||
| 82 | * Tries to convert a FacebookResponse entity into a GraphNode. |
||
| 83 | * |
||
| 84 | * @param string|null $subclassName The GraphNode sub class to cast to. |
||
| 85 | * |
||
| 86 | * @return GraphNode |
||
| 87 | * |
||
| 88 | * @throws FacebookSDKException |
||
| 89 | */ |
||
| 90 | public function makeGraphNode($subclassName = null) |
||
| 91 | { |
||
| 92 | $this->validateResponseAsArray(); |
||
| 93 | $this->validateResponseCastableAsGraphNode(); |
||
| 94 | |||
| 95 | return $this->castAsGraphNodeOrGraphEdge($this->decodedBody, $subclassName); |
||
|
0 ignored issues
–
show
Bug
Compatibility
introduced
by
Loading history...
|
|||
| 96 | } |
||
| 97 | |||
| 98 | /** |
||
| 99 | * Convenience method for creating a GraphAchievement collection. |
||
| 100 | * |
||
| 101 | * @return GraphAchievement |
||
| 102 | * |
||
| 103 | * @throws FacebookSDKException |
||
| 104 | */ |
||
| 105 | public function makeGraphAchievement() |
||
| 106 | { |
||
| 107 | return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphAchievement'); |
||
| 108 | } |
||
| 109 | |||
| 110 | /** |
||
| 111 | * Convenience method for creating a GraphAlbum collection. |
||
| 112 | * |
||
| 113 | * @return GraphAlbum |
||
| 114 | * |
||
| 115 | * @throws FacebookSDKException |
||
| 116 | */ |
||
| 117 | public function makeGraphAlbum() |
||
| 118 | { |
||
| 119 | return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphAlbum'); |
||
| 120 | } |
||
| 121 | |||
| 122 | /** |
||
| 123 | * Convenience method for creating a GraphPage collection. |
||
| 124 | * |
||
| 125 | * @return GraphPage |
||
| 126 | * |
||
| 127 | * @throws FacebookSDKException |
||
| 128 | */ |
||
| 129 | public function makeGraphPage() |
||
| 130 | { |
||
| 131 | return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphPage'); |
||
| 132 | } |
||
| 133 | |||
| 134 | /** |
||
| 135 | * Convenience method for creating a GraphSessionInfo collection. |
||
| 136 | * |
||
| 137 | * @return GraphSessionInfo |
||
| 138 | * |
||
| 139 | * @throws FacebookSDKException |
||
| 140 | */ |
||
| 141 | public function makeGraphSessionInfo() |
||
| 142 | { |
||
| 143 | return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphSessionInfo'); |
||
| 144 | } |
||
| 145 | |||
| 146 | /** |
||
| 147 | * Convenience method for creating a GraphUser collection. |
||
| 148 | * |
||
| 149 | * @return GraphUser |
||
| 150 | * |
||
| 151 | * @throws FacebookSDKException |
||
| 152 | */ |
||
| 153 | public function makeGraphUser() |
||
| 154 | { |
||
| 155 | return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphUser'); |
||
| 156 | } |
||
| 157 | |||
| 158 | /** |
||
| 159 | * Convenience method for creating a GraphEvent collection. |
||
| 160 | * |
||
| 161 | * @return GraphEvent |
||
| 162 | * |
||
| 163 | * @throws FacebookSDKException |
||
| 164 | */ |
||
| 165 | public function makeGraphEvent() |
||
| 166 | { |
||
| 167 | return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphEvent'); |
||
| 168 | } |
||
| 169 | |||
| 170 | /** |
||
| 171 | * Convenience method for creating a GraphGroup collection. |
||
| 172 | * |
||
| 173 | * @return GraphGroup |
||
| 174 | * |
||
| 175 | * @throws FacebookSDKException |
||
| 176 | */ |
||
| 177 | public function makeGraphGroup() |
||
| 178 | { |
||
| 179 | return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphGroup'); |
||
| 180 | } |
||
| 181 | |||
| 182 | /** |
||
| 183 | * Tries to convert a FacebookResponse entity into a GraphEdge. |
||
| 184 | * |
||
| 185 | * @param string|null $subclassName The GraphNode sub class to cast the list items to. |
||
| 186 | * @param boolean $auto_prefix Toggle to auto-prefix the subclass name. |
||
| 187 | * |
||
| 188 | * @return GraphEdge |
||
| 189 | * |
||
| 190 | * @throws FacebookSDKException |
||
| 191 | */ |
||
| 192 | public function makeGraphEdge($subclassName = null, $auto_prefix = true) |
||
| 193 | { |
||
| 194 | $this->validateResponseAsArray(); |
||
| 195 | $this->validateResponseCastableAsGraphEdge(); |
||
| 196 | |||
| 197 | if ($subclassName && $auto_prefix) { |
||
|
0 ignored issues
–
show
The expression
$subclassName of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
| 198 | $subclassName = static::BASE_GRAPH_OBJECT_PREFIX . $subclassName; |
||
| 199 | } |
||
| 200 | |||
| 201 | return $this->castAsGraphNodeOrGraphEdge($this->decodedBody, $subclassName); |
||
|
0 ignored issues
–
show
The expression
$this->castAsGraphNodeOr...edBody, $subclassName); of type Facebook\GraphNodes\Grap...ok\GraphNodes\GraphEdge adds the type Facebook\GraphNodes\GraphNode to the return on line 201 which is incompatible with the return type documented by Facebook\GraphNodes\Grap...eFactory::makeGraphEdge of type Facebook\GraphNodes\GraphEdge.
Loading history...
|
|||
| 202 | } |
||
| 203 | |||
| 204 | /** |
||
| 205 | * Validates the decoded body. |
||
| 206 | * |
||
| 207 | * @throws FacebookSDKException |
||
| 208 | */ |
||
| 209 | public function validateResponseAsArray() |
||
| 210 | { |
||
| 211 | if (!is_array($this->decodedBody)) { |
||
| 212 | throw new FacebookSDKException('Unable to get response from Graph as array.', 620); |
||
| 213 | } |
||
| 214 | } |
||
| 215 | |||
| 216 | /** |
||
| 217 | * Validates that the return data can be cast as a GraphNode. |
||
| 218 | * |
||
| 219 | * @throws FacebookSDKException |
||
| 220 | */ |
||
| 221 | View Code Duplication | public function validateResponseCastableAsGraphNode() |
|
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 222 | { |
||
| 223 | if (isset($this->decodedBody['data']) && static::isCastableAsGraphEdge($this->decodedBody['data'])) { |
||
| 224 | throw new FacebookSDKException( |
||
| 225 | 'Unable to convert response from Graph to a GraphNode because the response looks like a GraphEdge. Try using GraphNodeFactory::makeGraphEdge() instead.', |
||
| 226 | 620 |
||
| 227 | ); |
||
| 228 | } |
||
| 229 | } |
||
| 230 | |||
| 231 | /** |
||
| 232 | * Validates that the return data can be cast as a GraphEdge. |
||
| 233 | * |
||
| 234 | * @throws FacebookSDKException |
||
| 235 | */ |
||
| 236 | View Code Duplication | public function validateResponseCastableAsGraphEdge() |
|
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 237 | { |
||
| 238 | if (!(isset($this->decodedBody['data']) && static::isCastableAsGraphEdge($this->decodedBody['data']))) { |
||
| 239 | throw new FacebookSDKException( |
||
| 240 | 'Unable to convert response from Graph to a GraphEdge because the response does not look like a GraphEdge. Try using GraphNodeFactory::makeGraphNode() instead.', |
||
| 241 | 620 |
||
| 242 | ); |
||
| 243 | } |
||
| 244 | } |
||
| 245 | |||
| 246 | /** |
||
| 247 | * Safely instantiates a GraphNode of $subclassName. |
||
| 248 | * |
||
| 249 | * @param array $data The array of data to iterate over. |
||
| 250 | * @param string|null $subclassName The subclass to cast this collection to. |
||
| 251 | * |
||
| 252 | * @return GraphNode |
||
| 253 | * |
||
| 254 | * @throws FacebookSDKException |
||
| 255 | */ |
||
| 256 | public function safelyMakeGraphNode(array $data, $subclassName = null) |
||
| 257 | { |
||
| 258 | $subclassName = $subclassName ?: static::BASE_GRAPH_NODE_CLASS; |
||
| 259 | static::validateSubclass($subclassName); |
||
| 260 | |||
| 261 | // Remember the parent node ID |
||
| 262 | $parentNodeId = isset($data['id']) ? $data['id'] : null; |
||
| 263 | |||
| 264 | $items = []; |
||
| 265 | |||
| 266 | foreach ($data as $k => $v) { |
||
| 267 | // Array means could be recurable |
||
| 268 | if (is_array($v)) { |
||
| 269 | // Detect any smart-casting from the $graphObjectMap array. |
||
| 270 | // This is always empty on the GraphNode collection, but subclasses can define |
||
| 271 | // their own array of smart-casting types. |
||
| 272 | $graphObjectMap = $subclassName::getObjectMap(); |
||
| 273 | $objectSubClass = isset($graphObjectMap[$k]) |
||
| 274 | ? $graphObjectMap[$k] |
||
| 275 | : null; |
||
| 276 | |||
| 277 | // Could be a GraphEdge or GraphNode |
||
| 278 | $items[$k] = $this->castAsGraphNodeOrGraphEdge($v, $objectSubClass, $k, $parentNodeId); |
||
| 279 | } else { |
||
| 280 | $items[$k] = $v; |
||
| 281 | } |
||
| 282 | } |
||
| 283 | |||
| 284 | return new $subclassName($items); |
||
| 285 | } |
||
| 286 | |||
| 287 | /** |
||
| 288 | * Takes an array of values and determines how to cast each node. |
||
| 289 | * |
||
| 290 | * @param array $data The array of data to iterate over. |
||
| 291 | * @param string|null $subclassName The subclass to cast this collection to. |
||
| 292 | * @param string|null $parentKey The key of this data (Graph edge). |
||
| 293 | * @param string|null $parentNodeId The parent Graph node ID. |
||
| 294 | * |
||
| 295 | * @return GraphNode|GraphEdge |
||
| 296 | * |
||
| 297 | * @throws FacebookSDKException |
||
| 298 | */ |
||
| 299 | public function castAsGraphNodeOrGraphEdge(array $data, $subclassName = null, $parentKey = null, $parentNodeId = null) |
||
| 300 | { |
||
| 301 | if (isset($data['data'])) { |
||
| 302 | // Create GraphEdge |
||
| 303 | if (static::isCastableAsGraphEdge($data['data'])) { |
||
| 304 | return $this->safelyMakeGraphEdge($data, $subclassName, $parentKey, $parentNodeId); |
||
| 305 | } |
||
| 306 | // Sometimes Graph is a weirdo and returns a GraphNode under the "data" key |
||
| 307 | $data = $data['data']; |
||
| 308 | } |
||
| 309 | |||
| 310 | // Create GraphNode |
||
| 311 | return $this->safelyMakeGraphNode($data, $subclassName); |
||
| 312 | } |
||
| 313 | |||
| 314 | /** |
||
| 315 | * Return an array of GraphNode's. |
||
| 316 | * |
||
| 317 | * @param array $data The array of data to iterate over. |
||
| 318 | * @param string|null $subclassName The GraphNode subclass to cast each item in the list to. |
||
| 319 | * @param string|null $parentKey The key of this data (Graph edge). |
||
| 320 | * @param string|null $parentNodeId The parent Graph node ID. |
||
| 321 | * |
||
| 322 | * @return GraphEdge |
||
| 323 | * |
||
| 324 | * @throws FacebookSDKException |
||
| 325 | */ |
||
| 326 | public function safelyMakeGraphEdge(array $data, $subclassName = null, $parentKey = null, $parentNodeId = null) |
||
| 327 | { |
||
| 328 | if (!isset($data['data'])) { |
||
| 329 | throw new FacebookSDKException('Cannot cast data to GraphEdge. Expected a "data" key.', 620); |
||
| 330 | } |
||
| 331 | |||
| 332 | $dataList = []; |
||
| 333 | foreach ($data['data'] as $graphNode) { |
||
| 334 | $dataList[] = $this->safelyMakeGraphNode($graphNode, $subclassName); |
||
| 335 | } |
||
| 336 | |||
| 337 | $metaData = $this->getMetaData($data); |
||
| 338 | |||
| 339 | // We'll need to make an edge endpoint for this in case it's a GraphEdge (for cursor pagination) |
||
| 340 | $parentGraphEdgeEndpoint = $parentNodeId && $parentKey ? '/' . $parentNodeId . '/' . $parentKey : null; |
||
|
0 ignored issues
–
show
The expression
$parentNodeId of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
The expression
$parentKey of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
| 341 | $className = static::BASE_GRAPH_EDGE_CLASS; |
||
| 342 | |||
| 343 | return new $className($this->response->getRequest(), $dataList, $metaData, $parentGraphEdgeEndpoint, $subclassName); |
||
| 344 | } |
||
| 345 | |||
| 346 | /** |
||
| 347 | * Get the meta data from a list in a Graph response. |
||
| 348 | * |
||
| 349 | * @param array $data The Graph response. |
||
| 350 | * |
||
| 351 | * @return array |
||
| 352 | */ |
||
| 353 | public function getMetaData(array $data) |
||
| 354 | { |
||
| 355 | unset($data['data']); |
||
| 356 | |||
| 357 | return $data; |
||
| 358 | } |
||
| 359 | |||
| 360 | /** |
||
| 361 | * Determines whether or not the data should be cast as a GraphEdge. |
||
| 362 | * |
||
| 363 | * @param array $data |
||
| 364 | * |
||
| 365 | * @return boolean |
||
| 366 | */ |
||
| 367 | public static function isCastableAsGraphEdge(array $data) |
||
| 368 | { |
||
| 369 | if ($data === []) { |
||
| 370 | return true; |
||
| 371 | } |
||
| 372 | |||
| 373 | // Checks for a sequential numeric array which would be a GraphEdge |
||
| 374 | return array_keys($data) === range(0, count($data) - 1); |
||
| 375 | } |
||
| 376 | |||
| 377 | /** |
||
| 378 | * Ensures that the subclass in question is valid. |
||
| 379 | * |
||
| 380 | * @param string $subclassName The GraphNode subclass to validate. |
||
| 381 | * |
||
| 382 | * @throws FacebookSDKException |
||
| 383 | */ |
||
| 384 | public static function validateSubclass($subclassName) |
||
| 385 | { |
||
| 386 | if ($subclassName == static::BASE_GRAPH_NODE_CLASS || is_subclass_of($subclassName, static::BASE_GRAPH_NODE_CLASS)) { |
||
| 387 | return; |
||
| 388 | } |
||
| 389 | |||
| 390 | throw new FacebookSDKException('The given subclass "' . $subclassName . '" is not valid. Cannot cast to an object that is not a GraphNode subclass.', 620); |
||
| 391 | } |
||
| 392 | } |
||
| 393 |