2012-04-17 91 views
6

這已經過很多次了,但我仍然有點困惑。很多答案只是談論上傳進度條,並沒有從S3上傳獲取實際上傳進度。PHP S3上傳進度

我已經閱讀了大量的問題,並找到了一些軟件,但我仍然沒有接近理解S3上傳的基本問題。

有沒有辦法在上傳到S3的同時瞭解上傳的進度,而不必使用我自己的應用程序服務器資源將文件存儲在臨時目錄中?

我必須先將文件存儲在我自己的服務器上,然後再推送到S3?我曾經聽過人們一次談論S3的流式傳輸(一次一個),但我不確定這涉及到什麼。想象一下,我是從HTML頁面的客戶端上傳的,我怎樣才能通過來自多部分的塊來傳輸文件塊? (我沒有看到任何這樣的例子,只是當文件已經在你的系統上,並且你知道那些塊沒有用的時候tbh)。

當然在API文檔中有一個上傳進度的例子,但是又一次假定文件首先在服務器上,而不是來自用戶提供的另一臺計算機。

編輯:我最初的想法是製作一個PHP腳本,可以在AWS每次獲取上傳進度時都能ping通一次。我正在通過API看看他們是否支持類似的東西,但沒有運氣。讓我知道,如果有什麼...

進一步編輯:閃光是唯一的方式去與此?

感謝,

回答

3

YES,可以在AWS PHP SDK V3。

$client = new S3Client(/* config */); 

$result = $client->putObject([ 
    'Bucket'  => 'bucket-name', 
    'Key'  => 'bucket-name/file.ext', 
    'SourceFile' => 'local-file.ext', 
    'ContentType' => 'application/pdf', 
    '@http' => [ 
     'progress' => function ($downloadTotalSize, $downloadSizeSoFar, $uploadTotalSize, $uploadSizeSoFar) { 
      printf(
       "%s of %s downloaded, %s of %s uploaded.\n", 
       $downloadSizeSoFar, 
       $downloadTotalSize, 
       $uploadSizeSoFar, 
       $uploadTotalSize 
      ); 
     } 
    ] 
]); 

這在AWS文檔 - S3 Config section中有解釋。它通過暴露GuzzleHttp的progress屬性可調用來工作,如this SO answer中所解釋的。

0

很多周圍搜索後,我發現簡單的回答這個問題是NO。

基本上這樣做的最好方法,就像我從亞馬遜自己的編碼(他們在AWS S3控制檯上的小上傳小部件)中發現的那樣,只有真正有可能通過首先發送到另一個服務器來獲得上載進度,閱讀進度信息。

這會使用您自己的應用程序服務器/ tmp目錄作爲跳板,創建一個「傳遞」策略。這似乎是首選的方法。

+0

你是否還有任何可用的例子?我可能需要做類似的事情。 – trainoasis 2016-08-24 09:18:26

+0

只有非常舊的代碼我認爲不適用於他們的新API,基本上,您會正常上傳到我們自己的服務器,然後以完整形式或每個大塊複製到S3(使用多部分形式,你可以得到的大塊,然後它完全上傳到PHP中的PHP) – Sammaye 2016-08-24 09:21:21

+0

好的謝謝,將這樣做.. – trainoasis 2016-08-24 09:30:42

0

AWS PHP SDK有一個代碼示例,它顯示上傳到S3時的上傳進度。我不確定它是否適用於小文件,但流式傳輸確實有效。

您可以檢查在多出來 - http://aws.amazon.com/sdkforphp/

在某種程度上,如果他們表現出的進步 - 我們一定可以得到與JavaScript框架的幫助,如jQuery等

進度條的形式

我很快就會開始工作,一定會發佈一個教程。乾杯!

+0

我非常喜歡這個問題,這個問題寫了大約4個版本之前所以我會非常感興趣,如果事情發生了變化,並且AWS確實有很好的方法來處理這個問題 – Sammaye 2013-02-03 16:05:45

+1

如果您可以通過代碼示例鏈接到特定頁面而不僅僅是sdk主頁,那將是最好的。 – 2013-12-28 22:35:15

+0

您是否在此發佈教程? – trainoasis 2016-08-25 06:28:08

0

是的,你可以通過多上傳:http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMPphpAPI.html

多部分上傳的是一個三步驟的過程:您開始上傳,上傳的對象部分,並上傳了所有的零件後,完成了多載。收到完整的分段上傳請求後,Amazon S3會從上傳的部分構建對象,然後您可以像訪問存儲桶中的任何其他對象一樣訪問該對象。

http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html

我將親自很快這樣做,但是這是你需要開始什麼。

+0

您仍然必須將其上載到您自己的服務器以瞭解進度,因爲您必須先在服務器上擁有文件總大小,然後才能對其進行任何操作。實際上,您將首先像往常一樣將它上傳到您的sertver,然後多部分上傳到亞馬遜以獲取上傳進度,這意味着您實際上只會判斷服務器上傳的進度。我想你可以重寫核心PHP腳本來釋放上傳到Amazon的上傳部分,但是PHP內核目前不會這麼做 – Sammaye 2013-02-27 08:28:07

+0

@Sammaye我實際上正在做這個atm,我不得不上傳到服務器然後到S3。在我想直接進入S3之前,我會寫一些小技巧或者暫時寫一個文件給我的用戶發送反饋。只要你可以看到或使用這個多部分功能,你應該能夠以某種方式掛鉤。 – 2013-02-27 19:01:10

+1

@MichaelCalkins你有沒有得到這個成就? 2014年幾乎已經完成,我仍然無法看到明確的答案來做到這一點? – turntwo 2014-11-21 07:20:44

-2

是的,你可以通過修改s3.php這樣做,

<?php 
class S3Withprogressbar { 
// ACL flags 
const ACL_PRIVATE = 'private'; 
const ACL_PUBLIC_READ = 'public-read'; 
const ACL_PUBLIC_READ_WRITE = 'public-read-write'; 
private static $__accessKey; // AWS Access key 
private static $__secretKey; // AWS Secret key 
public static $_uploadProgressFileName="" ;//uploadProgressFileName 
public function __construct($accessKey = null, $secretKey = null) { 
if ($accessKey !== null && $secretKey !== null) 
self::setAuth($accessKey, $secretKey); 
} 
public static function setAuth($accessKey, $secretKey) { 
self::$__accessKey = $accessKey; 
self::$__secretKey = $secretKey; 
} 
public static function listBuckets($detailed = false) { 
$rest = new S3Request('GET', '', ''); 
$rest = $rest->getResponse(); 
if ($rest->error === false && $rest->code !== 200) 
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); 
if ($rest->error !== false) { 
trigger_error(sprintf("S3Withprogressbar::listBuckets(): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING); 
return false; 
} 
$results = array(); //var_dump($rest->body); 
if (!isset($rest->body->Buckets)) return $results; 
if ($detailed) { 
if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName)) 
$results['owner'] = array(
'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->ID 
); 
$results['buckets'] = array(); 
foreach ($rest->body->Buckets->Bucket as $b) 
$results['buckets'][] = array(
'name' => (string)$b->Name, 'time' => strtotime((string)$b->CreationDate) 
); 
} else 
foreach ($rest->body->Buckets->Bucket as $b) $results[] = (string)$b->Name; 
return $results; 
} 
public static function getBucket($bucket, $prefix = null, $marker = null, $maxKeys = null) { 
$rest = new S3Request('GET', $bucket, ''); 
if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix); 
if ($marker !== null && $prefix !== '') $rest->setParameter('marker', $marker); 
if ($maxKeys !== null && $prefix !== '') $rest->setParameter('max-keys', $maxKeys); 
$response = $rest->getResponse(); 
if ($response->error === false && $response->code !== 200) 
$response->error = array('code' => $response->code, 'message' => 'Unexpected HTTP status'); 
if ($response->error !== false) { 
trigger_error(sprintf("S3Withprogressbar::getBucket(): [%s] %s", $response->error['code'], $response->error['message']), E_USER_WARNING); 
return false; 
} 
$results = array(); 
$lastMarker = null; 
if (isset($response->body, $response->body->Contents)) 
foreach ($response->body->Contents as $c) { 
$results[(string)$c->Key] = array(
'name' => (string)$c->Key, 
'time' => strToTime((string)$c->LastModified), 
'size' => (int)$c->Size, 
'hash' => substr((string)$c->ETag, 1, -1) 
); 
$lastMarker = (string)$c->Key; 
//$response->body->IsTruncated = 'true'; break; 
} 
if (isset($response->body->IsTruncated) && 
(string)$response->body->IsTruncated == 'false') return $results; 
// Loop through truncated results if maxKeys isn't specified 
if ($maxKeys == null && $lastMarker !== null && (string)$response->body->IsTruncated == 'true') 
do { 
$rest = new S3Request('GET', $bucket, ''); 
if ($prefix !== null) $rest->setParameter('prefix', $prefix); 
$rest->setParameter('marker', $lastMarker); 
if (($response = $rest->getResponse(true)) == false || $response->code !== 200) break; 
if (isset($response->body, $response->body->Contents)) 
foreach ($response->body->Contents as $c) { 
$results[(string)$c->Key] = array(
'name' => (string)$c->Key, 
'time' => strToTime((string)$c->LastModified), 
'size' => (int)$c->Size, 
'hash' => substr((string)$c->ETag, 1, -1) 
); 
$lastMarker = (string)$c->Key; 
} 
} while ($response !== false && (string)$response->body->IsTruncated == 'true'); 
return $results; 
} 
public function putBucket($bucket, $acl = self::ACL_PRIVATE) { 
$rest = new S3Request('PUT', $bucket, ''); 
$rest->setAmzHeader('x-amz-acl', $acl); 
$rest = $rest->getResponse(); 
if ($rest->error === false && $rest->code !== 200) 
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); 
if ($rest->error !== false) { 
//trigger_error(sprintf("S3Withprogressbar::putBucket({$bucket}): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING); 
return false; 
} 
return true; 
} 
public function deleteBucket($bucket = '') { 
$rest = new S3Request('DELETE', $bucket); 
$rest = $rest->getResponse(); 
if ($rest->error === false && $rest->code !== 204) 
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); 
if ($rest->error !== false) { 
trigger_error(sprintf("S3Withprogressbar::deleteBucket({$bucket}): [%s] %s", 
$rest->error['code'], $rest->error['message']), E_USER_WARNING); 
return false; 
} 
return true; 
} 
public static function inputFile($file, $md5sum = true) { 
if (!file_exists($file) || !is_file($file) || !is_readable($file)) { 
trigger_error('S3Withprogressbar::inputFile(): Unable to open input file: '.$file, E_USER_WARNING); 
return false; 
} 
return array('file' => $file, 'size' => filesize($file), 
'md5sum' => $md5sum !== false ? (is_string($md5sum) ? $md5sum : 
base64_encode(md5_file($file, true))) : ''); 
} 
public static function inputResource(&$resource, $bufferSize, $md5sum = '') { 
if (!is_resource($resource) || $bufferSize <= 0) { 
trigger_error('S3Withprogressbar::inputResource(): Invalid resource or buffer size', E_USER_WARNING); 
return false; 
} 
$input = array('size' => $bufferSize, 'md5sum' => $md5sum); 
$input['fp'] =& $resource; 
return $input; 
} 
// Modified Function with one more parameter $uploadProgressFileName 
public static function putObject($input, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = null,$uploadProgressFileName) { 
if ($input == false) return false; 
$rest = new S3Request('PUT', $bucket, $uri); 
// Set public variable value($uploadProgressFileName) in S3Request class 
$rest->uploadProgressFileName = $uploadProgressFileName; 
if (is_string($input)) $input = array(
'data' => $input, 'size' => strlen($input), 
'md5sum' => base64_encode(md5($input, true)) 
); 
// Data 
if (isset($input['fp'])) 
$rest->fp =& $input['fp']; 
elseif (isset($input['file'])) 
$rest->fp = @fopen($input['file'], 'rb'); 
elseif (isset($input['data'])) 
$rest->data = $input['data']; 
// Content-Length (required) 
if (isset($input['size']) && $input['size'] > 0) 
$rest->size = $input['size']; 
else { 
if (isset($input['file'])) 
$rest->size = filesize($input['file']); 
elseif (isset($input['data'])) 
$rest->size = strlen($input['data']); 
} 
// Content-Type 
if ($contentType !== null) 
$input['type'] = $contentType; 
elseif (!isset($input['type']) && isset($input['file'])) 
$input['type'] = self::__getMimeType($input['file']); 
else 
$input['type'] = 'application/octet-stream'; 
// We need to post with the content-length and content-type, MD5 is optional 
if ($rest->size > 0 && ($rest->fp !== false || $rest->data !== false)) { 
$rest->setHeader('Content-Type', $input['type']); 
if (isset($input['md5sum'])) $rest->setHeader('Content-MD5', $input['md5sum']); 
$rest->setAmzHeader('x-amz-acl', $acl); 
foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v); 
$rest->getResponse(); 
} else 
$rest->response->error = array('code' => 0, 'message' => 'Missing input parameters'); 
if ($rest->response->error === false && $rest->response->code !== 200) 
$rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status'); 
if ($rest->response->error !== false) { 
//trigger_error(sprintf("S3Withprogressbar::putObject(): [%s] %s", $rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING); 
return false; 
} 
return true; 
} 
// Modified Function with one more parameter $uploadProgressFileName 
public static function putObjectFile($file, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = null,$uploadProgressFileName) { 
return self::putObject(S3Withprogressbar::inputFile($file), $bucket, $uri, $acl, $metaHeaders, $contentType,$uploadProgressFileName); 
} 
public function putObjectString($string, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = 'text/plain') { 
return self::putObject($string, $bucket, $uri, $acl, $metaHeaders, $contentType); 
} 
public static function getObject($bucket = '', $uri = '', $saveTo = false) { 
$rest = new S3Request('GET', $bucket, $uri); 
if ($saveTo !== false) { 
if (is_resource($saveTo)) 
$rest->fp =& $saveTo; 
else 
if (($rest->fp = @fopen($saveTo, 'wb')) == false) 
$rest->response->error = array('code' => 0, 'message' => 'Unable to open save file for writing: '.$saveTo); 
} 
if ($rest->response->error === false) $rest->getResponse(); 
if ($rest->response->error === false && $rest->response->code !== 200) 
$rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status'); 
if ($rest->response->error !== false) { 
trigger_error(sprintf("S3Withprogressbar::getObject({$bucket}, {$uri}): [%s] %s", 
$rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING); 
return false; 
} 
$rest->file = realpath($saveTo); 
return $rest->response; 
} 
public static function getObjectInfo($bucket = '', $uri = '', $returnInfo = true) { 
$rest = new S3Request('HEAD', $bucket, $uri); 
$rest = $rest->getResponse(); 
if ($rest->error === false && ($rest->code !== 200 && $rest->code !== 404)) 
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); 
if ($rest->error !== false) { 
trigger_error(sprintf("S3Withprogressbar::getObjectInfo({$bucket}, {$uri}): [%s] %s", 
$rest->error['code'], $rest->error['message']), E_USER_WARNING); 
return false; 
} 
return $rest->code == 200 ? $returnInfo ? $rest->headers : true : false; 
} 
public static function setBucketLogging($bucket, $targetBucket, $targetPrefix) { 
$dom = new DOMDocument; 
$bucketLoggingStatus = $dom->createElement('BucketLoggingStatus'); 
$bucketLoggingStatus->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/'); 
$loggingEnabled = $dom->createElement('LoggingEnabled'); 
$loggingEnabled->appendChild($dom->createElement('TargetBucket', $targetBucket)); 
$loggingEnabled->appendChild($dom->createElement('TargetPrefix', $targetPrefix)); 
// TODO: Add TargetGrants 
$bucketLoggingStatus->appendChild($loggingEnabled); 
$dom->appendChild($bucketLoggingStatus); 
$rest = new S3Request('PUT', $bucket, ''); 
$rest->setParameter('logging', null); 
$rest->data = $dom->saveXML(); 
$rest->size = strlen($rest->data); 
$rest->setHeader('Content-Type', 'application/xml'); 
$rest = $rest->getResponse(); 
if ($rest->error === false && $rest->code !== 200) 
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); 
if ($rest->error !== false) { 
trigger_error(sprintf("S3Withprogressbar::setBucketLogging({$bucket}, {$uri}): [%s] %s", 
$rest->error['code'], $rest->error['message']), E_USER_WARNING); 
return false; 
} 
return true; 
} 
public static function getBucketLogging($bucket = '') { 
$rest = new S3Request('GET', $bucket, ''); 
$rest->setParameter('logging', null); 
$rest = $rest->getResponse(); 
if ($rest->error === false && $rest->code !== 200) 
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); 
if ($rest->error !== false) { 
trigger_error(sprintf("S3Withprogressbar::getBucketLogging({$bucket}): [%s] %s", 
$rest->error['code'], $rest->error['message']), E_USER_WARNING); 
return false; 
} 
if (!isset($rest->body->LoggingEnabled)) return false; // No logging 
return array(
'targetBucket' => (string)$rest->body->LoggingEnabled->TargetBucket, 
'targetPrefix' => (string)$rest->body->LoggingEnabled->TargetPrefix, 
); 
} 
public static function setAccessControlPolicy($bucket, $uri = '', $acp = array()) { 
$dom = new DOMDocument; 
$dom->formatOutput = true; 
$accessControlPolicy = $dom->createElement('AccessControlPolicy'); 
$accessControlList = $dom->createElement('AccessControlList'); 
// It seems the owner has to be passed along too 
$owner = $dom->createElement('Owner'); 
$owner->appendChild($dom->createElement('ID', $acp['owner']['id'])); 
$owner->appendChild($dom->createElement('DisplayName', $acp['owner']['name'])); 
$accessControlPolicy->appendChild($owner); 
foreach ($acp['acl'] as $g) { 
$grant = $dom->createElement('Grant'); 
$grantee = $dom->createElement('Grantee'); 
$grantee->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); 
if (isset($g['id'])) { // CanonicalUser (DisplayName is omitted) 
$grantee->setAttribute('xsi:type', 'CanonicalUser'); 
$grantee->appendChild($dom->createElement('ID', $g['id'])); 
} elseif (isset($g['email'])) { // AmazonCustomerByEmail 
$grantee->setAttribute('xsi:type', 'AmazonCustomerByEmail'); 
$grantee->appendChild($dom->createElement('EmailAddress', $g['email'])); 
} elseif ($g['type'] == 'Group') { // Group 
$grantee->setAttribute('xsi:type', 'Group'); 
$grantee->appendChild($dom->createElement('URI', $g['uri'])); 
} 
$grant->appendChild($grantee); 
$grant->appendChild($dom->createElement('Permission', $g['permission'])); 
$accessControlList->appendChild($grant); 
} 
$accessControlPolicy->appendChild($accessControlList); 
$dom->appendChild($accessControlPolicy); 
$rest = new S3Request('PUT', $bucket, ''); 
$rest->setParameter('acl', null); 
$rest->data = $dom->saveXML(); 
$rest->size = strlen($rest->data); 
$rest->setHeader('Content-Type', 'application/xml'); 
$rest = $rest->getResponse(); 
if ($rest->error === false && $rest->code !== 200) 
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); 
if ($rest->error !== false) { 
trigger_error(sprintf("S3Withprogressbar::setAccessControlPolicy({$bucket}, {$uri}): [%s] %s", 
$rest->error['code'], $rest->error['message']), E_USER_WARNING); 
return false; 
} 
return true; 
} 
public static function getAccessControlPolicy($bucket, $uri = '') { 
$rest = new S3Request('GET', $bucket, $uri); 
$rest->setParameter('acl', null); 
$rest = $rest->getResponse(); 
if ($rest->error === false && $rest->code !== 200) 
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); 
if ($rest->error !== false) { 
trigger_error(sprintf("S3Withprogressbar::getAccessControlPolicy({$bucket}, {$uri}): [%s] %s", 
$rest->error['code'], $rest->error['message']), E_USER_WARNING); 
return false; 
} 
$acp = array(); 
if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName)) { 
$acp['owner'] = array(
'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->DisplayName 
); 
} 
if (isset($rest->body->AccessControlList)) { 
$acp['acl'] = array(); 
foreach ($rest->body->AccessControlList->Grant as $grant) { 
foreach ($grant->Grantee as $grantee) { 
if (isset($grantee->ID, $grantee->DisplayName)) // CanonicalUser 
$acp['acl'][] = array(
'type' => 'CanonicalUser', 
'id' => (string)$grantee->ID, 
'name' => (string)$grantee->DisplayName, 
'permission' => (string)$grant->Permission 
); 
elseif (isset($grantee->EmailAddress)) // AmazonCustomerByEmail 
$acp['acl'][] = array(
'type' => 'AmazonCustomerByEmail', 
'email' => (string)$grantee->EmailAddress, 
'permission' => (string)$grant->Permission 
); 
elseif (isset($grantee->URI)) // Group 
$acp['acl'][] = array(
'type' => 'Group', 
'uri' => (string)$grantee->URI, 
'permission' => (string)$grant->Permission 
); 
else continue; 
} 
} 
} 
return $acp; 
} 
public static function deleteObject($bucket = '', $uri = '') { 
$rest = new S3Request('DELETE', $bucket, $uri); 
$rest = $rest->getResponse(); 
if ($rest->error === false && $rest->code !== 204) 
$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); 
if ($rest->error !== false) { 
trigger_error(sprintf("S3Withprogressbar::deleteObject(): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING); 
return false; 
} 
return true; 
} 
public static function __getMimeType(&$file) { 
$type = false; 
// Fileinfo documentation says fileinfo_open() will use the 
// MAGIC env var for the magic file 
if (extension_loaded('fileinfo') && isset($_ENV['MAGIC']) && 
($finfo = finfo_open(FILEINFO_MIME, $_ENV['MAGIC'])) !== false) { 
if (($type = finfo_file($finfo, $file)) !== false) { 
// Remove the charset and grab the last content-type 
$type = explode(' ', str_replace('; charset=', ';charset=', $type)); 
$type = array_pop($type); 
$type = explode(';', $type); 
$type = array_shift($type); 
} 
finfo_close($finfo); 
// If anyone is still using mime_content_type() 
} elseif (function_exists('mime_content_type')) 
$type = mime_content_type($file); 
if ($type !== false && strlen($type) > 0) return $type; 
// Otherwise do it the old fashioned way 
static $exts = array(
'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png', 
'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ico' => 'image/x-icon', 
'swf' => 'application/x-shockwave-flash', 'pdf' => 'application/pdf', 
'zip' => 'application/zip', 'gz' => 'application/x-gzip', 
'tar' => 'application/x-tar', 'bz' => 'application/x-bzip', 
'bz2' => 'application/x-bzip2', 'txt' => 'text/plain', 
'asc' => 'text/plain', 'htm' => 'text/html', 'html' => 'text/html', 
'xml' => 'text/xml', 'xsl' => 'application/xsl+xml', 
'ogg' => 'application/ogg', 'mp3' => 'audio/mpeg', 'wav' => 'audio/x-wav', 
'avi' => 'video/x-msvideo', 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg', 
'mov' => 'video/quicktime', 'flv' => 'video/x-flv', 'php' => 'text/x-php' 
); 
$ext = strToLower(pathInfo($file, PATHINFO_EXTENSION)); 
return isset($exts[$ext]) ? $exts[$ext] : 'application/octet-stream'; 
} 
public static function __getSignature($string) { 
return 'AWS '.self::$__accessKey.':'.base64_encode(extension_loaded('hash') ? 
hash_hmac('sha1', $string, self::$__secretKey, true) : pack('H*', sha1(
(str_pad(self::$__secretKey, 64, chr(0x00))^(str_repeat(chr(0x5c), 64))) . 
pack('H*', sha1((str_pad(self::$__secretKey, 64, chr(0x00))^
(str_repeat(chr(0x36), 64))) . $string))))); 
} 
} 
final class S3Request { 
private $verb, $bucket, $uri, $resource = '', $parameters = array(), 
$amzHeaders = array(), $headers = array(
'Host' => '', 'Date' => '', 'Content-MD5' => '', 'Content-Type' => '' 
); 
public $fp = false, $size = 0, $data = false, $response; 
public $uploadProgressFileName; 
function __construct($verb, $bucket = '', $uri = '') { 
$this->verb = $verb; 
$this->bucket = strtolower($bucket); 
$this->uri = $uri !== '' ? '/'.$uri : '/'; 
if ($this->bucket !== '') { 
$this->bucket = explode('/', $this->bucket); 
$this->resource = '/'.$this->bucket[0].$this->uri; 
$this->headers['Host'] = $this->bucket[0].'.s3.amazonaws.com'; 
$this->bucket = implode('/', $this->bucket); 
} else { 
$this->headers['Host'] = 's3.amazonaws.com'; 
if (strlen($this->uri) > 1) 
$this->resource = '/'.$this->bucket.$this->uri; 
else $this->resource = $this->uri; 
} 
$this->headers['Date'] = gmdate('D, d M Y H:i:s T'); 
$this->response = new STDClass; 
$this->response->error = false; 
$this->response->body = false; 
$CI =& get_instance(); 
$CI->load->helper('file'); 
} 
public function setParameter($key, $value) { 
$this->parameters[$key] = $value; 
} 
public function setHeader($key, $value) { 
$this->headers[$key] = $value; 
} 
public function setAmzHeader($key, $value) { 
$this->amzHeaders[$key] = $value; 
} 
//:callback function for upload progress. 
public function progressCallback_new_curl($new,$download_size, $downloaded_size, $upload_size, $uploaded_size) 
{ 
ob_start(); 
static $previousProgress = 0; 
if ($upload_size == 0) 
$progress = 0; 
else 
$progress = round($uploaded_size * 100/$upload_size); 
if ($progress > $previousProgress) 
{ 
flush(); 
$previousProgress = $progress; 
$new_file_path = FCPATH.'upload/'.$this->uploadProgressFileName.'.txt'; // modify this line to point to the actual location of the file 
write_file($new_file_path, $progress."\n"); 
// Check for Cancel upload text file and if exists return 1 to interrupt curl upload process. 
$cancel_path=FCPATH.'upload/cancel_'.$this->uploadProgressFileName.'.txt'; 
if(file_exists($cancel_path)){ 
unlink($cancel_path); 
if(file_exists($new_file_path)){ 
unlink($new_file_path); 
} 
return 1; 
} 
}   
ob_flush(); 
flush();       
} 
public function progressCallback_old_curl($download_size, $downloaded_size, $upload_size, $uploaded_size) 
{ 
ob_start(); 
static $previousProgress = 0; 
if ($upload_size == 0) 
$progress = 0; 
else 
$progress = round($uploaded_size * 100/$upload_size); 
if ($progress > $previousProgress) 
{ 
flush(); 
$previousProgress = $progress; 
$new_file_path = FCPATH.'upload/'.$this->uploadProgressFileName.'.txt'; // modify this line to point to the actual location of the file 
write_file($new_file_path, $progress."\n"); 
// Check for Cancel upload text file and if exists return 1 to interrupt curl upload process. 
$cancel_path=FCPATH.'upload/cancel_'.$this->uploadProgressFileName.'.txt'; 
if(file_exists($cancel_path)){ 
unlink($cancel_path); 
if(file_exists($new_file_path)){ 
unlink($new_file_path); 
} 
return 1; 
} 
} 
ob_flush(); 
flush(); 
} 
public function getResponse() { 
$query = ''; 
if (sizeof($this->parameters) > 0) { 
$query = substr($this->uri, -1) !== '?' ? '?' : '&'; 
foreach ($this->parameters as $var => $value) 
if ($value == null || $value == '') $query .= $var.'&'; 
else $query .= $var.'='.$value.'&'; 
$query = substr($query, 0, -1); 
$this->uri .= $query; 
if (isset($this->parameters['acl']) || !isset($this->parameters['logging'])) 
$this->resource .= $query; 
} 
$url = (extension_loaded('openssl')?'https://':'http://').$this->headers['Host'].$this->uri; 
//var_dump($this->bucket, $this->uri, $this->resource, $url); 
// Basic setup 
$curl = curl_init(); 
curl_setopt($curl, CURLOPT_USERAGENT, 'S3/php'); 
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); 
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); 
curl_setopt($curl, CURLOPT_URL, $url); 
//:callback function call for upload progress. 
curl_setopt($curl, CURLOPT_NOPROGRESS, false); 
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50500) { 
curl_setopt($curl, CURLOPT_PROGRESSFUNCTION, array($this, 'progressCallback_old_curl')); 
} else { 
curl_setopt($curl, CURLOPT_PROGRESSFUNCTION, array($this, 'progressCallback_new_curl')); 
} 
// Headers 
$headers = array(); $amz = array(); 
foreach ($this->amzHeaders as $header => $value) 
if (strlen($value) > 0) $headers[] = $header.': '.$value; 
foreach ($this->headers as $header => $value) 
if (strlen($value) > 0) $headers[] = $header.': '.$value; 
foreach ($this->amzHeaders as $header => $value) 
if (strlen($value) > 0) $amz[] = strToLower($header).':'.$value; 
$amz = (sizeof($amz) > 0) ? "\n".implode("\n", $amz) : ''; 
// Authorization string 
$headers[] = 'Authorization: ' . S3Withprogressbar::__getSignature(
$this->verb."\n". 
$this->headers['Content-MD5']."\n". 
$this->headers['Content-Type']."\n". 
$this->headers['Date'].$amz."\n".$this->resource 
); 
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); 
curl_setopt($curl, CURLOPT_HEADER, false); 
curl_setopt($curl, CURLOPT_RETURNTRANSFER, false); 
curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback')); 
curl_setopt($curl, CURLOPT_HEADERFUNCTION, array(&$this, '__responseHeaderCallback')); 
// Request types 
switch ($this->verb) { 
case 'GET': break; 
case 'PUT': 
if ($this->fp !== false) { 
curl_setopt($curl, CURLOPT_PUT, true); 
curl_setopt($curl, CURLOPT_INFILE, $this->fp); 
if ($this->size > 0) 
curl_setopt($curl, CURLOPT_INFILESIZE, $this->size); 
} elseif ($this->data !== false) { 
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT'); 
curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data); 
if ($this->size > 0) 
curl_setopt($curl, CURLOPT_BUFFERSIZE, $this->size); 
} else 
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT'); 
break; 
case 'HEAD': 
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD'); 
curl_setopt($curl, CURLOPT_NOBODY, true); 
break; 
case 'DELETE': 
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE'); 
break; 
default: break; 
} 
// Execute, grab errors 
if (curl_exec($curl)) 
$this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE); 
else 
$this->response->error = array(
'code' => curl_errno($curl), 
'message' => curl_error($curl), 
'resource' => $this->resource 
); 
@curl_close($curl); 
// Parse body into XML 
if ($this->response->error === false && isset($this->response->headers['type']) && 
$this->response->headers['type'] == 'application/xml' && isset($this->response->body)) { 
$this->response->body = simplexml_load_string($this->response->body); 
// Grab S3 errors 
if (!in_array($this->response->code, array(200, 204)) && 
isset($this->response->body->Code, $this->response->body->Message)) { 
$this->response->error = array(
'code' => (string)$this->response->body->Code, 
'message' => (string)$this->response->body->Message 
); 
if (isset($this->response->body->Resource)) 
$this->response->error['resource'] = (string)$this->response->body->Resource; 
unset($this->response->body); 
} 
} 
// Clean up file resources 
if ($this->fp !== false && is_resource($this->fp)) fclose($this->fp); 
return $this->response; 
} 
private function __responseWriteCallback(&$curl, &$data) { 
if ($this->response->code == 200 && $this->fp !== false) 
return fwrite($this->fp, $data); 
else 
$this->response->body .= $data; 
return strlen($data); 
} 
private function __responseHeaderCallback(&$curl, &$data) { 
if (($strlen = strlen($data)) <= 2) return $strlen; 
if (substr($data, 0, 4) == 'HTTP') 
$this->response->code = (int)substr($data, 9, 3); 
else { 
list($header, $value) = explode(': ', trim($data)); 
if ($header == 'Last-Modified') 
$this->response->headers['time'] = strtotime($value); 
elseif ($header == 'Content-Length') 
$this->response->headers['size'] = (int)$value; 
elseif ($header == 'Content-Type') 
$this->response->headers['type'] = $value; 
elseif ($header == 'ETag') 
$this->response->headers['hash'] = substr($value, 1, -1); 
elseif (preg_match('/^x-amz-meta-.*$/', $header)) 
$this->response->headers[$header] = is_numeric($value) ? (int)$value : $value; 
} 
return $strlen; 
} 
} 
?>