【问题标题】:PHP S3 upload progressPHP S3 上传进度
【发布时间】:2012-04-28 13:57:18
【问题描述】:

这已经发生了很多次,但我仍然有点困惑。很多答案只涉及上传进度条,而不是从 S3 上传中获得实际的上传进度。

我已经阅读了许多问题并找到了许多软件,但我仍然没有更深入地了解 S3 上传的基本问题。

有没有一种方法可以在了解上传进度的同时上传到 S3,而不必先使用我自己的应用服务器资源将文件存储在 temp 目录中?

我必须先将文件存储在自己的服务器上,然后再推送到 S3 吗?我听说有人谈论一次将流传输到 S3(一次一个块),但我不确定这涉及到什么。想象一下,我正在从 HTML 页面中的客户端上传文件,我将如何从多部分中逐块流式传输文件? (我没有看到任何例子,只有当文件已经在你的系统上并且你知道块有点没用的时候的例子)。

在 API 文档中当然有一个上传进度示例,但同样假设文件首先在您的服务器上,并且不是来自用户提供的另一台计算机。

编辑:我最初的想法是制作一个 PHP 脚本,它可以每隔一段时间 ping AWS 一次以获取上传进度。我正在查看 API,看看他们是否支持类似的东西,但 atm 没有运气。有什么事请告诉我...

进一步编辑:闪存是唯一的方法吗?

谢谢,

【问题讨论】:

    标签: php amazon-s3


    【解决方案1】:

    是的,在 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 property-callable 来工作,如 this SO answer 中所述。

    【讨论】:

      【解决方案2】:

      经过大量搜索,我发现这个问题的简单答案是否定的。

      基本上是最好的方法,正如我从亚马逊自己的编码(他们在 AWS S3 控制台上的小上传小部件)中发现的那样,只有通过首先发送到 PHP 可以读取的另一台服务器才能真正获得上传进度了解进度信息。

      这将使用您自己的应用服务器 /tmp 目录作为垫脚石创建“直通”策略。这似乎是首选方法。

      【讨论】:

      • 您是否还有可用的示例?我可能不得不做类似的事情..
      • 只有非常旧的代码,我认为他们的新 API 无效,基本上你照常上传到我们自己的服务器,然后以完整形式或每个块复制到 S3(使用多个部分表单,您可以在从流中完全上传到 PHP 之前获取块)
      • 我设法通过我的 PHP 代理从 JS 上传到 S3。但是我将如何在 JS 中保持进度条状态?任何地方都没有这方面的信息..
      • 你不能真正在 JS 中做一个进度条,你需要为服务器端创建一个 AJAX 轮询器来响应进度
      • 确实 - 但是我如何从 putObject PHP 调用中获得进展? (这样我就可以在..上传递数据了)
      【解决方案3】:

      AWS PHP SDK 有一个代码示例,它们在上传到 S3 时显示上传进度。我不确定它是否对小文件有效,但对于流式传输它确实有效。

      您可以查看更多信息 - http://aws.amazon.com/sdkforphp/

      在某种程度上,如果他们正在显示进度 - 我们当然可以在 jquery 等 Javascript 框架的帮助下以进度条的形式获得它。

      我很快就会着手处理它,并且一定会发布一个教程。干杯!

      【讨论】:

      • 我非常想要这个问题,这个问题是在 4 个版本的 sdk 之前写的,所以如果事情发生了变化并且 AWS 确实有一个很好的方法来解决这个问题,我会非常感兴趣
      • 如果您可以链接到带有代码示例的特定页面,而不仅仅是 sdk 主页,那将是最好的。
      • 你发过这方面的教程吗?
      【解决方案4】:

      是的,您可以通过分段上传:http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMPphpAPI.html

      分段上传是一个三步过程:启动上传,上传对象分段,上传完所有分段后,完成分段上传。收到完整的分段上传请求后,Amazon S3 会根据上传的部分构造对象,然后您可以像访问存储桶中的任何其他对象一样访问该对象。

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

      我将很快亲自执行此操作,但这是您需要开始的。

      【讨论】:

      • 您仍然需要将其上传到您自己的服务器以了解进度,因为您必须先拥有服务器上的总文件大小,然后才能对其进行任何操作。实际上,您将首先照常将其上传到您的服务器,然后将其分段上传到亚马逊以获得上传进度,这意味着您实际上将仅判断您的服务器上的上传进度。我想你可以重写核心 PHP 脚本来发布上传部分,然后你可以上传到亚马逊,但是 PHP 核心目前不这样做
      • @Sammaye 我实际上正在执行此操作,我必须先上传到服务器,然后再上传到 S3。在我想直接进入 S3 之前,我会写一些小技巧或临时写入文件以向我的用户发送反馈。只要您可以看到或使用这个多部分功能,您就应该能够以一种或另一种方式挂钩。
      • @MichaelCalkins 你有没有完成这个任务? 2014 年快结束了,我仍然看不到明确的答案吗?
      • 有什么例子吗?我正在使用 JS 发送到浏览器,但凭据是纯文本的,所以我必须使用 JS->proxy->S3,其中代理将是我的服务器脚本。任何帮助表示赞赏
      【解决方案5】:

      是的,你可以通过像这样修改 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;
      }
      }
      ?>
      

      【讨论】:

        猜你喜欢
        • 2011-07-24
        • 1970-01-01
        • 2012-03-08
        • 2012-04-10
        • 2014-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-26
        相关资源
        最近更新 更多