3 // This file is part of Moodle - http://moodle.org/
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
19 * This plugin is used to access s3 files
22 * @package repository_s3
23 * @copyright 2010 Dongsheng Cai {@link http://dongsheng.org}
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 require_once($CFG->dirroot
. '/repository/lib.php');
27 require_once($CFG->dirroot
. '/repository/s3/S3.php');
29 // This constant is not defined in php 5.4. Set it to avoid errors.
30 if (!defined('CURL_SSLVERSION_TLSv1')) {
31 define('CURL_SSLVERSION_TLSv1', 1);
35 * This is a repository class used to browse Amazon S3 content.
38 * @package repository_s3
39 * @copyright 2009 Dongsheng Cai {@link http://dongsheng.org}
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42 class repository_s3
extends repository
{
44 /** @var string access key. */
45 protected $access_key;
46 /** @var string secret key. */
47 protected $secret_key;
48 /** @var string endpoint URL. */
50 /** @var S3 S3 class. */
55 * @param int $repositoryid
56 * @param object $context
57 * @param array $options
59 public function __construct($repositoryid, $context = SYSCONTEXTID
, $options = array()) {
61 parent
::__construct($repositoryid, $context, $options);
62 $this->access_key
= get_config('s3', 'access_key');
63 $this->secret_key
= get_config('s3', 'secret_key');
64 $this->endpoint
= get_config('s3', 'endpoint');
65 if ($this->endpoint
=== false) { // If no endpoint has been set, use the default.
66 $this->endpoint
= 's3.amazonaws.com';
68 $this->s
= new S3($this->access_key
, $this->secret_key
, false, $this->endpoint
);
69 $this->s
->setExceptions(true);
71 // Port of curl::__construct().
72 if (!empty($CFG->proxyhost
)) {
73 if (empty($CFG->proxyport
)) {
74 $proxyhost = $CFG->proxyhost
;
76 $proxyhost = $CFG->proxyhost
. ':' . $CFG->proxyport
;
78 $proxytype = CURLPROXY_HTTP
;
81 if (!empty($CFG->proxyuser
) and !empty($CFG->proxypassword
)) {
82 $proxyuser = $CFG->proxyuser
;
83 $proxypass = $CFG->proxypassword
;
85 if (!empty($CFG->proxytype
) && $CFG->proxytype
== 'SOCKS5') {
86 $proxytype = CURLPROXY_SOCKS5
;
88 $this->s
->setProxy($proxyhost, $proxyuser, $proxypass, $proxytype);
93 * Extracts the Bucket and URI from the path
95 * @param string $path path in this format 'bucket/path/to/folder/and/file'
96 * @return array including bucket and uri
98 protected function explode_path($path) {
99 $parts = explode('/', $path, 2);
100 if (isset($parts[1]) && $parts[1] !== '') {
101 list($bucket, $uri) = $parts;
106 return array($bucket, $uri);
112 * @param string $path
113 * @return array The file list and options
115 public function get_listing($path = '', $page = '') {
116 global $CFG, $OUTPUT;
117 if (empty($this->access_key
)) {
118 throw new moodle_exception('needaccesskey', 'repository_s3');
122 $list['list'] = array();
123 $list['path'] = array(
124 array('name' => get_string('pluginname', 'repository_s3'), 'path' => '')
127 // the management interface url
128 $list['manage'] = false;
129 // dynamically loading
130 $list['dynload'] = true;
131 // the current path of this list.
132 // set to true, the login link will be removed
133 $list['nologin'] = true;
134 // set to true, the search button will be removed
135 $list['nosearch'] = true;
141 $buckets = $this->s
->listBuckets();
142 } catch (S3Exception
$e) {
143 throw new moodle_exception(
144 'errorwhilecommunicatingwith',
151 foreach ($buckets as $bucket) {
154 'children' => array(),
155 'thumbnail' => $OUTPUT->image_url(file_folder_icon())->out(false),
163 list($bucket, $uri) = $this->explode_path($path);
166 $contents = $this->s
->getBucket($bucket, $uri, null, null, '/', true);
167 } catch (S3Exception
$e) {
168 throw new moodle_exception(
169 'errorwhilecommunicatingwith',
176 foreach ($contents as $object) {
178 // If object has a prefix, it is a 'CommonPrefix', which we consider a folder
179 if (isset($object['prefix'])) {
180 $title = rtrim($object['prefix'], '/');
182 $title = $object['name'];
185 // Removes the prefix (folder path) from the title
186 if (strlen($uri) > 0) {
187 $title = substr($title, strlen($uri));
188 // Check if title is empty and not zero
189 if (empty($title) && !is_numeric($title)) {
190 // Amazon returns the prefix itself, we skip it
195 // This is a so-called CommonPrefix, we consider it as a folder
196 if (isset($object['prefix'])) {
199 'children' => array(),
200 'thumbnail' => $OUTPUT->image_url(file_folder_icon())->out(false),
201 'path' => $bucket . '/' . $object['prefix'],
206 'size' => $object['size'],
207 'datemodified' => $object['time'],
208 'source' => $bucket . '/' . $object['name'],
209 'thumbnail' => $OUTPUT->image_url(file_extension_icon($title))->out(false)
213 $tree = array_merge($folders, $files);
218 $parts = explode('/', $path);
219 if (count($parts) > 1) {
220 foreach ($parts as $part) {
222 $trail .= $part . '/';
223 $list['path'][] = array('name' => $part, 'path' => $trail);
227 $list['path'][] = array('name' => $path, 'path' => $path);
231 $list['list'] = $tree;
237 * Download S3 files to moodle
239 * @param string $filepath
240 * @param string $file The file path in moodle
241 * @return array The local stored path
243 public function get_file($filepath, $file = '') {
244 list($bucket, $uri) = $this->explode_path($filepath);
245 $path = $this->prepare_file($file);
247 $this->s
->getObject($bucket, $uri, $path);
248 } catch (S3Exception
$e) {
249 throw new moodle_exception(
250 'errorwhilecommunicatingwith',
257 return array('path' => $path);
261 * Return the source information
263 * @param stdClass $filepath
266 public function get_file_source_info($filepath) {
267 return 'Amazon S3: ' . $filepath;
271 * S3 doesn't require login
275 public function check_login() {
280 * S3 doesn't provide search
284 public function global_search() {
288 public static function get_type_option_names() {
289 return array('access_key', 'secret_key', 'endpoint', 'pluginname');
292 public static function type_config_form($mform, $classname = 'repository') {
293 parent
::type_config_form($mform);
294 $strrequired = get_string('required');
295 $endpointselect = array( // List of possible Amazon S3 Endpoints.
296 "s3.amazonaws.com" => "s3.amazonaws.com",
297 "s3-external-1.amazonaws.com" => "s3-external-1.amazonaws.com",
298 "s3-us-west-2.amazonaws.com" => "s3-us-west-2.amazonaws.com",
299 "s3-us-west-1.amazonaws.com" => "s3-us-west-1.amazonaws.com",
300 "s3-eu-west-1.amazonaws.com" => "s3-eu-west-1.amazonaws.com",
301 "s3.eu-central-1.amazonaws.com" => "s3.eu-central-1.amazonaws.com",
302 "s3-eu-central-1.amazonaws.com" => "s3-eu-central-1.amazonaws.com",
303 "s3-ap-southeast-1.amazonaws.com" => "s3-ap-southeast-1.amazonaws.com",
304 "s3-ap-southeast-2.amazonaws.com" => "s3-ap-southeast-2.amazonaws.com",
305 "s3-ap-northeast-1.amazonaws.com" => "s3-ap-northeast-1.amazonaws.com",
306 "s3-sa-east-1.amazonaws.com" => "s3-sa-east-1.amazonaws.com"
308 $mform->addElement('text', 'access_key', get_string('access_key', 'repository_s3'));
309 $mform->setType('access_key', PARAM_RAW_TRIMMED
);
310 $mform->addElement('text', 'secret_key', get_string('secret_key', 'repository_s3'));
311 $mform->setType('secret_key', PARAM_RAW_TRIMMED
);
312 $mform->addElement('select', 'endpoint', get_string('endpoint', 'repository_s3'), $endpointselect);
313 $mform->setDefault('endpoint', 's3.amazonaws.com'); // Default to US Endpoint.
314 $mform->addRule('access_key', $strrequired, 'required', null, 'client');
315 $mform->addRule('secret_key', $strrequired, 'required', null, 'client');
319 * S3 plugins doesn't support return links of files
323 public function supported_returntypes() {
324 return FILE_INTERNAL
;
328 * Is this repository accessing private data?
332 public function contains_private_data() {