/[drupal]/contributions/modules/fileapi/drivers/s3.driver
ViewVC logotype

Diff of /contributions/modules/fileapi/drivers/s3.driver

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph | View Patch Patch

revision 1.3.4.3, Thu Jan 4 16:41:48 2007 UTC revision 1.4, Wed Jun 18 12:04:57 2008 UTC
# Line 2  Line 2 
2    
3  /**  /**
4   * @file   * @file
5   * Amazon S3 storage driver for fileapi.   * Amazon S3 storage driver for filesystem.
  *  
  * We are treating S3 like a normal hierarchal filesystem. The bucket  
  * is predetermined by the mountpoint settings. Except for list buckets  
  * and put bucket functions.  
  *  
  * We use the keys with a delimiter of '/' to create our heirarchy.  
  *  
  * @todo examine adding caching to save some requests to S3.  
  * @todo wrap amazon s3 functions into a single class with multiple instance and  
  *       caching support.  
  *  
6   */   */
7    
8    
9  /**  /**
10   * driver settings form. called by fileapi.module when creating a respository using this driver.   * driver settings form. called by filesystem.module when creating a respository using this driver.
11   * @param $settings   * @param $settings
12   *   settings array from database.   *  settings array from database.
  * @todo convert form to multistep to allow input of credentials, then bucket selection/creation.  
  * @todo add bucket access control policy settings  
13   */   */
14    
15  function fileapi_driver_s3_settings_form($settings = array()) {  function fileapi_driver_s3_settings_form($settings = array()) {
# Line 31  function fileapi_driver_s3_settings_form Line 18  function fileapi_driver_s3_settings_form
18      '#type' => 'fieldset',      '#type' => 'fieldset',
19      '#title' => t('Amazon S3 storage driver settings'),      '#title' => t('Amazon S3 storage driver settings'),
20      '#tree' => TRUE,      '#tree' => TRUE,
     '#validate' => array('fileapi_driver_s3_settings_form_validate' => array()),  
     '#submit' => array('fileapi_driver_s3_settings_form_submit' => array()),  
21    );    );
22    
23    $form['driver'] = array(    $form['driver'] = array(
# Line 43  function fileapi_driver_s3_settings_form Line 28  function fileapi_driver_s3_settings_form
28    $form['s3 url'] = array(    $form['s3 url'] = array(
29      '#type' => 'textfield',      '#type' => 'textfield',
30      '#title' => t('Amazon S3 url'),      '#title' => t('Amazon S3 url'),
     '#description' => t('The URL must not contain a trailing slash.'),  
31      '#default_value' => strlen($settings['s3 url']) ? $settings['s3 url'] : 'http://s3.amazonaws.com',      '#default_value' => strlen($settings['s3 url']) ? $settings['s3 url'] : 'http://s3.amazonaws.com',
32    );    );
33    
# Line 59  function fileapi_driver_s3_settings_form Line 43  function fileapi_driver_s3_settings_form
43      '#default_value' => $settings['awsSecret'],      '#default_value' => $settings['awsSecret'],
44    );    );
45    
   
   if (isset($settings['awsID']) && isset($settings['awsSecret'])) {  
   
     $buckets = s3_buckets($settings);  
     debug_msg($buckets, 'buckets');  
     // use !== FALSE to pass on empty array checks.  
     if ($buckets !== FALSE) {  
       $buckets['Create a New Bucket'] = t('Create a New Bucket');  
       $form['bucket'] = array(  
         '#type' => 'select',  
         '#title' => 'Use Existing S3 Bucket',  
         '#options' => $buckets,  
         '#default_value' => (isset($settings['bucket'])) ? $settings['bucket'] : 'Create a New Bucket',  
       );  
   
       $form['new_bucket'] = array(  
         '#type' => 'textfield',  
         '#title' => t('New S3 Bucket'),  
         '#default_value' => '',  
       );  
     }  
   }  
   
   
46    return $form;    return $form;
47  }  }
48    
49  function fileapi_driver_s3_settings_form_validate($element) {  function fileapi_driver_s3_settings_form_validate() {
   //@todo test for trailing slash in 's3 url';  
   if (preg_match('/\/$/', $element['s3 url']['#value'])) {  
     form_set_error('s3 url', t('The URL must not include a trailing slash.'));  
   }  
   
   
   
   //@todo validate AWS credentials.  
   $settings = array(  
       's3 url' => $element['s3 url']['#value'],  
       'awsID' => $element['awsID']['#value'],  
       'awsSecret' => $element['awsSecret']['#value'],  
   );  
   
   debug_msg($settings);  
   $result = s3_buckets($settings);  
   debug_msg(htmlspecialchars($result));  
   if ($result === FALSE)  {  
     form_set_error('awsID', t('Your AWS credentials seem to be invalid.'));  
     form_set_error('awsSecret','');  
   }  
   
 }  
   
 //function fileapi_driver_s3_settings_form_submit($form_id, &$form_values) {  
 function fileapi_driver_s3_settings_form_submit($element) {  
   $settings = array(  
       's3 url' => $element['s3 url']['#value'],  
       'awsID' => $element['awsID']['#value'],  
       'awsSecret' => $element['awsSecret']['#value'],  
   );  
   // @todo create a new bucket if one doesn't exist...  
   if (isset($element['awsID']['#value']) && isset($element['aws_Secret']['#value'])) {  
     if ($element['bucket']['#value'] == 'Create A New Bucket') {  
       s3_bucket_put($settings, $element['new_bucket']['#value']);  
       $element['bucket']['#value'] = $element['new_bucket']['#value'];  
       unset($element['new_bucket']['#value']);  
     }  
   }  
   else {  
     return FALSE;  
   }  
50  }  }
51    
52    
53  /**  /**
54   * test if a path is a file.   * test if a path is a file.
  *  
  * for S3 we are going to operate on an object if an object  
  * has the key we're requesting.  
  * see: S3 Developers Guide pg 67.  
  *  
55   * @param $path   * @param $path
56   *   path to be tested   *   path to be tested
  *  
57   */   */
58  function fileapi_driver_s3_is_file($settings, $path) {  function fileapi_driver_s3_is_file($settings, $path) {
59    // request meta data for an object with the key $path.  
   $result = s3_request('HEAD', $settings['bucket'] .'/'. $path, $settings);  
   
   //parse results for request...  
60  }  }
61    
62  /**  /**
# Line 186  function fileapi_driver_s3_rmdir($settin Line 95  function fileapi_driver_s3_rmdir($settin
95   * @param $path   * @param $path
96   */   */
97  function fileapi_driver_s3_remove($settings, $path) {  function fileapi_driver_s3_remove($settings, $path) {
98      clearstatcache();
99    
100  }  }
101    
# Line 225  function fileapi_driver_s3_touch($settin Line 135  function fileapi_driver_s3_touch($settin
135    $headers = array();    $headers = array();
136    $headers['Content-Type'] = 'text/plain';    $headers['Content-Type'] = 'text/plain';
137    $body = file_get_contents($tmp);    $body = file_get_contents($tmp);
138    $result = s3_request('PUT', $path, $settings, array(), $body);    s3_request('PUT', $path, $settings, array(), $body);
139    unlink($tmp);    unlink($tmp);
   if ($result) {  
     return $TRUE;  
   }  
   else {  
     return FALSE;  
   }  
140  }  }
141    
142    
# Line 244  function fileapi_driver_s3_touch($settin Line 148  function fileapi_driver_s3_touch($settin
148   *   action results and array of directory contents.   *   action results and array of directory contents.
149   */   */
150  function fileapi_driver_s3_readdir($settings, $path) {  function fileapi_driver_s3_readdir($settings, $path) {
   // $result = s3_request('GET', $settings['bucket'], $settings, array(), array(), NULL, array('prefix='. $path, 'delimiter=/');  
151  }  }
152    
153  /**  /**
# Line 256  function fileapi_driver_s3_readdir($sett Line 159  function fileapi_driver_s3_readdir($sett
159   *       and our support target is 4.3.0.   *       and our support target is 4.3.0.
160   */   */
161  function fileapi_driver_s3_fileread($settings, $path) {  function fileapi_driver_s3_fileread($settings, $path) {
162    // $result = s3_request('GET', $path, $settings);    return s3_request('GET', $path, $settings);
   return $result;  
163  }  }
164    
165  function fileapi_driver_s3_filewrite($settings, $path, $data) {  function fileapi_driver_s3_filewrite($settings, $path, $data) {
166    $headers = array('Content-Type' => 'text/plain');    $headers = array('Content-Type' => 'text/plain');
167    // $result = s3_request('PUT', $settings['bucket'] .'/'. $path, $settings, array(), $data);    s3_request('PUT', $path, $settings, array(), $data);
   return $result;  
 }  
   
   
   
 function s3_buckets($settings) {  
   $result = s3_request('GET','', $settings);  
   if ($result) {  
     $buckets = array();  
     $xml = simplexml_load_string($result);  
     foreach($xml->Buckets->Bucket->Name as $Name) {  
       $name = (string)$Name;  
       $buckets[$name] = $name;  
     }  
     return $buckets;  
   }  
   return FALSE;  
 }  
   
 /** Operations on Buckets **/  
 function s3_bucket_put($settings, $bucket = '') {  
   $result = s3_request('PUT', $bucket, $settings);  
   return $result;  
168  }  }
169    
170    
171    function s3_request($method, $resource, $settings, $headers=array(), $amzheaders=array(),  $body= '') {
172      $url = $settings['s3 url'] . $settings['bucket'];
 function s3_request($method, $resource, $settings, $headers=array(), $amzheaders=array(),  $body=NULL, $query = array()) {  
   $url = $settings['s3 url'];  
173    
174    // Set date to proper format for S3.    // Set date to proper format for S3.
175    $headers['Date'] = gmdate(DATE_RFC822);    $headers['Date'] = gmdate(DATE_RFC822);
176    if (!is_null($body)) {    $headers['Authorization'] = 'AWS '. $settings['awsID'] .':'. $signature;
     $headers['Content-MD5'] = hex2b64(md5($body));  
   }  
177    
178    // Build S3 authorization hash.    // Build S3 authorization hash.
179    $auth_string = $method ."\n";    $auth_string = $method ."\n\n". $headers['Content-type'] ."\n";
180    // Apparently we need a trailing \n whether we have a body or not...    $auth_string .= $headers['Date'] ."\n". implode("\n",$amzheaders) ."\n". $resource;
   if (isset($headers['Content-MD5'])) {  
     $auth_string .= $headers['Content-MD5'];  
   }  
   $auth_string .= "\n" . $headers['Content-Type'] ."\n" . $headers['Date'] ."\n";  
   // Apparently we DONT need a trailing \n here if its not present.  
   if (count($amzheaders)) {  
     $auth_string .= implode("\n",$amzheaders) ."\n";  
   }  
   
   $auth_string .= '/'. $resource;  
181    $signature = hex2b64(s3_hmac_sha1($settings['awsSecret'], $auth_string));    $signature = hex2b64(s3_hmac_sha1($settings['awsSecret'], $auth_string));
   //print "auth_string:\n$auth_string\n";  
   //print "signature: $signature\n";  
182    
183    // Set date to proper format for S3.    // Set date to proper format for S3.
184    $headers['Date'] = gmdate(DATE_RFC822);    $headers['Date'] = gmdate(DATE_RFC822);
185    $headers['Authorization'] = 'AWS '. $settings['awsID'] .':'. $signature;    $headers['Authorization'] = 'AWS '. $settings['awsID'] .':'. $signature;
   
   if (count($query)) {  
     $qs = '?'. implode('&', $query);  
   }  
186    
187    $result = drupal_http_request($url .'/'. $resource . $qs, array_merge($headers, $amzheaders), $method, $body);    $result = drupal_http_request($url .'/'. $resource, array_merge($headers, $amzheaders), $method, $body);
188    if ($result->code == '403') {    drupal_set_message('<pre>'. print_r($result, TRUE) .'</pre>');
     //watchdog('fileapi', t('Amazon S3 Authentication Failed'));  
     // should we log our string to sign, amazon's string to sign, and our signature here?  
     return FALSE;  
   }  
   // clean up the start and finish lines from the XML data that S3 adds for some reason.  
   $result  = split("\n", trim($result->data));  
   unset($result[0]);  
   unset($result[count($result)]);  
   $result = implode("\n", $result);  
   return $result;  
189  }  }
190    
   
191  /**  /**
192   * Generate an sha1 signed hash of a string.   * Generate an sha1 signed hash of a string.
193   * @param K   * @param K
# Line 391  function s3_hmac($h, $B, $K, $string) { Line 239  function s3_hmac($h, $B, $K, $string) {
239    return $h($opad.$string);    return $h($opad.$string);
240  }  }
241    
242  // conversion.  
 function hex2b64($str)  
 {  
     $raw = '';  
     for ($i=0; $i < strlen($str); $i+=2)  
     {  
         $raw .= chr(hexdec(substr($str, $i, 2)));  
     }  
     return base64_encode($raw);  
 }  
243    

Legend:
Removed from v.1.3.4.3  
changed lines
  Added in v.1.4

  ViewVC Help
Powered by ViewVC 1.1.2