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 | namespace Barracuda\Copy; |
||
4 | |||
5 | /** |
||
6 | * Copy API class |
||
7 | * |
||
8 | * @package Copy |
||
9 | * @license https://raw.github.com/copy-app/php-client-library/master/LICENSE MIT |
||
10 | */ |
||
11 | class API |
||
12 | { |
||
13 | /** |
||
14 | * API URl |
||
15 | * @var string $api_url |
||
16 | */ |
||
17 | protected $api_url = 'https://api.copy.com'; |
||
18 | |||
19 | /** |
||
20 | * Instance of curl |
||
21 | * @var resource $curl |
||
22 | */ |
||
23 | private $curl; |
||
24 | |||
25 | /** |
||
26 | * @var array |
||
27 | * User data |
||
28 | */ |
||
29 | private $signature; |
||
30 | |||
31 | /** |
||
32 | * Constructor |
||
33 | * |
||
34 | * @param string $consumerKey OAuth consumer key |
||
35 | * @param string $consumerSecret OAuth consumer secret |
||
36 | * @param string $accessToken OAuth access token |
||
37 | * @param string $tokenSecret OAuth token secret |
||
38 | */ |
||
39 | 12 | public function __construct($consumerKey, $consumerSecret, $accessToken, $tokenSecret) |
|
40 | { |
||
41 | // oauth setup |
||
42 | 12 | $this->signature = array( |
|
43 | 12 | 'consumer_key' => $consumerKey, |
|
44 | 12 | 'shared_secret' => $consumerSecret, |
|
45 | 12 | 'oauth_token' => $accessToken, |
|
46 | 'oauth_secret' => $tokenSecret |
||
47 | 12 | ); |
|
48 | |||
49 | 12 | $this->__wakeup(); |
|
50 | 12 | } |
|
51 | |||
52 | /** |
||
53 | * Wakeup function on unserialize |
||
54 | * |
||
55 | */ |
||
56 | 12 | private function __wakeup() |
|
57 | { |
||
58 | // curl setup |
||
59 | 12 | $this->curl = curl_init(); |
|
60 | 12 | if (!$this->curl) { |
|
61 | throw new \Exception("Failed to initialize curl"); |
||
62 | } |
||
63 | |||
64 | // ca bundle |
||
65 | 12 | $cacrt = __DIR__ . '/ca.crt'; |
|
66 | 12 | if (!is_file($cacrt)) { |
|
67 | throw new \Exception("Failed to load ca certificate"); |
||
68 | } |
||
69 | // check for phar execution |
||
70 | // in case we have to move the .crt file to a temp folder so curl is able to load it |
||
71 | 12 | if (substr(__FILE__, 0, 7) == 'phar://') { |
|
72 | $cacrt = self::extractPharCacert($cacrt); |
||
73 | } |
||
74 | 12 | curl_setopt($this->curl, CURLOPT_CAINFO, $cacrt); |
|
75 | 12 | } |
|
76 | |||
77 | /** |
||
78 | * Upload a file from a string |
||
79 | * |
||
80 | * @param string $path full path containing leading slash and file name |
||
81 | * @param string $data binary data |
||
82 | * |
||
83 | * @return object described in createFile() |
||
84 | */ |
||
85 | 1 | public function uploadFromString($path, $data) |
|
86 | { |
||
87 | // create the temporary stream |
||
88 | 1 | $stream = fopen('php://temp', 'w+'); |
|
89 | |||
90 | // write the data |
||
91 | 1 | fwrite($stream, $data); |
|
92 | |||
93 | // rewind the pointer |
||
94 | 1 | rewind($stream); |
|
95 | |||
96 | // upload as a stream |
||
97 | 1 | return $this->uploadFromStream($path, $stream); |
|
98 | } |
||
99 | |||
100 | /** |
||
101 | * Upload a file from a stream resource |
||
102 | * |
||
103 | * @param string $path full path containing leading slash and file name |
||
104 | * @param resource $stream resource to read data from |
||
105 | * |
||
106 | * @return object described in createFile() |
||
107 | */ |
||
108 | 1 | public function uploadFromStream($path, $stream) |
|
109 | { |
||
110 | // send data 1MB at a time |
||
111 | 1 | $parts = array(); |
|
112 | 1 | $limit = 1048576; |
|
113 | 1 | $buffer = ''; |
|
114 | 1 | while ($buffer .= fread($stream, $limit)) { |
|
115 | // check $buffer size for remote stream |
||
116 | // ref. http://php.net/manual/function.fread.php |
||
117 | // see Example #3 Remote fread() examples |
||
118 | 1 | if (!feof($stream) && strlen($buffer) < $limit) { |
|
119 | continue; |
||
120 | } |
||
121 | 1 | $next = ''; |
|
122 | 1 | if (strlen($buffer) > $limit) { |
|
123 | $next = substr($buffer, $limit); |
||
124 | $buffer = substr($buffer, 0, $limit); |
||
125 | } |
||
126 | 1 | $parts[] = $this->sendData($buffer); |
|
127 | 1 | $buffer = $next; |
|
128 | 1 | } |
|
129 | |||
130 | // close the stream |
||
131 | 1 | fclose($stream); |
|
132 | |||
133 | // update the file in the cloud |
||
134 | 1 | return $this->createFile('/' . $path, $parts); |
|
135 | } |
||
136 | |||
137 | /** |
||
138 | * Read a file to a string |
||
139 | * |
||
140 | * @param string $path full path containing leading slash and file name |
||
141 | * |
||
142 | * @return array contains key of contents which contains binary data of the file |
||
143 | */ |
||
144 | 1 | public function readToString($path) |
|
145 | { |
||
146 | 1 | $object = $this->readToStream($path); |
|
147 | 1 | $object['contents'] = stream_get_contents($object['stream']); |
|
148 | 1 | fclose($object['stream']); |
|
149 | 1 | unset($object['stream']); |
|
150 | |||
151 | 1 | return $object; |
|
152 | } |
||
153 | |||
154 | /** |
||
155 | * Read a file to a stream |
||
156 | * |
||
157 | * @param string $path full path containing leading slash and file name |
||
158 | * |
||
159 | * @return array contains key of stream which contains a stream resource |
||
160 | */ |
||
161 | 1 | public function readToStream($path) |
|
162 | { |
||
163 | // create the temporary stream |
||
164 | 1 | $stream = fopen('php://temp', 'w+'); |
|
165 | |||
166 | // obtain the list of parts for the file (should be an array of one) |
||
167 | 1 | $files = $this->listPath('/' . $path, array('include_parts' => true)); |
|
168 | |||
169 | 1 | if (is_array($files) === false || sizeof($files) !== 1) { |
|
170 | throw new \Exception("Could not find file at path: '" . $path . "'"); |
||
171 | } |
||
172 | |||
173 | // found it, verify its a file |
||
174 | 1 | $file = array_pop($files); |
|
175 | 1 | if ($file->{"type"} != "file") { |
|
176 | throw new \Exception("Could not find file at path: '" . $path . "'"); |
||
177 | } |
||
178 | |||
179 | // obtain each part and add it to the stream |
||
180 | 1 | foreach ($file->{"revisions"}[0]->{"parts"} as $part) { |
|
181 | 1 | $data = $this->getPart($part->{"fingerprint"}, $part->{"size"}, $file->{"share_id"}); |
|
182 | 1 | fwrite($stream, $data); |
|
183 | 1 | } |
|
184 | |||
185 | // rewind the pointer |
||
186 | 1 | rewind($stream); |
|
187 | |||
188 | 1 | return compact('stream'); |
|
189 | } |
||
190 | |||
191 | /** |
||
192 | * Send a request to remove a given file. |
||
193 | * |
||
194 | * @param string $path full path containing leading slash and file name |
||
195 | * |
||
196 | * @return bool true if the file was removed successfully |
||
197 | */ |
||
198 | 2 | public function removeFile($path) |
|
199 | { |
||
200 | 2 | return $this->removeItem($path, 'file'); |
|
201 | } |
||
202 | |||
203 | /** |
||
204 | * Send a request to remove a given dir. |
||
205 | * |
||
206 | * @param string $path full path containing leading slash and dir name |
||
207 | * |
||
208 | * @return bool true if the dir was removed successfully |
||
209 | */ |
||
210 | 1 | public function removeDir($path) |
|
211 | { |
||
212 | 1 | return $this->removeItem($path, 'dir'); |
|
213 | } |
||
214 | |||
215 | /** |
||
216 | * Send a request to remove a given item. |
||
217 | * |
||
218 | * @param string $path full path containing leading slash and file name |
||
219 | * @param string $type file or dir |
||
220 | * |
||
221 | * @return bool true if the item was removed successfully |
||
222 | */ |
||
223 | 3 | private function removeItem($path, $type) |
|
224 | { |
||
225 | 3 | $request = array(); |
|
226 | 3 | $request["object_type"] = $type; |
|
227 | |||
228 | 3 | $this->updateObject('remove', $path, $request); |
|
229 | |||
230 | 3 | return true; |
|
231 | } |
||
232 | |||
233 | /** |
||
234 | * Rename a file |
||
235 | * |
||
236 | * Object structure: |
||
237 | * { |
||
238 | * object_id: "4008" |
||
239 | * path: "/example" |
||
240 | * type: "dir" || "file" |
||
241 | * share_id: "0" |
||
242 | * share_owner: "21956799" |
||
243 | * company_id: NULL |
||
244 | * size: filesize in bytes, 0 for folders |
||
245 | * created_time: unix timestamp, e.g. "1389731126" |
||
246 | * modified_time: unix timestamp, e.g. "1389731126" |
||
247 | * date_last_synced: unix timestamp, e.g. "1389731126" |
||
248 | * removed_time: unix timestamp, e.g. "1389731126" or empty string for non-deleted files/folders |
||
249 | * mime_type: string |
||
250 | * revisions: array of revision objects |
||
251 | * } |
||
252 | * |
||
253 | * @param string $source_path full path containing leading slash and file name |
||
254 | * @param string $destination_path full path containing leading slash and file name |
||
255 | * |
||
256 | * @return stdClass using structure as noted above |
||
257 | */ |
||
258 | 1 | public function rename($source_path, $destination_path) |
|
259 | { |
||
260 | 1 | return $this->updateObject('rename', $source_path, array('new_path' => $destination_path)); |
|
261 | } |
||
262 | |||
263 | /** |
||
264 | * Copy an item |
||
265 | * |
||
266 | * Object structure: |
||
267 | * { |
||
268 | * object_id: "4008" |
||
269 | * path: "/example" |
||
270 | * type: "dir" || "file" |
||
271 | * share_id: "0" |
||
272 | * share_owner: "21956799" |
||
273 | * company_id: NULL |
||
274 | * size: filesize in bytes, 0 for folders |
||
275 | * created_time: unix timestamp, e.g. "1389731126" |
||
276 | * modified_time: unix timestamp, e.g. "1389731126" |
||
277 | * date_last_synced: unix timestamp, e.g. "1389731126" |
||
278 | * removed_time: unix timestamp, e.g. "1389731126" or empty string for non-deleted files/folders |
||
279 | * mime_type: string |
||
280 | * revisions: array of revision objects |
||
281 | * } |
||
282 | * |
||
283 | * @param string $source_path full path containing leading slash and file name |
||
284 | * @param string $destination_path full path containing leading slash and file name |
||
285 | * |
||
286 | * @return stdClass using structure as noted above |
||
287 | */ |
||
288 | 1 | public function copy($source_path, $destination_path) |
|
289 | { |
||
290 | 1 | return $this->updateObject('copy', $source_path, array('new_path' => $destination_path)); |
|
291 | } |
||
292 | |||
293 | /** |
||
294 | * List objects within a path |
||
295 | * |
||
296 | * Object structure: |
||
297 | * { |
||
298 | * object_id: "4008" |
||
299 | * path: "/example" |
||
300 | * type: "dir" || "file" |
||
301 | * share_id: "0" |
||
302 | * share_owner: "21956799" |
||
303 | * company_id: NULL |
||
304 | * size: filesize in bytes, 0 for folders |
||
305 | * created_time: unix timestamp, e.g. "1389731126" |
||
306 | * modified_time: unix timestamp, e.g. "1389731126" |
||
307 | * date_last_synced: unix timestamp, e.g. "1389731126" |
||
308 | * removed_time: unix timestamp, e.g. "1389731126" or empty string for non-deleted files/folders |
||
309 | * mime_type: string |
||
310 | * revisions: array of revision objects |
||
311 | * } |
||
312 | * |
||
313 | * @param string $path full path with leading slash and optionally a filename |
||
314 | * @param array $additionalOptions used for passing options such as include_parts |
||
315 | * |
||
316 | * @return array List of file/folder objects described above. |
||
317 | */ |
||
318 | 3 | public function listPath($path, $additionalOptions = null) |
|
319 | { |
||
320 | 3 | $list_watermark = false; |
|
321 | 3 | $return = array(); |
|
322 | |||
323 | do { |
||
324 | 3 | $request = array(); |
|
325 | 3 | $request["path"] = $path; |
|
326 | 3 | $request["max_items"] = 100; |
|
327 | 3 | $request["list_watermark"] = $list_watermark; |
|
328 | |||
329 | 3 | if ($additionalOptions) { |
|
330 | 2 | $request = array_merge($request, $additionalOptions); |
|
331 | 2 | } |
|
332 | |||
333 | 3 | $result = $this->post("list_objects", $this->encodeRequest("list_objects", $request), true); |
|
334 | |||
335 | // add the children if we got some, otherwise add the root object itself to the return |
||
336 | 3 | if (isset($result->result->children) && empty($result->result->children) === false) { |
|
337 | 1 | $return = array_merge($return, $result->result->children); |
|
338 | 1 | $list_watermark = $result->result->list_watermark; |
|
339 | 1 | } else { |
|
340 | 2 | $return[] = $result->result->object; |
|
341 | } |
||
342 | 3 | } while (isset($result->result->more_items) && $result->result->more_items == 1); |
|
343 | |||
344 | 3 | return $return; |
|
345 | } |
||
346 | |||
347 | /** |
||
348 | * Get directory or file meta data |
||
349 | * |
||
350 | * Object structure: |
||
351 | * { |
||
352 | * id: "/copy/example" |
||
353 | * path: "/example" |
||
354 | * name: "example", |
||
355 | * type: "dir" || "file" |
||
356 | * share_id: "0" |
||
357 | * share_owner: "21956799" |
||
358 | * company_id: NULL |
||
359 | * size: filesize in bytes, 0 for folders |
||
360 | * created_time: unix timestamp, e.g. "1389731126" |
||
361 | * modified_time: unix timestamp, e.g. "1389731126" |
||
362 | * date_last_synced: unix timestamp, e.g. "1389731126" |
||
363 | * removed_time: unix timestamp, e.g. "1389731126" or empty string for non-deleted files/folders |
||
364 | * mime_type: string |
||
365 | * revisions: array of revision objects |
||
366 | * children: array of children objects |
||
367 | * } |
||
368 | * |
||
369 | * @param string $path full path with leading slash and optionally a filename |
||
370 | * @param string $root Optional, "copy" is the first level of the real filesystem |
||
371 | * |
||
372 | * @return array List of file/folder objects described above. |
||
373 | */ |
||
374 | 1 | public function getMeta($path, $root = "copy") |
|
375 | { |
||
376 | 1 | $result = $this->get("meta/" . $root . $path); |
|
377 | |||
378 | // Decode the json reply |
||
379 | 1 | $result = json_decode($result); |
|
380 | |||
381 | // Check for errors |
||
382 | 1 | View Code Duplication | if (isset($result->error)) { |
0 ignored issues
–
show
|
|||
383 | if ($result->error == 1301) { |
||
384 | // item not found |
||
385 | return array(); |
||
386 | } |
||
387 | throw new \Exception("Error listing path " . $path . ": (" . $result->error . ") '" . $result->message . "'"); |
||
388 | } |
||
389 | |||
390 | 1 | return $result; |
|
391 | } |
||
392 | |||
393 | /** |
||
394 | * Create a dir |
||
395 | * |
||
396 | * Object structure: |
||
397 | * { |
||
398 | * object_id: "4008" |
||
399 | * path: "/example" |
||
400 | * type: "dir" |
||
401 | * share_id: "0" |
||
402 | * share_owner: "21956799" |
||
403 | * company_id: NULL |
||
404 | * size: filesize in bytes, 0 for folders |
||
405 | * created_time: unix timestamp, e.g. "1389731126" |
||
406 | * modified_time: unix timestamp, e.g. "1389731126" |
||
407 | * date_last_synced: unix timestamp, e.g. "1389731126" |
||
408 | * removed_time: unix timestamp, e.g. "1389731126" or empty string for non-deleted files/folders |
||
409 | * } |
||
410 | * |
||
411 | * @param string $path full path containing leading slash and dir name |
||
412 | * @param bool $recursive true to create parent directories |
||
413 | * |
||
414 | * @return object described above. |
||
415 | */ |
||
416 | 1 | public function createDir($path, $recursive = true) |
|
417 | { |
||
418 | $request = array( |
||
419 | 1 | 'object_type' => 'dir', |
|
420 | 1 | 'recurse' => $recursive, |
|
421 | 1 | ); |
|
422 | |||
423 | 1 | return $this->updateObject('create', $path, $request); |
|
424 | } |
||
425 | |||
426 | /** |
||
427 | * Create a file with a set of data parts |
||
428 | * |
||
429 | * Object structure: |
||
430 | * { |
||
431 | * object_id: "4008" |
||
432 | * path: "/example" |
||
433 | * type: "file" |
||
434 | * share_id: "0" |
||
435 | * share_owner: "21956799" |
||
436 | * company_id: NULL |
||
437 | * size: filesize in bytes, 0 for folders |
||
438 | * created_time: unix timestamp, e.g. "1389731126" |
||
439 | * modified_time: unix timestamp, e.g. "1389731126" |
||
440 | * date_last_synced: unix timestamp, e.g. "1389731126" |
||
441 | * removed_time: unix timestamp, e.g. "1389731126" or empty string for non-deleted files/folders |
||
442 | * mime_type: string |
||
443 | * revisions: array of revision objects |
||
444 | * } |
||
445 | * |
||
446 | * @param string $path full path containing leading slash and file name |
||
447 | * @param array $parts contains arrays of parts returned by \Barracuda\Copy\API\sendData |
||
448 | * |
||
449 | * @return object described above. |
||
450 | */ |
||
451 | 2 | public function createFile($path, $parts) |
|
452 | { |
||
453 | 2 | $request = array(); |
|
454 | 2 | $request["object_type"] = "file"; |
|
455 | 2 | $request["parts"] = array(); |
|
456 | |||
457 | 2 | $offset = 0; |
|
458 | 2 | foreach ($parts as $part) { |
|
459 | $partRequest = array( |
||
460 | 2 | 'fingerprint' => $part["fingerprint"], |
|
461 | 2 | 'offset' => $offset, |
|
462 | 2 | 'size' => $part["size"], |
|
463 | 2 | ); |
|
464 | |||
465 | 2 | array_push($request["parts"], $partRequest); |
|
466 | |||
467 | 2 | $offset += $part["size"]; |
|
468 | 2 | } |
|
469 | |||
470 | 2 | $request["size"] = $offset; |
|
471 | |||
472 | 2 | return $this->updateObject('create', $path, $request); |
|
473 | } |
||
474 | |||
475 | /** |
||
476 | * Generate the fingerprint for a string of data. |
||
477 | * |
||
478 | * @param string $data Data part to generate the fingerprint for. |
||
479 | * |
||
480 | * @return string Fingerprint for $data. |
||
481 | **/ |
||
482 | 2 | public function fingerprint($data) |
|
483 | { |
||
484 | 2 | return md5($data) . sha1($data); |
|
485 | } |
||
486 | |||
487 | /** |
||
488 | * Send a piece of data |
||
489 | * |
||
490 | * @param string $data binary data |
||
491 | * @param int $shareId setting this to zero is best, unless share id is known |
||
492 | * |
||
493 | * @return array contains fingerprint and size, to be used when creating a file |
||
494 | */ |
||
495 | 2 | public function sendData($data, $shareId = 0) |
|
496 | { |
||
497 | // first generate a part hash |
||
498 | 2 | $fingerprint = $this->fingerprint($data); |
|
499 | 2 | $part_size = strlen($data); |
|
500 | |||
501 | // see if the cloud has this part, and send if needed |
||
502 | 2 | if(!$this->hasPart($fingerprint, $part_size, $shareId)) { |
|
503 | 1 | $this->sendPart($fingerprint, $part_size, $data, $shareId); |
|
504 | 1 | } |
|
505 | |||
506 | // return information about this part |
||
507 | 2 | return array("fingerprint" => $fingerprint, "size" => $part_size); |
|
508 | } |
||
509 | |||
510 | /** |
||
511 | * Send a data part |
||
512 | * |
||
513 | * @param string $fingerprint md5 and sha1 concatenated |
||
514 | * @param int $size number of bytes |
||
515 | * @param string $data binary data |
||
516 | * @param int $shareId setting this to zero is best, unless share id is known |
||
517 | * |
||
518 | */ |
||
519 | 1 | public function sendPart($fingerprint, $size, $data, $shareId = 0) |
|
520 | { |
||
521 | // They must match |
||
522 | 1 | if (md5($data) . sha1($data) != $fingerprint) { |
|
523 | throw new \Exception("Failed to validate part hash"); |
||
524 | } |
||
525 | |||
526 | $request = array( |
||
527 | 'parts' => array( |
||
528 | array( |
||
529 | 1 | 'share_id' => $shareId, |
|
530 | 1 | 'fingerprint' => $fingerprint, |
|
531 | 1 | 'size' => $size, |
|
532 | 'data' => 'BinaryData-0-' . $size |
||
533 | 1 | ) |
|
534 | 1 | ) |
|
535 | 1 | ); |
|
536 | |||
537 | 1 | $result = $this->post("send_object_parts_v2", $this->encodeRequest("send_object_parts_v2", $request) . chr(0) . $data, true); |
|
538 | |||
539 | 1 | if ($result->result->has_failed_parts) { |
|
540 | throw new \Exception("Error sending part: " . $result->result->failed_parts[0]->message); |
||
541 | } |
||
542 | 1 | } |
|
543 | |||
544 | /** |
||
545 | * Check to see if a part already exists |
||
546 | * |
||
547 | * @param string $fingerprint md5 and sha1 concatenated |
||
548 | * @param int $size number of bytes |
||
549 | * @param int $shareId setting this to zero is best, unless share id is known |
||
550 | * @return bool true if part already exists |
||
551 | */ |
||
552 | 2 | public function hasPart($fingerprint, $size, $shareId = 0) |
|
553 | { |
||
554 | $request = array( |
||
555 | 'parts' => array( |
||
556 | array( |
||
557 | 2 | 'share_id' => $shareId, |
|
558 | 2 | 'fingerprint' => $fingerprint, |
|
559 | 'size' => $size |
||
560 | 2 | ) |
|
561 | 2 | ) |
|
562 | 2 | ); |
|
563 | |||
564 | 2 | $result = $this->post("has_object_parts_v2", $this->encodeRequest("has_object_parts_v2", $request), true); |
|
565 | |||
566 | 2 | if (empty($result->result->needed_parts)) { |
|
567 | 1 | return true; |
|
568 | } else { |
||
569 | 1 | $part = $result->result->needed_parts[0]; |
|
570 | 1 | if (!empty($part->message)) { |
|
571 | throw new \Exception("Error checking for part: " . $part->message); |
||
572 | } else { |
||
573 | 1 | return false; |
|
574 | } |
||
575 | } |
||
576 | } |
||
577 | |||
578 | /** |
||
579 | * Get a part |
||
580 | * |
||
581 | * @param string $fingerprint md5 and sha1 concatinated |
||
582 | * @param int $size number of bytes |
||
583 | * @param int $shareId setting this to zero is best, unless share id is known |
||
584 | * |
||
585 | * @return string binary data |
||
586 | */ |
||
587 | 2 | public function getPart($fingerprint, $size, $shareId = 0) |
|
588 | { |
||
589 | $request = array( |
||
590 | 'parts' => array( |
||
591 | array( |
||
592 | 2 | 'share_id' => $shareId, |
|
593 | 2 | 'fingerprint' => $fingerprint, |
|
594 | 'size' => $size |
||
595 | 2 | ) |
|
596 | 2 | ) |
|
597 | 2 | ); |
|
598 | |||
599 | 2 | $result = $this->post("get_object_parts_v2", $this->encodeRequest("get_object_parts_v2", $request)); |
|
600 | |||
601 | // Find the null byte |
||
602 | 2 | $null_offset = strpos($result, chr(0)); |
|
603 | |||
604 | // Grab the binary payload |
||
605 | 2 | $binary = substr($result, $null_offset + 1, strlen($result) - $null_offset); |
|
606 | |||
607 | 2 | if ($binary === false) { |
|
608 | throw new \Exception("Error getting part data"); |
||
609 | } |
||
610 | |||
611 | // Grab the json payload |
||
612 | 2 | $json = isset($binary) ? substr($result, 0, $null_offset) : $result; |
|
613 | |||
614 | 2 | if ($json === false) { |
|
615 | throw new \Exception("Error getting part data"); |
||
616 | } |
||
617 | |||
618 | // Decode the json reply |
||
619 | 2 | $result = json_decode($json); |
|
620 | |||
621 | // Check for errors |
||
622 | 2 | if (isset($result->error)) { |
|
623 | throw new \Exception("Error getting part data"); |
||
624 | } |
||
625 | |||
626 | 2 | if (isset($result->result->parts[0]->message)) { |
|
627 | throw new \Exception("Error getting part data: " . $result->result->parts[0]->message); |
||
628 | } |
||
629 | |||
630 | // Get the part data (since there is only one part the binary payload should just be the data) |
||
631 | 2 | if (strlen($binary) != $size) { |
|
632 | throw new \Exception("Error getting part data"); |
||
633 | } |
||
634 | |||
635 | 2 | return $binary; |
|
636 | } |
||
637 | |||
638 | /** |
||
639 | * Create a New Link |
||
640 | * |
||
641 | * Object structure: |
||
642 | * { |
||
643 | * id: "MBrss3roGDk4", |
||
644 | * name: "My Cool Shared Files", |
||
645 | * public: true, |
||
646 | * url: "https://copy.com/MBrss3roGDk4", |
||
647 | * url_short: "https://copy.com/MBrss3roGDk4", |
||
648 | * creator_id: "1381231", |
||
649 | * company_id: null, |
||
650 | * confirmation_required: false, |
||
651 | * status: "viewed", |
||
652 | * permissions: "read" |
||
653 | * } |
||
654 | * |
||
655 | * @param array|string $paths target item(s) path |
||
656 | * @param array $options option attributes, (bool) "public", (string) "name" |
||
657 | * @param string $root |
||
658 | * |
||
659 | * @throws \Exception |
||
660 | * |
||
661 | * @return object described above. |
||
662 | */ |
||
663 | 1 | public function createLink($paths, $options = array(), $root = 'copy') |
|
664 | { |
||
665 | 1 | if (is_string($paths)) { |
|
666 | 1 | $paths = array($paths); |
|
667 | 1 | } |
|
668 | $paths = array_map(function($p) use ($root){return '/' . $root . $p;}, $paths); |
||
669 | |||
670 | 1 | $data = array("paths" => $paths); |
|
671 | 1 | $data = array_merge($data, $options); |
|
672 | |||
673 | 1 | $result = $this->post("links", $data); |
|
674 | |||
675 | // Decode the json reply |
||
676 | 1 | $result = json_decode($result); |
|
677 | |||
678 | // Check for errors |
||
679 | 1 | View Code Duplication | if (isset($result->error)) { |
0 ignored issues
–
show
This code seems to be duplicated across 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. ![]() |
|||
680 | throw new \Exception("Error creating link for paths " . implode(', ', $paths) . ": (" . $result->error . ") '" . $result->message . "'"); |
||
681 | } |
||
682 | |||
683 | 1 | return $result; |
|
684 | } |
||
685 | |||
686 | /** |
||
687 | * Update meta object |
||
688 | * |
||
689 | * Object structure: |
||
690 | * { |
||
691 | * object_id: "4008" |
||
692 | * path: "/example" |
||
693 | * type: "dir" || "file" |
||
694 | * share_id: "0" |
||
695 | * share_owner: "21956799" |
||
696 | * company_id: NULL |
||
697 | * size: filesize in bytes, 0 for folders |
||
698 | * created_time: unix timestamp, e.g. "1389731126" |
||
699 | * modified_time: unix timestamp, e.g. "1389731126" |
||
700 | * date_last_synced: unix timestamp, e.g. "1389731126" |
||
701 | * removed_time: unix timestamp, e.g. "1389731126" or empty string for non-deleted files/folders |
||
702 | * mime_type: string |
||
703 | * revisions: array of revision objects |
||
704 | * } |
||
705 | * |
||
706 | * @param string $action |
||
707 | * @param string $path |
||
708 | * @param array $meta contains action, path, and other attributes of the object to update |
||
709 | * |
||
710 | * @return stdClass using structure as noted above |
||
711 | */ |
||
712 | 8 | private function updateObject($action, $path, $meta) |
|
713 | { |
||
714 | // Add action and path to meta |
||
715 | 8 | $meta["action"] = $action; |
|
716 | 8 | $meta["path"] = $path; |
|
717 | |||
718 | 8 | $result = $this->post("update_objects", $this->encodeRequest("update_objects", array("meta" => array($meta))), true); |
|
719 | |||
720 | // Return the object |
||
721 | 8 | return $result->{"result"}[0]->{"object"}; |
|
722 | } |
||
723 | |||
724 | /** |
||
725 | * Create and execute cURL request to send data. |
||
726 | * |
||
727 | * @param string $method API method |
||
728 | * @param string $data raw request |
||
729 | * @param boolean $decodeResponse true to decode response |
||
730 | * |
||
731 | * @return mixed result from curl_exec |
||
732 | */ |
||
733 | 11 | private function post($method, $data, $decodeResponse = false) |
|
734 | { |
||
735 | 11 | if (is_array($data)) { |
|
736 | 1 | $data = str_replace('\\/', '/', json_encode($data)); |
|
737 | 1 | } |
|
738 | |||
739 | 11 | curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, "POST"); |
|
740 | 11 | curl_setopt($this->curl, CURLOPT_POSTFIELDS, $data); |
|
741 | 11 | curl_setopt($this->curl, CURLOPT_HTTPHEADER, $this->getHeaders($method)); |
|
742 | 11 | curl_setopt($this->curl, CURLOPT_URL, $this->api_url . "/" . $this->getEndpoint($method)); |
|
743 | 11 | curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); |
|
744 | 11 | curl_setopt($this->curl, CURLOPT_POST, 1); |
|
745 | |||
746 | 11 | $result = curl_exec($this->curl); |
|
747 | |||
748 | // If curl grossly failed, throw |
||
749 | 11 | if ($result === false) { |
|
750 | throw new \Exception("Curl failed to exec " . curl_error($this->curl)); |
||
751 | } |
||
752 | |||
753 | // Decode the response if requested to do so |
||
754 | 11 | if ($decodeResponse) { |
|
755 | 10 | return $this->decodeResponse($result); |
|
756 | } else { |
||
757 | 3 | return $result; |
|
758 | } |
||
759 | } |
||
760 | |||
761 | /** |
||
762 | * Create and execute cURL request by GET method. |
||
763 | * |
||
764 | * @param string $method API method |
||
765 | * |
||
766 | * @return mixed result from curl_exec |
||
767 | */ |
||
768 | 1 | protected function get($method) |
|
769 | { |
||
770 | 1 | $method = str_replace("%2F", "/", rawurlencode($method)); |
|
771 | 1 | curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, "GET"); |
|
772 | 1 | curl_setopt($this->curl, CURLOPT_POSTFIELDS, null); |
|
773 | 1 | curl_setopt($this->curl, CURLOPT_HTTPHEADER, $this->getHeaders($method, "GET")); |
|
774 | 1 | curl_setopt($this->curl, CURLOPT_URL, $this->api_url . "/" . $this->GetEndpoint($method)); |
|
775 | 1 | curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); |
|
776 | 1 | curl_setopt($this->curl, CURLOPT_HTTPGET, 1); |
|
777 | |||
778 | 1 | $result = curl_exec($this->curl); |
|
779 | |||
780 | // If curl grossly failed, throw |
||
781 | 1 | if ($result == FALSE) { |
|
782 | throw new \Exception("Curl failed to exec " . curl_error($this->curl)); |
||
783 | } |
||
784 | |||
785 | 1 | return $result; |
|
786 | } |
||
787 | |||
788 | /** |
||
789 | * Return which cloud API end point to use for a given method. |
||
790 | * |
||
791 | * @param string $method API method |
||
792 | * |
||
793 | * @return string uri of endpoint without leading slash |
||
794 | */ |
||
795 | 12 | private function getEndpoint($method) |
|
796 | { |
||
797 | 12 | if ($method == "has_object_parts_v2" || $method == "send_object_parts_v2" || $method == "get_object_parts_v2") { |
|
798 | 4 | return "jsonrpc_binary"; |
|
799 | 12 | } else if ($method == "update_objects" || $method == "list_objects") { |
|
800 | 10 | return "jsonrpc"; |
|
801 | } else { |
||
802 | 2 | return "rest/" . $method; |
|
803 | } |
||
804 | } |
||
805 | |||
806 | /** |
||
807 | * Generate the HTTP headers need for a given Cloud API method. |
||
808 | * |
||
809 | * @param string $method API method |
||
810 | * @param string $http_method Optional, HTTP request method |
||
811 | * |
||
812 | * @return array contains headers to use for HTTP requests |
||
813 | */ |
||
814 | 12 | public function getHeaders($method, $http_method = "POST") |
|
815 | { |
||
816 | 12 | $headers = array(); |
|
817 | |||
818 | 12 | $consumer = new \Eher\OAuth\Consumer($this->signature['consumer_key'], $this->signature['shared_secret']); |
|
819 | 12 | $signatureMethod = new \Eher\OAuth\HmacSha1(); |
|
820 | 12 | $token = new \Eher\OAuth\Token($this->signature['oauth_token'], $this->signature['oauth_secret']); |
|
821 | 12 | $request = \Eher\OAuth\Request::from_consumer_and_token( |
|
822 | 12 | $consumer, |
|
823 | 12 | $token, |
|
824 | 12 | $http_method, |
|
825 | 12 | $this->api_url . "/" . $this->GetEndpoint($method), |
|
826 | 12 | array() |
|
827 | 12 | ); |
|
828 | 12 | $request->sign_request($signatureMethod, $consumer, $token); |
|
829 | |||
830 | 12 | if ($method == "has_object_parts_v2" || $method == "send_object_parts_v2" || $method == "get_object_parts_v2") { |
|
831 | 4 | array_push($headers, "Content-Type: application/octet-stream"); |
|
832 | 4 | } |
|
833 | |||
834 | 12 | array_push($headers, "X-Api-Version: 1.0"); |
|
835 | 12 | array_push($headers, "X-Client-Type: api"); |
|
836 | 12 | array_push($headers, "X-Client-Time: " . time()); |
|
837 | 12 | array_push($headers, $request->to_header()); |
|
838 | |||
839 | 12 | return $headers; |
|
840 | } |
||
841 | |||
842 | /** |
||
843 | * JSON encode request data. |
||
844 | * |
||
845 | * @param string $method Cloud API method |
||
846 | * @param array $json contains data to be encoded |
||
847 | * |
||
848 | * @return string JSON formatted request body |
||
849 | */ |
||
850 | 10 | private function encodeRequest($method, $json) |
|
851 | { |
||
852 | $request = array( |
||
853 | 10 | 'jsonrpc' => '2.0', |
|
854 | 10 | 'id' => '0', |
|
855 | 10 | 'method' => $method, |
|
856 | 10 | 'params' => $json, |
|
857 | 10 | ); |
|
858 | |||
859 | 10 | return str_replace('\\/', '/', json_encode($request)); |
|
860 | } |
||
861 | |||
862 | /** |
||
863 | * Decode a JSON response. |
||
864 | * |
||
865 | * @param string $response JSON response |
||
866 | * |
||
867 | * @return array JSON decoded string |
||
868 | */ |
||
869 | 10 | private function decodeResponse($response) |
|
870 | { |
||
871 | // Decode the json reply |
||
872 | 10 | $result = json_decode($response); |
|
873 | |||
874 | // Check for errors |
||
875 | 10 | if (isset($result->error)) { |
|
876 | throw new \Exception("Error: '" . $result->error->message . "'"); |
||
877 | } |
||
878 | |||
879 | 10 | return $result; |
|
880 | } |
||
881 | |||
882 | /** |
||
883 | * Copies the phar cacert from a phar into the temp directory. |
||
884 | * |
||
885 | * @param string $pharCacertPath Path to the phar cacert. |
||
886 | * |
||
887 | * @return string Returns the path to the extracted cacert file. |
||
888 | */ |
||
889 | public static function extractPharCacert($pharCacertPath) |
||
890 | { |
||
891 | $certFile = sys_get_temp_dir() . '/barracuda-copycom-cacert.crt'; |
||
892 | |||
893 | if (!file_exists($pharCacertPath)) { |
||
894 | throw new \Exception("Could not find " . $pharCacertPath); |
||
895 | } |
||
896 | |||
897 | // Copy the cacert file from the phar if it is not in the temp folder. |
||
898 | if (!file_exists($certFile) || filesize($certFile) != filesize($pharCacertPath)) { |
||
899 | if (!copy($pharCacertPath, $certFile)) { |
||
900 | throw new \Exception( |
||
901 | "Could not copy " . $pharCacertPath . " to " . $certFile . ": " |
||
902 | . var_export(error_get_last(), true) |
||
903 | ); |
||
904 | } |
||
905 | } |
||
906 | |||
907 | return $certFile; |
||
908 | } |
||
909 | } |
||
910 |
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.