├── Changelog.md
├── ElasticTranscoder.php
└── README.md
/Changelog.md:
--------------------------------------------------------------------------------
1 | Change Log
2 | ============================
3 | ### Version 1.0.2 ###
4 | * Fixed incorrect signature bug for GET requests following a POST request
5 | * Updated `createPipeline()` to accept an array of options
6 |
7 | ### Version 1.0.1 ###
8 | * Fixed duplicate header bug for multiple calls
9 |
10 | Special thanks to exuvis for pointing this out.
--------------------------------------------------------------------------------
/ElasticTranscoder.php:
--------------------------------------------------------------------------------
1 | array(
50 | 'Key' => $input['Key'],
51 | 'FrameRate' => (array_key_exists('FrameRate', $input)) ? $input['FrameRate'] : 'auto',
52 | 'Resolution' => (array_key_exists('Resolution', $input)) ? $input['Resolution'] : 'auto',
53 | 'AspectRatio' => (array_key_exists('AspectRatio', $input)) ? $input['AspectRatio'] : 'auto',
54 | 'Interlaced' => (array_key_exists('Interlaced', $input)) ? $input['Interlaced'] : 'auto',
55 | 'Container' => (array_key_exists('Container', $input)) ? $input['Container'] : 'auto'
56 | )
57 | );
58 | if ($outputKeyPrefix !== null) {
59 | $requestBody['OutputKeyPrefix'] = $outputKeyPrefix;
60 | }
61 | $requestBody['Outputs'] = array();
62 | $num = sizeof($outputs);
63 | for ($i=0; $i<$num; $i++) {
64 | $requestBody['Outputs'][$i] = array(
65 | 'Key' => $outputs[$i]['Key'],
66 | 'ThumbnailPattern' => (array_key_exists('ThumbnailPattern', $outputs[$i])) ? $outputs[$i]['ThumbnailPattern'] : '',
67 | 'Rotate' => (array_key_exists('Rotate', $outputs[$i])) ? $outputs[$i]['Rotate'] : 'auto',
68 | 'PresetId' => $outputs[$i]['PresetId']
69 | );
70 | if (array_key_exists('SegmentDuration', $outputs[$i])) {
71 | $requestBody['Outputs'][$i]['SegmentDuration'] = $outputs[$i]['SegmentDuration'];
72 | }
73 | }
74 | if (!empty($playlists)) {
75 | $requestBody['Playlists'] = array(
76 | 'Format' => 'HLSv3',
77 | 'Name' => $playlists['Name']
78 | );
79 | if (array_key_exists('OutputKeys', $playlists)) {
80 | $requestBody['Playlists']['OutputKeys'] = $playlists['OutputKeys'];
81 | }
82 | }
83 | if (!empty($usermetadata)) {
84 | $requestBody['UserMetadata'] = $usermetadata;
85 | }
86 | $requestBody['PipelineId'] = $pipelineId;
87 | $requestBody = json_encode($requestBody);
88 | self::setRequestBody($requestBody);
89 | $result = self::sendRequest();
90 | return $result;
91 | }
92 |
93 | /**
94 | * Get all jobs for a pipeline
95 | *
96 | * @param string $pipelineId pipeline ID
97 | * @param boolean $ascending results in ascending order
98 | * @return array | false
99 | */
100 | public static function listJobsByPipeline($pipelineId, $ascending = true) {
101 | self::resetProps();
102 | self::$HttpRequestMethod = 'GET';
103 | if ($ascending) {
104 | $ascending = 'true';
105 | } else {
106 | $ascending = 'false';
107 | }
108 | self::$Uri = '/2012-09-25/jobsByPipeline/'.$pipelineId.'?Ascending='.$ascending;
109 | $result = self::sendRequest();
110 | return $result;
111 | }
112 |
113 | /**
114 | * Get all jobs that have a given status
115 | *
116 | * @param string $Status job status
117 | * @return array | false
118 | */
119 | public static function listJobsByStatus($status) {
120 | self::resetProps();
121 | self::$HttpRequestMethod = 'GET';
122 | self::$Uri = '/2012-09-25/jobsByStatus/'.$status;
123 | $result = self::sendRequest();
124 | return $result;
125 | }
126 |
127 | /**
128 | * Get details of a job
129 | *
130 | * @param string $jobId job ID
131 | * @return array | false
132 | */
133 | public static function readJob($jobId) {
134 | self::resetProps();
135 | self::$HttpRequestMethod = 'GET';
136 | self::$Uri = '/2012-09-25/jobs/'.$jobId;
137 | $result = self::sendRequest();
138 | return $result;
139 | }
140 |
141 | /**
142 | * Cancel a job
143 | *
144 | * @param string $jobId job ID
145 | * @return array | false
146 | */
147 | public static function cancelJob($jobId) {
148 | self::resetProps();
149 | self::$HttpRequestMethod = 'DELETE';
150 | self::$Uri = '/2012-09-25/jobs/'.$jobId;
151 | $result = self::sendRequest();
152 | return $result;
153 | }
154 |
155 | /**
156 | * Create a new pipeline
157 | *
158 | * @param array $options settings
159 | * @return array | false
160 | */
161 | public static function createPipeline($options = array()) {
162 | self::resetProps();
163 | self::$HttpRequestMethod = 'POST';
164 | self::$Uri = '/2012-09-25/pipelines';
165 | $requestBody = array(
166 | 'Name' => $options['Name'],
167 | 'Role' => $options['Role'],
168 | 'InputBucket' => $options['InputBucket'],
169 | 'Notifications' => array(
170 | 'Progressing' => (array_key_exists('Notifications', $options) && array_key_exists('Progressing', $options['Notifications']['Progressing'])) ? $options['Notifications']['Progressing'] : '',
171 | 'Completed' => (array_key_exists('Notifications', $options) && array_key_exists('Completed', $options['Notifications']['Completed'])) ? $options['Notifications']['Completed'] : '',
172 | 'Warning' => (array_key_exists('Notifications', $options) && array_key_exists('Warning', $options['Notifications']['Warning'])) ? $options['Notifications']['Warning'] : '',
173 | 'Error' => (array_key_exists('Notifications', $options) && array_key_exists('Error', $options['Notifications']['Error'])) ? $options['Notifications']['Error'] : ''
174 | )
175 | );
176 | // Either OutputBucket or ContentConfig with ThumbnailConfig are required
177 | if (array_key_exists('OutputBucket', $options)) {
178 | $requestBody['OutputBucket'] = $options['OutputBucket'];
179 | } elseif (array_key_exists('ContentConfig', $options) && array_key_exists('ThumbnailConfig', $options)) {
180 | $requestBody['ContentConfig'] = $options['ContentConfig'];
181 | $requestBody['ThumbnailConfig'] = $options['ThumbnailConfig'];
182 | } else {
183 | self::setErrorMsg('Missing parameters. OutputBucket or ContentConfig with ThumbnailConfig are required.');
184 | return false;
185 | }
186 | $requestBody = json_encode($requestBody);
187 | self::setRequestBody($requestBody);
188 | $result = self::sendRequest();
189 | return $result;
190 | }
191 |
192 | /**
193 | * Get a list of pipelines associated with account
194 | *
195 | * @return array | false
196 | */
197 | public static function listPipelines() {
198 | self::resetProps();
199 | self::$HttpRequestMethod = 'GET';
200 | self::$Uri = '/2012-09-25/pipelines';
201 | $result = self::sendRequest();
202 | return $result;
203 | }
204 |
205 | /**
206 | * Get info about a pipeline
207 | *
208 | * @param string $pipelineId pipeline ID
209 | * @return array | false
210 | */
211 | public static function readPipeline($pipelineId) {
212 | self::resetProps();
213 | self::$HttpRequestMethod = 'GET';
214 | self::$Uri = '/2012-09-25/pipelines/'.$pipelineId;
215 | $result = self::sendRequest();
216 | return $result;
217 | }
218 |
219 | /**
220 | * Update settings for a pipeline
221 | *
222 | * @param string $pipelineId pipeline ID
223 | * @param array $updates updates
224 | * @return array | false
225 | */
226 | public static function updatePipeline($pipelineId, $updates) {
227 | self::resetProps();
228 | self::$HttpRequestMethod = 'PUT';
229 | self::$Uri = '/2012-09-25/pipelines/'.$pipelineId;
230 | $requestBody = json_encode($updates);
231 | self::setRequestBody($requestBody);
232 | $result = self::sendRequest();
233 | return $result;
234 | }
235 |
236 | /**
237 | * Update pipeline status (active/paused)
238 | *
239 | * @param string $pipelineId pipeline ID
240 | * @param array $status new status
241 | * @return array | false
242 | */
243 | public static function updatePipelineStatus($pipelineId, $status) {
244 | self::resetProps();
245 | self::$HttpRequestMethod = 'POST';
246 | self::$Uri = '/2012-09-25/pipelines/'.$pipelineId.'/status';
247 | $requestBody = json_encode(array('Status' => $status));
248 | self::setRequestBody($requestBody);
249 | $result = self::sendRequest();
250 | return $result;
251 | }
252 |
253 | /**
254 | * Update pipeline notification settings
255 | *
256 | * @param string $pipelineId pipeline ID
257 | * @param array $notifications new notification settings
258 | * @return array | false
259 | */
260 | public static function updatePipelineNotifications($pipelineId, $notifications = array()) {
261 | self::resetProps();
262 | self::$HttpRequestMethod = 'POST';
263 | self::$Uri = '/2012-09-25/pipelines/'.$pipelineId.'/notifications';
264 | $requestBody = json_encode(array(
265 | 'Id' => $pipelineId,
266 | 'Notifications' => array(
267 | 'Progressing' => (array_key_exists('Progressing', $notifications)) ? $notifications['Progressing'] : '',
268 | 'Completed' => (array_key_exists('Completed', $notifications)) ? $notifications['Completed'] : '',
269 | 'Warning' => (array_key_exists('Warning', $notifications)) ? $notifications['Warning'] : '',
270 | 'Error' => (array_key_exists('Error', $notifications)) ? $notifications['Error'] : ''
271 | )
272 | ));
273 | self::setRequestBody($requestBody);
274 | $result = self::sendRequest();
275 | return $result;
276 | }
277 |
278 | /**
279 | * Delete a pipeline
280 | *
281 | * @param string $pipelineId pipeline ID
282 | * @return array | false
283 | */
284 | public static function deletePipeline($pipelineId) {
285 | self::resetProps();
286 | self::$HttpRequestMethod = 'DELETE';
287 | self::$Uri = '/2012-09-25/pipelines/'.$pipelineId;
288 | $result = self::sendRequest();
289 | return $result;
290 | }
291 |
292 | /**
293 | * Test the settings for a pipeline
294 | *
295 | * @param string $inputBucket input bucket ID
296 | * @param string $outBucket output bucket ID
297 | * @param string $role The IAM Amazon Resource Name (ARN) for role to use for transcoding jobs
298 | * @param array $topics The ARNs of one or more Amazon Simple Notification Service (Amazon SNS) topics
299 | * @return array | false
300 | */
301 | public static function testRole($inputBucket, $outputBucket, $role, $topics = array()) {
302 | self::resetProps();
303 | self::$HttpRequestMethod = 'POST';
304 | self::$Uri = '/2012-09-25/roleTests';
305 | $requestBody = json_encode(array(
306 | 'InputBucket' => $inputBucket,
307 | 'OutputBucket' => $outputBucket,
308 | 'Role' => $role,
309 | 'Topics' => $topics
310 | ));
311 | self::setRequestBody($requestBody);
312 | $result = self::sendRequest();
313 | return $result;
314 | }
315 |
316 | /**
317 | * Create a new preset
318 | *
319 | * @param string $name name of the preset
320 | * @param string $description preset description
321 | * @param string $container container type for output file
322 | * @param array $audio audio settings
323 | * @param array $video video settings
324 | * @param array $thumbnails thumbnail settings
325 | * @return array | false
326 | */
327 | public static function createPreset($name, $description, $container = 'mp4', $audio = array(), $video = array(), $thumbnails = array()) {
328 | self::resetProps();
329 | self::$HttpRequestMethod = 'POST';
330 | self::$Uri = '/2012-09-25/presets';
331 | $requestBody = array(
332 | 'Name' => $name,
333 | 'Description' => $description,
334 | 'Container' => $container,
335 | 'Audio' => array(
336 | 'Codec' => (array_key_exists('Codec', $audio)) ? $audio['Codec'] : 'AAC',
337 | 'SampleRate' => (array_key_exists('SampleRate', $audio)) ? $audio['SampleRate'] : 'auto',
338 | 'BitRate' => (array_key_exists('BitRate', $audio)) ? $audio['BitRate'] : '64',
339 | 'Channels' => (array_key_exists('Channels', $audio)) ? $audio['Channels'] : 'auto'
340 | ),
341 | 'Video' => array(
342 | 'Codec' => (array_key_exists('Codec', $video)) ? $video['Codec'] : 'H.264',
343 | 'CodecOptions' => array(
344 | 'Profile' => (array_key_exists('CodecOptions', $video) && array_key_exists('Profile', $video['CodecOptions'])) ? $video['CodecOptions']['Profile'] : 'baseline',
345 | 'Level' => (array_key_exists('CodecOptions', $video) && array_key_exists('Level', $video['CodecOptions'])) ? $video['CodecOptions']['Level'] : '1',
346 | 'MaxReferenceFrames' => (array_key_exists('CodecOptions', $video) && array_key_exists('MaxReferenceFrames', $video['CodecOptions'])) ? $video['CodecOptions']['MaxReferenceFrames'] : '0',
347 | 'MaxBitRate' => (array_key_exists('CodecOptions', $video) && array_key_exists('MaxBitRate', $video['CodecOptions'])) ? $video['CodecOptions']['MaxBitRate'] : '16',
348 | 'BufferSize' => (array_key_exists('CodecOptions', $video) && array_key_exists('BufferSize', $video['CodecOptions'])) ? $video['CodecOptions']['BufferSize'] : '10'
349 | ),
350 | 'KeyframesMaxDist' => (array_key_exists('KeyframesMaxDist', $video)) ? $video['KeyframesMaxDist'] : '1',
351 | 'FixedGOP' => (array_key_exists('FixedGOP', $video)) ? $video['FixedGOP'] : 'true',
352 | 'BitRate' => (array_key_exists('BitRate', $video)) ? $video['BitRate'] : 'auto',
353 | 'FrameRate' => (array_key_exists('FrameRate', $video)) ? $video['FrameRate'] : 'auto',
354 | 'MaxFrameRate' => (array_key_exists('MaxFrameRate', $video)) ? $video['MaxFrameRate'] : '10',
355 | 'MaxWidth' => (array_key_exists('MaxWidth', $video)) ? $video['MaxWidth'] : 'auto',
356 | 'MaxHeight' => (array_key_exists('MaxHeight', $video)) ? $video['MaxHeight'] : 'auto',
357 | 'SizingPolicy' => (array_key_exists('SizingPolicy', $video)) ? $video['SizingPolicy'] : 'Fit',
358 | 'PaddingPolicy' => (array_key_exists('PaddingPolicy', $video)) ? $video['PaddingPolicy'] : 'Pad',
359 | 'DisplayAspectRatio' => (array_key_exists('DisplayAspectRatio', $video)) ? $video['DisplayAspectRatio'] : 'auto'
360 | )
361 | );
362 | if (isset($video['Resolution']) && isset($video['AspectRatio'])) {
363 | unset($requestBody['Video']['MaxWidth']);
364 | unset($requestBody['Video']['MaxHeight']);
365 | unset($requestBody['Video']['SizingPolicy']);
366 | unset($requestBody['Video']['PaddingPolicy']);
367 | unset($requestBody['Video']['DisplayAspectRatio']);
368 | $requestBody['Video']['Resolution'] = $video['Resolution'];
369 | $requestBody['Video']['AspectRatio'] = $video['AspectRatio'];
370 | }
371 | if (isset($video['Watermarks'])) {
372 | $requestBody['Video']['Watermarks'] = array(
373 | 'Id' => $video['Watermarks']['Id'],
374 | 'MaxWidth' => (array_key_exists('MaxWidth', $video['Watermarks'])) ? $video['Watermarks']['MaxWidth'] : '16',
375 | 'MaxHeight' => (array_key_exists('MaxHeight', $video['Watermarks'])) ? $video['Watermarks']['MaxHeight'] : '16',
376 | 'SizingPolicy' => (array_key_exists('SizingPolicy', $video['Watermarks'])) ? $video['Watermarks']['SizingPolicy'] : 'Fit',
377 | 'HorizontalAlign' => (array_key_exists('HorizontalAlign', $video['Watermarks'])) ? $video['Watermarks']['HorizontalAlign'] : 'Left',
378 | 'HorizontalOffset' => (array_key_exists('HorizontalOffset', $video['Watermarks'])) ? $video['Watermarks']['HorizontalOffset'] : '0%',
379 | 'VerticalAlign' => (array_key_exists('VerticalAlign', $video['Watermarks'])) ? $video['Watermarks']['VerticalAlign'] : 'Top',
380 | 'VerticalOffset' => (array_key_exists('VerticalOffset', $video['Watermarks'])) ? $video['Watermarks']['VerticalOffset'] : '0%',
381 | 'Opacity' => (array_key_exists('Opacity', $video['Watermarks'])) ? $video['Watermarks']['Opacity'] : '0',
382 | 'Target' => (array_key_exists('Target', $video['Target'])) ? $video['Watermarks']['Target'] : 'Content'
383 | );
384 | }
385 | $requestBody['Thumbnails'] = array(
386 | 'Format' => (array_key_exists('Format', $thumbnails)) ? $thumbnails['Format'] : 'jpg',
387 | 'Interval' => (array_key_exists('Interval', $thumbnails)) ? $thumbnails['Interval'] : '120',
388 | 'MaxWidth' => (array_key_exists('MaxWidth', $thumbnails)) ? $thumbnails['MaxWidth'] : 'auto',
389 | 'MaxHeight' => (array_key_exists('MaxHeight', $thumbnails)) ? $thumbnails['MaxHeight'] : 'auto',
390 | 'SizingPolicy' => (array_key_exists('SizingPolicy', $thumbnails)) ? $thumbnails['SizingPolicy'] : 'Fit',
391 | 'PaddingPolicy' => (array_key_exists('PaddingPolicy', $thumbnails)) ? $thumbnails['PaddingPolicy'] : 'Pad'
392 | );
393 | // Resolution and AspectRatio aren't recommended per AWS docs
394 | if (isset($thumbnails['Resolution']) && isset($thumbnails['AspectRatio'])) {
395 | unset($requestBody['Thumbnails']['MaxWidth']);
396 | unset($requestBody['Thumbnails']['MaxHeight']);
397 | unset($requestBody['Thumbnails']['SizingPolicy']);
398 | unset($requestBody['Thumbnails']['PaddingPolicy']);
399 | $requestBody['Thumbnails']['Resolution'] = $thumbnails['Resolution'];
400 | $requestBody['Thumbnails']['AspectRatio'] = $thumbnails['AspectRatio'];
401 | }
402 | $requestBody = json_encode($requestBody);
403 | self::setRequestBody($requestBody);
404 | $result = self::sendRequest();
405 | return $result;
406 | }
407 |
408 | /**
409 | * Get a list of all presets
410 | *
411 | * @return array | false
412 | */
413 | public static function listPresets() {
414 | self::resetProps();
415 | self::$HttpRequestMethod = 'GET';
416 | self::$Uri = '/2012-09-25/presets';
417 | $result = self::sendRequest();
418 | return $result;
419 | }
420 |
421 | /**
422 | * Get info about a preset
423 | *
424 | * @param string $presetId preset ID
425 | * @return array | false
426 | */
427 | public static function readPreset($presetId) {
428 | self::resetProps();
429 | self::$HttpRequestMethod = 'GET';
430 | self::$Uri = '/2012-09-25/presets/'.$presetId;
431 | $result = self::sendRequest();
432 | return $result;
433 | }
434 |
435 | /**
436 | * Delete a preset
437 | *
438 | * @param string $presetId preset ID
439 | * @return array | false
440 | */
441 | public static function deletePreset($presetId) {
442 | self::resetProps();
443 | self::$HttpRequestMethod = 'DELETE';
444 | self::$Uri = '/2012-09-25/presets/'.$presetId;
445 | $result = self::sendRequest();
446 | return $result;
447 | }
448 |
449 | /**
450 | * Set AWS credentials
451 | *
452 | * @param string $awsAccessKey AWS access key
453 | * @param string $awsPrivateKey AWS private key
454 | * @return void
455 | */
456 | public static function setAuth($awsAccessKey, $awsPrivateKey) {
457 | self::$AwsAccessKey = $awsAccessKey;
458 | self::$AwsPrivateKey = $awsPrivateKey;
459 | }
460 |
461 | /**
462 | * Set Amazon region
463 | *
464 | * @param string $region AWS region
465 | * @return void
466 | */
467 | public static function setRegion($region) {
468 | self::$Region = strtolower($region);
469 | }
470 |
471 | /**
472 | * Get the response HTTP status code
473 | *
474 | * @return integer
475 | */
476 | public static function getStatusCode() {
477 | return self::$ResponseStatus;
478 | }
479 |
480 | /**
481 | * Get server response
482 | *
483 | * @return mixed
484 | */
485 | public static function getResponse() {
486 | return self::$Response;
487 | }
488 |
489 | /**
490 | * Get error message after unsuccessful request
491 | *
492 | * @return string
493 | */
494 | public static function getErrorMsg() {
495 | return self::$ErrorMsg;
496 | }
497 |
498 | /**
499 | * Set error message
500 | *
501 | * @param string $error error message
502 | * @return void
503 | */
504 | private static function setErrorMsg($error) {
505 | self::$ErrorMsg = $error;
506 | }
507 |
508 | /**
509 | * Set request body
510 | *
511 | * @param mixed $body request body
512 | * @return void
513 | */
514 | private static function setRequestBody($body) {
515 | self::$RequestBody = $body;
516 | }
517 |
518 | /**
519 | * Set request header
520 | *
521 | * @param string $key key
522 | * @param string $value value
523 | * @return void
524 | */
525 | private static function setHeader($key, $value) {
526 | self::$Headers[$key] = $value;
527 | }
528 |
529 | /**
530 | * Reset property values
531 | *
532 | * @return void
533 | */
534 | private static function resetProps() {
535 | self::$Headers = array();
536 | self::$Date = new DateTime('UTC');
537 | self::$RequestBody = null;
538 | self::$ResponseStatus = null;
539 | self::$Response = null;
540 | self::$ErrorMsg = null;
541 | }
542 |
543 | /**
544 | * Executes server request
545 | *
546 | * @return array | false
547 | */
548 | private static function sendRequest() {
549 | $endpoint = 'elastictranscoder.'.self::$Region.'.amazonaws.com';
550 | self::setHeader('Host', $endpoint);
551 | self::setHeader('x-amz-date', self::$Date->format('Ymd\THis\Z'));
552 | self::setAuthorizationHeader();
553 |
554 | $curl = curl_init();
555 | curl_setopt($curl, CURLOPT_CUSTOMREQUEST, self::$HttpRequestMethod);
556 | $url = 'https://'.$endpoint . self::$Uri;
557 |
558 | if (self::$HttpRequestMethod == 'POST' || self::$HttpRequestMethod == 'PUT') {
559 | self::setHeader('Content-Type', 'application/json');
560 | self::setHeader('Content-Length', strlen(self::$RequestBody));
561 | curl_setopt($curl, CURLOPT_POSTFIELDS, self::$RequestBody);
562 | }
563 |
564 | $headers = array();
565 | foreach (self::$Headers as $header => $value) {
566 | if (strlen($value) > 0)
567 | $headers[] = $header.': '.$value;
568 | }
569 |
570 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
571 | curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
572 | curl_setopt($curl, CURLOPT_HEADER, false);
573 | curl_setopt($curl, CURLOPT_URL, $url);
574 |
575 | $result = curl_exec($curl);
576 |
577 | if ($result === false)
578 | self::setErrorMsg('Curl failed. Error code: '.curl_errno($curl).' Message: '.curl_error($curl));
579 | else
580 | self::$ResponseStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
581 |
582 | @curl_close($curl);
583 |
584 | if ($result === false)
585 | return false;
586 |
587 | $response = json_decode($result, true);
588 | self::$Response = $response;
589 |
590 | if (in_array(self::$ResponseStatus, array(200, 201, 202)))
591 | return $response;
592 |
593 | // Apparently "Message" is not always capitalized
594 | if (isset($response['message']))
595 | self::setErrorMsg($response['message']);
596 | if (isset($response['Message']))
597 | self::setErrorMsg($response['Message']);
598 | return false;
599 | }
600 |
601 | private static function hex16($val) {
602 | $unpack = unpack('H*', $val);
603 | return reset($unpack);
604 | }
605 |
606 | private static function parseCanonicalUri($url) {
607 | $parts = parse_url($url);
608 | $str = '';
609 | if (isset($parts['scheme'])) {
610 | $str .= $parts['scheme'];
611 | }
612 | if (isset($parts['host'])) {
613 | $str .= $parts['host'];
614 | }
615 | if (isset($parts['path'])) {
616 | $str .= $parts['path'];
617 | }
618 | return $str;
619 | }
620 |
621 | private static function parseQueryString($url) {
622 | $pos = strpos($url, '?');
623 | if (!$pos)
624 | return false;
625 | $url = substr($url, $pos + 1);
626 | if (empty($url))
627 | return false;
628 | $pairs = explode('&', $url);
629 | $urlVars = array();
630 | foreach ($pairs as $pair) {
631 | list($param, $value) = explode('=', $pair, 2);
632 | $urlVars[$param] = $value;
633 | }
634 | return $urlVars;
635 | }
636 |
637 | /**
638 | * Builds and sets authorization header
639 | *
640 | * @return array | false
641 | */
642 | private static function setAuthorizationHeader() {
643 | $canonicalRequest = array();
644 | $canonicalRequest[] = self::$HttpRequestMethod;
645 | $canonicalRequest[] = str_replace('%2F', '/', rawurlencode(self::parseCanonicalUri(self::$Uri)));
646 |
647 | // Format any query string
648 | $queryParams = self::parseQueryString(self::$Uri);
649 | if (!$queryParams) {
650 | $canonicalRequest[] = '';
651 | } else {
652 | $qs = '';
653 | ksort($queryParams);
654 | foreach($queryParams as $param => $value) {
655 | $qs .= rawurlencode($param) . '=' . rawurlencode($value) . '&';
656 | }
657 | $qs = substr($qs, 0, -1);
658 | $canonicalRequest[] = $qs;
659 | }
660 |
661 | $headers = array();
662 | $canonicalHeaders = array();
663 | $signedHeaders = array();
664 |
665 | foreach (self::$Headers as $key => $value) {
666 | $headers[strtolower($key)] = trim($value);
667 | }
668 |
669 | ksort($headers);
670 |
671 | foreach ($headers as $key => $value) {
672 | $signedHeaders[] = $key;
673 | $canonicalHeaders[] = $key . ':' . $value;
674 | }
675 |
676 | $signedHeaders = implode(';', $signedHeaders);
677 |
678 | $canonicalRequest[] = implode("\n", $canonicalHeaders);
679 | $canonicalRequest[] = '';
680 | $canonicalRequest[] = $signedHeaders;
681 | $canonicalRequest[] = self::hex16(hash('sha256', self::$RequestBody, true));
682 | $canonicalRequest = implode("\n", $canonicalRequest);
683 |
684 | $stringToSign = array();
685 | $stringToSign[] = 'AWS4-HMAC-SHA256';
686 | $stringToSign[] = self::$Date->format('Ymd\THis\Z');
687 |
688 | $credentialScope = array(self::$Date->format('Ymd'));
689 | $credentialScope[] = self::$Region;
690 | $credentialScope[] = 'elastictranscoder';
691 | $credentialScope[] = 'aws4_request';
692 | $credentialScope = implode('/', $credentialScope);
693 |
694 | $stringToSign[] = $credentialScope;
695 | $stringToSign[] = self::hex16(hash('sha256', $canonicalRequest, true));
696 | $stringToSign = implode("\n", $stringToSign);
697 |
698 | $kSecret = 'AWS4'.self::$AwsPrivateKey;
699 | $kDate = hash_hmac('sha256', self::$Date->format('Ymd'), $kSecret, true);
700 | $kRegion = hash_hmac('sha256', self::$Region, $kDate, true);
701 | $kService = hash_hmac('sha256', 'elastictranscoder', $kRegion, true);
702 | $kSigning = hash_hmac('sha256', 'aws4_request', $kService, true);
703 | $signature = hash_hmac('sha256', $stringToSign, $kSigning, true);
704 |
705 | $auth = 'AWS4-HMAC-SHA256 Credential='.self::$AwsAccessKey.'/'.$credentialScope;
706 | $auth .= ',SignedHeaders='.$signedHeaders;
707 | $auth .= ',Signature='.self::hex16($signature);
708 | self::setHeader('Authorization', $auth);
709 | }
710 |
711 | }
712 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Elastic Transcoder PHP Class
2 | ====================
3 |
4 | PHP class for interacting with Amazon Elastic Transcoder that does not require PEAR.
5 |
6 | #### Usage ###
7 |
8 | Object-oriented method:
9 |
10 | ```php
11 | $et = new AWS_ET($awsAccessKey, $awsSecretKey, $awsRegion);
12 | ```
13 |
14 | Statically:
15 |
16 | ```php
17 | AWS_ET::setAuth($awsAccessKey, $awsSecretKey, $awsRegion);
18 | ```
19 |
20 | Note: us-east-1 is the default AWS region setting. The third parameter is optional for us-east-1 users.
21 |
22 | #### Job Operations ####
23 |
24 | Creating a transcoding job:
25 |
26 | ```php
27 | $pipelineId = 'pipelineId';
28 | $input = array('Key' => 'inputFile');
29 | $output = array(
30 | 'Key' => 'outputFile.mp4',
31 | 'PresetId' => 'presetId'
32 | );
33 |
34 | $result = AWS_ET::createJob($input, array($output), $pipelineId);
35 |
36 | if (!$result) {
37 | echo AWS_ET::getErrorMsg();
38 | } else {
39 | echo 'New job ID: ' . $result['Job']['Id'];
40 | }
41 | ```
42 |
43 | List jobs by pipeline:
44 |
45 | ```php
46 | AWS_ET::listJobsByPipeline( string $pipelineId [, boolean $ascending = true ] );
47 | ```
48 |
49 | List jobs by status:
50 |
51 | ```php
52 | AWS_ET::listJobsByStatus( string $status );
53 | ```
54 |
55 | Get job info:
56 |
57 | ```php
58 | AWS_ET::readJob( string $jobId );
59 | ```
60 |
61 | Cancel a job:
62 |
63 | ```php
64 | AWS_ET::cancelJob( string $jobId );
65 | ```
66 |
67 | #### Pipeline Operations ####
68 |
69 | Create a new pipeline:
70 |
71 | ```php
72 | AWS_ET::createPipeline( string $name, string $inputBucket, string $outputBucket, string $role [, array $notifications ] );
73 | ```
74 |
75 | Get a list pipelines:
76 |
77 | ```php
78 | AWS_ET::listPipelines();
79 | ```
80 |
81 | Get info about a pipeline:
82 |
83 | ```php
84 | AWS_ET::readPipeline( string $pipelineId );
85 | ```
86 |
87 | Update pipeline settings:
88 |
89 | ```php
90 | AWS_ET::updatePipeline( string $pipelineId, array $updates );
91 | ```
92 |
93 | Change the status of a pipeline (active/paused):
94 |
95 | ```php
96 | AWS_ET::updatePipelineStatus( string $pipelineId, string $status );
97 | ```
98 |
99 | Update pipeline notification settings:
100 |
101 | ```php
102 | AWS_ET::updatePipelineNotifications( string $pipelineId [, array $notifications ] );
103 | ```
104 |
105 | Delete a pipeline:
106 |
107 | ```php
108 | AWS_ET::deletePipeline( string $pipelineId );
109 | ```
110 |
111 | Test the settings for a pipeline:
112 |
113 | ```php
114 | AWS_ET::testRole( string $inputBucket, string $outputBucket, string $role, array $topics );
115 | ```
116 |
117 | #### Preset Operations ####
118 |
119 | Create a preset:
120 |
121 | ```php
122 | AWS_ET::createPreset( array $options );
123 | ```
124 |
125 | List all presets:
126 |
127 | ```php
128 | AWS_ET::listPresets();
129 | ```
130 |
131 | Get info about a preset:
132 |
133 | ```php
134 | AWS_ET::readPreset( string $presetId );
135 | ```
136 |
137 | Delete a preset:
138 |
139 | ```php
140 | AWS_ET::deletePreset( string $presetId );
141 | ```
142 |
143 | #### Misc. ####
144 |
145 | Set AWS authentication credentials:
146 |
147 | ```php
148 | AWS_ET::setAuth( string $awsAccessKey, string $awsSecretKey );
149 | ```
150 |
151 | Set AWS region:
152 |
153 | ```php
154 | AWS_ET::setRegion( string $region = 'us-east-1' );
155 | ```
156 |
157 | Get HTTP status code of server response:
158 |
159 | ```php
160 | AWS_ET::getStatusCode();
161 | ```
162 |
163 | Get server response:
164 |
165 | ```php
166 | AWS_ET::getResponse();
167 | ```
168 |
169 | Get error message, if any:
170 |
171 | ```php
172 | AWS_ET::getErrorMsg();
173 | ```
174 |
175 |
176 | More Information:
177 | Getting Started with Elastic Transcoder
178 |
179 | #### License ####
180 |
181 | Released under the MIT license.
182 |
183 | [](http://githalytics.com/LPology/ElasticTranscoderPHP)
--------------------------------------------------------------------------------