Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 612 lines (535 sloc) 18.526 kb
13ed088 @bdougherty initial commit
bdougherty authored
1 <?
2
3 class phpVimeo {
4
5 const API_REST_URL = 'http://vimeo.com/api/rest/v2';
6 const API_AUTH_URL = 'http://vimeo.com/oauth/authorize';
7 const API_ACCESS_TOKEN_URL = 'http://vimeo.com/oauth/access_token';
8 const API_REQUEST_TOKEN_URL = 'http://vimeo.com/oauth/request_token';
9
10 const CACHE_FILE = 'file';
11
12 private $_consumer_key = false;
13 private $_consumer_secret = false;
14 private $_cache_enabled = false;
15 private $_cache_dir = false;
16 private $_token = false;
17 private $_token_secret = false;
18 private $_upload_md5s = array();
19
20 public function __construct($consumer_key, $consumer_secret, $token = null, $token_secret = null) {
21 $this->_consumer_key = $consumer_key;
22 $this->_consumer_secret = $consumer_secret;
23
24 if ($token && $token_secret) {
25 $this->setToken($token, $token_secret);
26 }
27 }
28
29 /**
30 * Cache a response.
31 *
32 * @param array $params The parameters for the response.
33 * @param string $response The serialized response data.
34 */
35 private function _cache($params, $response) {
36 // Remove some unique things
37 unset($params['oauth_nonce']);
38 unset($params['oauth_signature']);
39 unset($params['oauth_timestamp']);
40
41 $hash = md5(serialize($params));
42
43 if ($this->_cache_enabled == self::CACHE_FILE) {
44 $file = $this->_cache_dir.'/'.$hash.'.cache';
45 if (file_exists($file)) {
46 unlink($file);
47 }
48 return file_put_contents($file, $response);
49 }
50 }
51
52 /**
53 * Create the authorization header for a set of params.
54 *
55 * @param array $oauth_params The OAuth parameters for the call.
56 * @return string The OAuth Authorization header.
57 */
58 private function _generateAuthHeader($oauth_params) {
59 $auth_header = 'Authorization: OAuth realm=""';
60 foreach ($oauth_params as $k => $v) {
61 $auth_header .= ','.self::url_encode_rfc3986($k).'="'.self::url_encode_rfc3986($v).'"';
62 }
63 return $auth_header;
64 }
65
66 /**
67 * Generate a nonce for the call.
68 *
69 * @return string The nonce
70 */
71 private function _generateNonce() {
72 return md5(uniqid(microtime()));
73 }
74
75 /**
76 * Generate the OAuth signature.
77 *
78 * @param array $args The full list of args to generate the signature for.
79 * @param string $request_method The request method, either POST or GET.
80 * @param string $url The base URL to use.
81 * @return string The OAuth signature.
82 */
83 private function _generateSignature($params, $request_method = 'GET', $url = self::API_REST_URL) {
84 uksort($params, 'strcmp');
85
86 // Make the base string
87 $base_parts = array(
88 strtoupper($request_method),
89 $url,
958d536 @bdougherty fix base string urlencoding issue
bdougherty authored
90 urldecode(http_build_query($params))
13ed088 @bdougherty initial commit
bdougherty authored
91 );
92 $base_parts = self::url_encode_rfc3986($base_parts);
93 $base_string = implode('&', $base_parts);
94
95 // Make the key
96 $key_parts = array(
97 $this->_consumer_secret,
98 ($this->_token_secret) ? $this->_token_secret : ''
99 );
100 $key_parts = self::url_encode_rfc3986($key_parts);
101 $key = implode('&', $key_parts);
102
103 // Generate signature
104 return base64_encode(hash_hmac('sha1', $base_string, $key, true));
105 }
106
107 /**
108 * Get the unserialized contents of the cached request.
109 *
110 * @param array $params The full list of api parameters for the request.
111 */
112 private function _getCached($params) {
113 // Remove some unique things
114 unset($params['oauth_nonce']);
115 unset($params['oauth_signature']);
116 unset($params['oauth_timestamp']);
117
118 $hash = md5(serialize($params));
119
120 if ($this->_cache_enabled == self::CACHE_FILE) {
121 $file = $this->_cache_dir.'/'.$hash.'.cache';
122 if (file_exists($file)) {
123 return unserialize(file_get_contents($file));
124 }
125 }
126 }
127
128 /**
129 * Call an API method.
130 *
131 * @param string $method The method to call.
132 * @param array $call_params The parameters to pass to the method.
133 * @param string $request_method The HTTP request method to use.
134 * @param string $url The base URL to use.
135 * @param boolean $cache Whether or not to cache the response.
136 * @param boolean $use_auth_header Use the OAuth Authorization header to pass the OAuth params.
137 * @return string The response from the method call.
138 */
139 private function _request($method, $call_params = array(), $request_method = 'GET', $url = self::API_REST_URL, $cache = true, $use_auth_header = true) {
140
141 // Prepare oauth arguments
142 $oauth_params = array(
143 'oauth_consumer_key' => $this->_consumer_key,
144 'oauth_version' => '1.0',
145 'oauth_signature_method' => 'HMAC-SHA1',
146 'oauth_timestamp' => time(),
147 'oauth_nonce' => $this->_generateNonce()
148 );
149
150 // If we have a token, include it
151 if ($this->_token) {
152 $oauth_params['oauth_token'] = $this->_token;
153 }
154
155 // Regular args
156 $api_params = array('format' => 'php');
157 if (!empty($method)) {
158 $api_params['method'] = $method;
159 }
160
161 // Merge args
162 foreach ($call_params as $k => $v) {
163 if (strpos($k, 'oauth_') === 0) {
164 $oauth_params[$k] = $v;
165 }
166 else {
167 $api_params[$k] = $v;
168 }
169 }
170
171 // Generate the signature
172 $oauth_params['oauth_signature'] = $this->_generateSignature(array_merge($oauth_params, $api_params), $request_method, $url);
173
174 // Merge all args
175 $all_params = array_merge($oauth_params, $api_params);
176
177 // Returned cached value
178 if ($this->_cache_enabled && ($cache && $response = $this->_getCached($all_params))) {
179 return $response;
180 }
181
182 // Curl options
183 if ($use_auth_header) {
184 $params = $api_params;
185 }
186 else {
187 $params = $all_params;
188 }
189
190 if (strtoupper($request_method) == 'GET') {
191 $curl_url = $url.'?'.http_build_query($params);
192 $curl_opts = array(
193 CURLOPT_RETURNTRANSFER => true,
194 CURLOPT_TIMEOUT => 30
195 );
196 }
197 elseif (strtoupper($request_method) == 'POST') {
198 $curl_url = $url;
199 $curl_opts = array(
200 CURLOPT_RETURNTRANSFER => true,
201 CURLOPT_TIMEOUT => 30,
202 CURLOPT_POST => true,
203 CURLOPT_POSTFIELDS => http_build_query($params)
204 );
205 }
206
207 // Authorization header
208 if ($use_auth_header) {
209 $curl_opts[CURLOPT_HTTPHEADER] = array($this->_generateAuthHeader($oauth_params));
210 }
211
212 // Call the API
213 $curl = curl_init($curl_url);
214 curl_setopt_array($curl, $curl_opts);
215 $response = curl_exec($curl);
216 $curl_info = curl_getinfo($curl);
217 curl_close($curl);
218
219 // Cache the response
220 if ($this->_cache_enabled && $cache) {
221 $this->_cache($all_params, $response);
222 }
223
224 // Return
225 if (!empty($method)) {
226 $response = unserialize($response);
227 if ($response->stat == 'ok') {
228 return $response;
229 }
230 else if ($response->err) {
231 throw new VimeoAPIException($response->err->msg, $response->err->code);
232 }
233 return false;
234 }
235 return $response;
236 }
237
238 /**
239 * Send the user to Vimeo to authorize your app.
240 * http://www.vimeo.com/api/docs/oauth
241 *
242 * @param string $perms The level of permissions to request: read, write, or delete.
243 */
244 public function auth($permission = 'read', $callback_url = 'oob') {
245 $t = $this->getRequestToken($callback_url);
246 $this->setToken($t['oauth_token'], $t['oauth_token_secret'], 'request', true);
247 $url = $this->getAuthorizeUrl($this->_token, $permission);
248 header("Location: {$url}");
249 }
250
251 /**
252 * Call a method.
253 *
254 * @param string $method The name of the method to call.
255 * @param array $params The parameters to pass to the method.
256 * @param string $request_method The HTTP request method to use.
257 * @param string $url The base URL to use.
258 * @param boolean $cache Whether or not to cache the response.
259 * @return array The response from the API method
260 */
261 public function call($method, $params = array(), $request_method = 'GET', $url = self::API_REST_URL, $cache = true) {
262 $method = (substr($method, 0, 6) != 'vimeo.') ? "vimeo.{$method}" : $method;
263 return $this->_request($method, $params, $request_method, $url, $cache);
264 }
265
266 /**
267 * Enable the cache.
268 *
269 * @param string $type The type of cache to use (phpVimeo::CACHE_FILE is built in)
270 * @param string $path The path to the cache (the directory for CACHE_FILE)
271 * @param int $expire The amount of time to cache responses (default 10 minutes)
272 */
273 public function enableCache($type, $path, $expire = 600) {
274 $this->_cache_enabled = $type;
275 if ($this->_cache_enabled == self::CACHE_FILE) {
276 $this->_cache_dir = $path;
277 $files = scandir($this->_cache_dir);
278 foreach ($files as $file) {
279 $last_modified = filemtime($this->_cache_dir.'/'.$file);
280 if (substr($file, -6) == '.cache' && ($last_modified + $expire) < time()) {
281 unlink($this->_cache_dir.'/'.$file);
282 }
283 }
284 }
285 return false;
286 }
287
288 /**
289 * Get an access token. Make sure to call setToken() with the
290 * request token before calling this function.
291 *
292 * @param string $verifier The OAuth verifier returned from the authorization page or the user.
293 */
294 public function getAccessToken($verifier) {
295 $access_token = $this->_request(null, array('oauth_verifier' => $verifier), 'GET', self::API_ACCESS_TOKEN_URL, false, true);
296 parse_str($access_token, $parsed);
297 return $parsed;
298 }
299
300 /**
301 * Get the URL of the authorization page.
302 *
303 * @param string $token The request token.
304 * @param string $permission The level of permissions to request: read, write, or delete.
305 * @param string $callback_url The URL to redirect the user back to, or oob for the default.
306 * @return string The Authorization URL.
307 */
308 public function getAuthorizeUrl($token, $permission = 'read') {
309 return self::API_AUTH_URL."?oauth_token={$token}&permission={$permission}";
310 }
311
312 /**
313 * Get a request token.
314 */
315 public function getRequestToken($callback_url = 'oob') {
316 $request_token = $this->_request(
317 null,
a163229 @bdougherty fix callback url bug
bdougherty authored
318 array('oauth_callback' => $callback_url),
13ed088 @bdougherty initial commit
bdougherty authored
319 'GET',
320 self::API_REQUEST_TOKEN_URL,
321 false,
322 false
323 );
324
325 parse_str($request_token, $parsed);
326 return $parsed;
327 }
328
329 /**
330 * Get the stored auth token.
331 *
332 * @return array An array with the token and token secret.
333 */
334 public function getToken() {
335 return array($this->_token, $this->_token_secret);
336 }
337
338 /**
339 * Set the OAuth token.
340 *
341 * @param string $token The OAuth token
342 * @param string $token_secret The OAuth token secret
343 * @param string $type The type of token, either request or access
344 * @param boolean $session_store Store the token in a session variable
345 * @return boolean true
346 */
347 public function setToken($token, $token_secret, $type = 'access', $session_store = false) {
348 $this->_token = $token;
349 $this->_token_secret = $token_secret;
350
351 if ($session_store) {
352 $_SESSION["{$type}_token"] = $token;
353 $_SESSION["{$type}_token_secret"] = $token_secret;
354 }
355
356 return true;
357 }
358
359 /**
360 * Upload a video in one piece.
361 *
362 * @param string $file_name The full path to the file
363 * @return int The video ID
364 */
365 public function upload($file_name) {
366 if (file_exists($file_name)) {
367
368 // MD5 the file
369 $hash = md5_file($file_name);
370
371 // Get an upload ticket
372 $rsp = $this->call('vimeo.videos.upload.getTicket');
373 $ticket = $rsp->ticket->id;
374 $endpoint = $rsp->ticket->endpoint;
375
376 // Set up params for video post
377 $params = array(
378 'oauth_consumer_key' => $this->_consumer_key,
379 'oauth_token' => $this->_token,
380 'oauth_signature_method' => 'HMAC-SHA1',
381 'oauth_timestamp' => time(),
382 'oauth_nonce' => $this->_generateNonce(),
383 'oauth_version' => '1.0',
384 'ticket_id' => $ticket,
385 );
386 $signature = $this->_generateSignature($params, 'POST', self::API_REST_URL);
387 $params = array_merge($params, array(
388 'oauth_signature' => $signature,
389 'file_data' => '@'.realpath($file_name) // don't include the file in the signature
390 ));
391
392 // Post the video
393 $curl = curl_init($endpoint);
394 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
395 curl_setopt($curl, CURLOPT_POST, 1);
396 curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
397 $rsp = curl_exec($curl);
398 curl_close($curl);
399
400 // If the uploaded file's MD5 doesn't match
401 if ($rsp !== $hash) {
402 throw new VimeoAPIException(799, 'Uploaded file MD5 does not match');
403 }
404
405 // Figure out the filename
406 $path_parts = pathinfo($file_name);
407 $base_name = $path_parts['basename'];
408
409 // Set up parameters for confirm call
410 $params = array(
411 'oauth_consumer_key' => $this->_consumer_key,
412 'oauth_token' => $this->_token,
413 'oauth_signature_method' => 'HMAC-SHA1',
414 'oauth_timestamp' => time(),
415 'oauth_nonce' => $this->_generateNonce(),
416 'oauth_version' => '1.0',
417 'ticket_id' => $ticket,
418 'method' => 'vimeo.videos.upload.confirm',
419 'format' => 'php',
420 'filename' => $base_name
421 );
422 $signature = $this->_generateSignature($params, 'POST', self::API_REST_URL);
423 $params = array_merge($params, array(
424 'oauth_signature' => $signature
425 ));
426
427 // Confirm the upload
428 $curl = curl_init(self::API_REST_URL.'?'.http_build_query($params));
429 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
430 curl_setopt($curl, CURLOPT_POST, 1);
431 $rsp = unserialize(curl_exec($curl));
432 curl_close($curl);
433
434 // Confirmation successful, return video id
435 if ($rsp->stat == 'ok') {
436 return $rsp->ticket->video_id;
437 }
438 else if ($rsp->err) {
439 throw new VimeoAPIException($rsp->err->msg, $rsp->err->code);
440 }
441 }
442 return false;
443 }
444
445 /**
446 * Upload a video in multiple pieces.
447 *
448 * @param string $file_name The full path to the file
449 * @param int $size The size of each piece in bytes (1MB default)
450 * @return int The video ID
451 */
452 public function uploadMulti($file_name, $size = 1048576) {
453 if (file_exists($file_name)) {
454
455 // MD5 the whole file
456 $hash = md5_file($file_name);
457
458 // Get an upload ticket
459 $rsp = $this->call('vimeo.videos.upload.getTicket', array(), 'GET', self::API_REST_URL, false);
460 $ticket = $rsp->ticket->id;
461 $endpoint = $rsp->ticket->endpoint;
462
463 // How many pieces?
464 $pieces = ceil(filesize($file_name) / $size);
465
466 // Create pieces and upload
467 $chunks = array();
468 for ($i = 0; $i < $pieces; $i++) {
469
470 $piece_file_name = "{$file_name}.{$i}";
471
472 // Break it up
473 $piece = file_get_contents($file_name, FILE_BINARY, null, $i * $size, $size);
474 file_put_contents($piece_file_name, $piece);
475
476 // Get the md5 for the manifest
477 $chunks[] = array('file' => $piece_file_name, 'md5' => md5_file($piece_file_name));
478
479 // Set up params for video post
480 $params = array(
481 'oauth_consumer_key' => $this->_consumer_key,
482 'oauth_token' => $this->_token,
483 'oauth_signature_method' => 'HMAC-SHA1',
484 'oauth_timestamp' => time(),
485 'oauth_nonce' => $this->_generateNonce(),
486 'oauth_version' => '1.0',
487 'ticket_id' => $ticket,
488 );
489 $signature = $this->_generateSignature($params, 'POST', self::API_REST_URL);
490 $params = array_merge($params, array(
491 'oauth_signature' => $signature,
492 'file_data' => '@'.realpath($piece_file_name)
493 ));
494
495 // Post the video
496 $curl = curl_init($endpoint);
497 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
498 curl_setopt($curl, CURLOPT_POST, 1);
499 curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
500 $rsp = curl_exec($curl);
501 curl_close($curl);
502 }
503
504 // Create the manifest
505 $manifest = array();
506 foreach ($chunks as $file) {
507 $manifest['files'][] = array('md5' => $file['md5']);
508 }
509 $manifest = json_encode($manifest);
510
511 // Verify the manifest
512 $params = array(
513 'oauth_consumer_key' => $this->_consumer_key,
514 'oauth_token' => $this->_token,
515 'oauth_signature_method' => 'HMAC-SHA1',
516 'oauth_timestamp' => time(),
517 'oauth_nonce' => $this->_generateNonce(),
518 'oauth_version' => '1.0',
519 'ticket_id' => $ticket,
520 'method' => 'vimeo.videos.upload.verifyManifest',
521 'format' => 'php'
522 );
523
524 $signature = $this->_generateSignature($params, 'POST', self::API_REST_URL);
525 $params = array_merge($params, array(
526 'oauth_signature' => $signature
527 ));
528 $curl = curl_init(self::API_REST_URL.'?'.http_build_query($params));
529 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
530 curl_setopt($curl, CURLOPT_POST, 1);
531 curl_setopt($curl, CURLOPT_POSTFIELDS, array('json_manifest' => $manifest));
532 $rsp = unserialize(curl_exec($curl));
533 curl_close($curl);
534
535 // Delete chunks
536 foreach ($chunks as $file) {
537 unlink($file['file']);
538 }
539
540 // Error
541 if ($rsp->stat != 'ok') {
542 throw new VimeoAPIException($rsp->err->msg, $rsp->err->code);
543 }
544
545 // If the uploaded file's MD5 doesn't match
546 if ($rsp->ticket->md5 !== $hash) {
547 throw new VimeoAPIException(799, 'Uploaded file MD5 does not match');
548 }
549
550 // Figure out the filename
551 $path_parts = pathinfo($file_name);
552 $base_name = $path_parts['basename'];
553
554 // Confirm upload
555 $params = array(
556 'oauth_consumer_key' => $this->_consumer_key,
557 'oauth_token' => $this->_token,
558 'oauth_signature_method' => 'HMAC-SHA1',
559 'oauth_timestamp' => time(),
560 'oauth_nonce' => $this->_generateNonce(),
561 'oauth_version' => '1.0',
562 'ticket_id' => $ticket,
563 'method' => 'vimeo.videos.upload.confirm',
564 'format' => 'php',
565 'filename' => $base_name
566 );
567 $signature = $this->_generateSignature($params, 'POST', self::API_REST_URL);
568 $params = array_merge($params, array(
569 'oauth_signature' => $signature
570 ));
571 $curl = curl_init(self::API_REST_URL.'?'.http_build_query($params));
572 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
573 curl_setopt($curl, CURLOPT_POST, 1);
574 curl_setopt($curl, CURLOPT_POSTFIELDS, array('json_manifest' => $manifest));
575 $rsp = unserialize(curl_exec($curl));
576 curl_close($curl);
577
578 // Confirmation successful, return video id
579 if ($rsp->stat == 'ok') {
580 return $rsp->ticket->video_id;
581 }
582 else if ($rsp->err) {
583 throw new VimeoAPIException($rsp->err->msg, $rsp->err->code);
584 }
585 }
586 return false;
587 }
588
589 /**
590 * URL encode a parameter or array of parameters.
591 *
592 * @param array/string $input A parameter or set of parameters to encode.
593 */
594 public static function url_encode_rfc3986($input) {
595 if (is_array($input)) {
596 return array_map(array('phpVimeo', 'url_encode_rfc3986'), $input);
597 }
598 elseif (is_scalar($input)) {
599 return str_replace(array('+', '%7E'), array(' ', '~'), rawurlencode($input));
600 }
601 else {
602 return '';
603 }
604 }
605
606 }
607
608 class VimeoAPIException extends Exception {
609
610 }
611
612 ?>
Something went wrong with that request. Please try again.