From bf5ee605a8a6179334240d85345c9d43044d7123 Mon Sep 17 00:00:00 2001
From: boombatower <jimmy@boombatower.com>
Date: Mon, 6 Aug 2012 00:48:09 -0700
Subject: Issue #1714696: Make use of amazons3 file stream wrapper and
 official php sdk.

---
 includes/destinations.s3.inc |  104 +++++++++++++++++-------------------------
 1 file changed, 42 insertions(+), 62 deletions(-)

diff --git a/includes/destinations.s3.inc b/includes/destinations.s3.inc
index 8937162..8e942b1 100644
--- a/includes/destinations.s3.inc
+++ b/includes/destinations.s3.inc
@@ -13,17 +13,14 @@
  */
 class backup_migrate_destination_s3 extends backup_migrate_destination_remote {
   var $supported_ops = array('scheduled backup', 'manual backup', 'restore', 'list files', 'configure', 'delete');
-  var $s3 = NULL;
   var $cache_files = TRUE;
 
-
   /**
    * Save to to the s3 destination.
    */
   function _save_file($file, $settings) {
-    if ($s3 = $this->s3_object()) {
-      $path = $file->filename();
-      if ($s3->putObject($s3->inputFile($file->filepath(), FALSE), $this->get_bucket(), $this->remote_path($file->filename()), S3::ACL_PRIVATE)) {
+    if ($url = $this->s3_url()) {
+      if (copy($file->filepath(), $url . '/' . $file->filename())) {
         return $file;
       }
     }
@@ -36,9 +33,8 @@ class backup_migrate_destination_s3 extends backup_migrate_destination_remote {
   function load_file($file_id) {
     backup_migrate_include('files');
     $file = new backup_file(array('filename' => $file_id));
-    if ($s3 = $this->s3_object()) {
-      $data = $s3->getObject($this->get_bucket(), $this->remote_path($file_id), $file->filepath());
-      if (!$data->error) {
+    if ($url = $this->s3_url()) {
+      if (file_put_contents($file->filepath(), file_get_contents($url . '/' . $file_id))) {
         return $file;
       }
     }
@@ -49,8 +45,8 @@ class backup_migrate_destination_s3 extends backup_migrate_destination_remote {
    * Delete from the s3 destination.
    */
   function _delete_file($file_id) {
-    if ($s3 = $this->s3_object()) {
-      $s3->deleteObject($this->get_bucket(), $this->remote_path($file_id));
+    if ($url = $this->s3_url()) {
+      unlink($url . '/' . $file_id);
     }
   }
 
@@ -60,15 +56,21 @@ class backup_migrate_destination_s3 extends backup_migrate_destination_remote {
   function _list_files() {
     backup_migrate_include('files');
     $files = array();
-    if ($s3 = $this->s3_object()) {
-      $s3_files = $s3->getBucket($this->get_bucket(), $this->get_subdir());
-      foreach ((array)$s3_files as $id => $file) {
-        $info = array(
-          'filename' => $this->local_path($file['name']),
-          'filesize' => $file['size'],
-          'filetime' => $file['time'],
-        );
-        $files[$info['filename']] = new backup_file($info);
+    if ($url = $this->s3_url()) {
+      // file_scan_directory() will not work due to http://drupal.org/node/1714654
+      $s3_files = scandir($url);
+      foreach ($s3_files as $file) {
+        if ($file != '.' && $file != '..') {
+          $info = array(
+            'filename' => $file,
+            // TODO Decide if the amazon sdk should be called directly to provide size and time
+            // otherwise could stat each file, but that is probably a bad idea. Is there a stream
+            // wrapper function that allows for scandir() with stat() results?
+            'filesize' => 0,
+            'filetime' => 0,
+          );
+          $files[$info['filename']] = new backup_file($info);
+        }
       }
     }
     return $files;
@@ -79,7 +81,7 @@ class backup_migrate_destination_s3 extends backup_migrate_destination_remote {
    */
   function edit_form() {
     // Check for the library.
-    $this->s3_object();
+    $this->s3_url();
 
     $form = parent::edit_form();
     $form['scheme']['#type'] = 'value';
@@ -91,8 +93,8 @@ class backup_migrate_destination_s3 extends backup_migrate_destination_remote {
     $form['path']['#default_value'] = $this->get_bucket();
     $form['path']['#description'] = 'This bucket must already exist. It will not be created for you.';
 
-    $form['user']['#title'] = 'Access Key ID';
-    $form['pass']['#title'] = 'Secret Access Key';
+    $form['user']['#access'] = FALSE;
+    $form['pass']['#access'] = FALSE;
 
     $form['subdir'] = array(
       '#type' => 'textfield',
@@ -118,26 +120,6 @@ class backup_migrate_destination_s3 extends backup_migrate_destination_remote {
   }
 
   /**
-   * Generate a filepath with the correct prefix.
-   */
-  function remote_path($path) {
-    if ($subdir = $this->get_subdir()) {
-      $path = $subdir .'/'. $path;
-    }
-    return $path;
-  }
-
-  /**
-   * Generate a filepath with the correct prefix.
-   */
-  function local_path($path) {
-    if ($subdir = $this->get_subdir()) {
-      $path = str_replace($subdir .'/', '', $path);
-    }
-    return $path;
-  }
-
-  /**
    * Get the bucket which is the first part of the path.
    */
   function get_bucket() {
@@ -158,27 +140,25 @@ class backup_migrate_destination_s3 extends backup_migrate_destination_remote {
     return implode('/', array_filter($parts));
   }
 
-  function s3_object() {
-    // Try to use libraries module if available to find the path.
-    if (function_exists('libraries_get_path')) {
-      $library_paths[] = libraries_get_path('s3-php5-curl');
-    }
-    else {
-      $library_paths[] = 'sites/all/libraries/s3-php5-curl';
-    }
-    $library_paths[] = drupal_get_path('module', 'backup_migrate') . '/includes/s3-php5-curl';
-    $library_paths[] = drupal_get_path('module', 'backup_migrate') . '/includes';
-
-    foreach($library_paths as $path) {
-      if (file_exists($path . '/S3.php')) {
-        require_once $path . '/S3.php';
-        if (!$this->s3 && !empty($this->dest_url['user'])) {
-          $this->s3 = new S3($this->dest_url['user'], $this->dest_url['pass']);
-        }
-        return $this->s3;
+  /**
+   * Ensure the amazons3 file wrapper is available and awssdk is configured.
+   *
+   * @return
+   *   The s3 url with the subdirectory.
+   */
+  function s3_url() {
+    $url = &drupal_static(__METHOD__, FALSE);
+    if (!$url) {
+      include_once DRUPAL_ROOT . '/includes/install.inc';
+      if (array_key_exists('s3', file_get_stream_wrappers()) && module_exists('awssdk')
+        && (($requirements = awssdk_requirements('runtime')) && $requirements['awssdk']['severity'] == REQUIREMENT_OK)) {
+        $GLOBALS['conf']['amazons3_bucket'] = $this->get_bucket();
+        $url = 's3://' . $this->get_subdir();
+      }
+      else {
+        drupal_set_message(t('Be sure the amazons3 and awssdk modules installed and configured correctly.'), 'error');
       }
     }
-    drupal_set_message(t('Due to drupal.org code hosting policies, the S3 library needed to use an S3 destination is no longer distributed with this module. You must download the library from !link and place it in one of these locations: %locations.', array('%locations' => implode(', ', $library_paths), '!link' => l('http://undesigned.org.za/2007/10/22/amazon-s3-php-class', 'http://undesigned.org.za/2007/10/22/amazon-s3-php-class'))), 'error', FALSE);
-    return NULL;
+    return $url;
   }
 }
-- 
1.7.10.4

