Skip to content

Commit

Permalink
port api3's upload workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
Aaron Hedges committed Jun 22, 2015
1 parent bb08b31 commit 38cc067
Showing 1 changed file with 108 additions and 85 deletions.
193 changes: 108 additions & 85 deletions vimeo.php
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,9 @@ public function upload($file_path, $use_multiple_chunks = false, $chunk_temp_dir
}

// Get an upload ticket
$params = array();
$params = array(
'upload_method' => 'streaming'
);

if ($replace_id) {
$params['video_id'] = $replace_id;
Expand All @@ -416,89 +418,14 @@ public function upload($file_path, $use_multiple_chunks = false, $chunk_temp_dir
throw new VimeoAPIException('File exceeds maximum allowed size.', 710);
}

// Split up the file if using multiple pieces
$chunks = array();
if ($use_multiple_chunks) {
if (!is_writeable($chunk_temp_dir)) {
throw new Exception('Could not write chunks. Make sure the specified folder has write access.');
}

// Create pieces
$number_of_chunks = ceil(filesize($file_path) / $size);
for ($i = 0; $i < $number_of_chunks; $i++) {
$chunk_file_name = "{$chunk_temp_dir}/{$file_name}.{$i}";

// Break it up
$chunk = file_get_contents($file_path, FILE_BINARY, null, $i * $size, $size);
$file = file_put_contents($chunk_file_name, $chunk);

$chunks[] = array(
'file' => realpath($chunk_file_name),
'size' => filesize($chunk_file_name)
);
}
}
else {
$chunks[] = array(
'file' => realpath($file_path),
'size' => filesize($file_path)
);
}

// Upload each piece
foreach ($chunks as $i => $chunk) {
$params = array(
'oauth_consumer_key' => $this->_consumer_key,
'oauth_token' => $this->_token,
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_nonce' => $this->_generateNonce(),
'oauth_version' => '1.0',
'ticket_id' => $ticket,
'chunk_id' => $i
);

// Generate the OAuth signature
$params = array_merge($params, array(
'oauth_signature' => $this->_generateSignature($params, 'POST', self::API_REST_URL),
'file_data' => '@'.$chunk['file'] // don't include the file in the signature
));

// Post the file
$curl = curl_init($endpoint);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
$rsp = curl_exec($curl);
curl_close($curl);
}

// Verify
$verify = $this->call('vimeo.videos.upload.verifyChunks', array('ticket_id' => $ticket));

// Make sure our file sizes match up
foreach ($verify->ticket->chunks as $chunk_check) {
$chunk = $chunks[$chunk_check->id];

if ($chunk['size'] != $chunk_check->size) {
// size incorrect, uh oh
echo "Chunk {$chunk_check->id} is actually {$chunk['size']} but uploaded as {$chunk_check->size}<br>";
}
}
$this->_perform_upload($file_path, $endpoint);

// Complete the upload
$complete = $this->call('vimeo.videos.upload.complete', array(
'filename' => $file_name,
'ticket_id' => $ticket
));

// Clean up
if (count($chunks) > 1) {
foreach ($chunks as $chunk) {
unlink($chunk['file']);
}
}

// Confirmation successful, return video id
if ($complete->stat == 'ok') {
return $complete->ticket->video_id;
Expand All @@ -508,15 +435,46 @@ public function upload($file_path, $use_multiple_chunks = false, $chunk_temp_dir
}
}

/**
* Upload a video in multiple pieces.
*
* @deprecated
*/
public function uploadMulti($file_name, $size = 1048576)
public function _perform_upload($file_path, $upload_endpoint)
{
// for compatibility with old library
return $this->upload($file_name, true, '.', $size);
// We need a handle on the input file since we may have to send segments multiple times.
$file = fopen($file_path, 'r');
// PUTs a file in a POST....do for the streaming when we get there.
$curl_opts = array(
CURLOPT_PUT => true,
CURLOPT_INFILE => $file,
CURLOPT_INFILESIZE => filesize($file_path),
CURLOPT_UPLOAD => true,
CURLOPT_HTTPHEADER => array('Expect: ', 'Content-Range: replaced...')
);

// These are the options that set up the validate call.
$curl_opts_check_progress = array(
CURLOPT_PUT => true,
CURLOPT_HTTPHEADER => array('Content-Length: 0', 'Content-Range: bytes */*')
);

// Perform the upload by streaming as much to the server as possible and ending when we reach the filesize on the server.
$size = filesize($file_path);
$server_at = 0;
do {
// The last HTTP header we set MUST be the Content-Range, since we need to remove it and replace it with a proper one.
array_pop($curl_opts[CURLOPT_HTTPHEADER]);
$curl_opts[CURLOPT_HTTPHEADER][] = 'Content-Range: bytes ' . $server_at . '-' . $size . '/' . $size;

fseek($file, $server_at); // Put the FP at the point where the server is.

try {
var_dump($this->_request3($upload_endpoint, $curl_opts)); //Send what we can.
} catch (\Vimeo\Exceptions\VimeoRequestException $exception) {
// ignored, it's likely a timeout, and we should only consider a failure from the progress check as a legit failure
}

$progress_check = $this->_request3($upload_endpoint, $curl_opts_check_progress); // Check on what the server has.
// Figure out how much is on the server.
list(, $server_at) = explode('-', $progress_check['headers']['Range']);
$server_at = (int)$server_at;
} while ($server_at < $size);
}

/**
Expand All @@ -539,6 +497,71 @@ public static function url_encode_rfc3986($input)
}
}

/**
* Internal function to handle requests, both authenticated and by the upload function.
*
* @param string $url
* @param array $curl_opts
* @return array
*/
private function _request3($url, $curl_opts = array()) {
// Merge the options (custom options take precedence).
$curl_opts = $curl_opts + array(
CURLOPT_HEADER => 1,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
);

// Call the API.
$curl = curl_init($url);
curl_setopt_array($curl, $curl_opts);
$response = curl_exec($curl);
$curl_info = curl_getinfo($curl);

if(isset($curl_info['http_code']) && $curl_info['http_code'] === 0){
$curl_error = curl_error($curl);
$curl_error = !empty($curl_error) ? '[' . $curl_error .']' : '';
throw new VimeoRequestException('Unable to complete request.' . $curl_error);
}

curl_close($curl);

// Retrieve the info
$header_size = $curl_info['header_size'];
$headers = substr($response, 0, $header_size);
$body = substr($response, $header_size);

// Return it raw.
return array(
'body' => $body,
'status' => $curl_info['http_code'],
'headers' => self::parse_headers($headers)
);

}

/**
* Convert the raw headers string into an associated array
*
* @param string $headers
* @return array
*/
public static function parse_headers($headers)
{
$final_headers = array();
$list = explode("\n", trim($headers));

$http = array_shift($list);

foreach ($list as $header) {
$parts = explode(':', $header);
$final_headers[trim($parts[0])] = isset($parts[1]) ? trim($parts[1]) : '';
}

return $final_headers;
}


}

class VimeoAPIException extends Exception {}

0 comments on commit 38cc067

Please sign in to comment.