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');
30 * This is a repository class used to browse Amazon S3 content.
33 * @package repository_s3
34 * @copyright 2009 Dongsheng Cai {@link http://dongsheng.org}
35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 class repository_s3
extends repository
{
41 * @param int $repositoryid
42 * @param object $context
43 * @param array $options
45 public function __construct($repositoryid, $context = SYSCONTEXTID
, $options = array()) {
46 parent
::__construct($repositoryid, $context, $options);
47 $this->access_key
= get_config('s3', 'access_key');
48 $this->secret_key
= get_config('s3', 'secret_key');
49 $this->endpoint
= get_config('s3', 'endpoint');
50 if ($this->endpoint
=== false) { // If no endpoint has been set, use the default.
51 $this->endpoint
= 's3.amazonaws.com';
53 $this->s
= new S3($this->access_key
, $this->secret_key
, false, $this->endpoint
);
54 $this->s
->setExceptions(true);
58 * Extracts the Bucket and URI from the path
60 * @param string $path path in this format 'bucket/path/to/folder/and/file'
61 * @return array including bucket and uri
63 protected function explode_path($path) {
64 $parts = explode('/', $path, 2);
65 if (isset($parts[1]) && $parts[1] !== '') {
66 list($bucket, $uri) = $parts;
71 return array($bucket, $uri);
78 * @return array The file list and options
80 public function get_listing($path = '', $page = '') {
82 if (empty($this->access_key
)) {
83 throw new moodle_exception('needaccesskey', 'repository_s3');
87 $list['list'] = array();
88 $list['path'] = array(
89 array('name' => get_string('pluginname', 'repository_s3'), 'path' => '')
92 // the management interface url
93 $list['manage'] = false;
94 // dynamically loading
95 $list['dynload'] = true;
96 // the current path of this list.
97 // set to true, the login link will be removed
98 $list['nologin'] = true;
99 // set to true, the search button will be removed
100 $list['nosearch'] = true;
106 $buckets = $this->s
->listBuckets();
107 } catch (S3Exception
$e) {
108 throw new moodle_exception('errorwhilecommunicatingwith', 'repository', '', $this->get_name());
110 foreach ($buckets as $bucket) {
113 'children' => array(),
114 'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
122 list($bucket, $uri) = $this->explode_path($path);
125 $contents = $this->s
->getBucket($bucket, $uri, null, null, '/', true);
126 } catch (S3Exception
$e) {
127 throw new moodle_exception('errorwhilecommunicatingwith', 'repository', '', $this->get_name());
129 foreach ($contents as $object) {
131 // If object has a prefix, it is a 'CommonPrefix', which we consider a folder
132 if (isset($object['prefix'])) {
133 $title = rtrim($object['prefix'], '/');
135 $title = $object['name'];
138 // Removes the prefix (folder path) from the title
139 if (strlen($uri) > 0) {
140 $title = substr($title, strlen($uri));
141 // Check if title is empty and not zero
142 if (empty($title) && !is_numeric($title)) {
143 // Amazon returns the prefix itself, we skip it
148 // This is a so-called CommonPrefix, we consider it as a folder
149 if (isset($object['prefix'])) {
152 'children' => array(),
153 'thumbnail'=> $OUTPUT->pix_url(file_folder_icon(90))->out(false),
154 'path' => $bucket . '/' . $object['prefix']
159 'size' => $object['size'],
160 'datemodified' => $object['time'],
161 'source' => $bucket . '/' . $object['name'],
162 'thumbnail' => $OUTPUT->pix_url(file_extension_icon($title, 90))->out(false)
166 $tree = array_merge($folders, $files);
171 $parts = explode('/', $path);
172 if (count($parts) > 1) {
173 foreach ($parts as $part) {
175 $trail .= $part . '/';
176 $list['path'][] = array('name' => $part, 'path' => $trail);
180 $list['path'][] = array('name' => $path, 'path' => $path);
184 $list['list'] = $tree;
190 * Download S3 files to moodle
192 * @param string $filepath
193 * @param string $file The file path in moodle
194 * @return array The local stored path
196 public function get_file($filepath, $file = '') {
197 list($bucket, $uri) = $this->explode_path($filepath);
198 $path = $this->prepare_file($file);
200 $this->s
->getObject($bucket, $uri, $path);
201 } catch (S3Exception
$e) {
202 throw new moodle_exception('errorwhilecommunicatingwith', 'repository', '', $this->get_name());
204 return array('path' => $path);
208 * Return the source information
210 * @param stdClass $filepath
213 public function get_file_source_info($filepath) {
214 return 'Amazon S3: ' . $filepath;
218 * S3 doesn't require login
222 public function check_login() {
227 * S3 doesn't provide search
231 public function global_search() {
235 public static function get_type_option_names() {
236 return array('access_key', 'secret_key', 'endpoint', 'pluginname');
239 public static function type_config_form($mform, $classname = 'repository') {
240 parent
::type_config_form($mform);
241 $strrequired = get_string('required');
242 $endpointselect = array( // List of possible Amazon S3 Endpoints.
243 "s3.amazonaws.com" => "s3.amazonaws.com",
244 "s3-external-1.amazonaws.com" => "s3-external-1.amazonaws.com",
245 "s3-us-west-2.amazonaws.com" => "s3-us-west-2.amazonaws.com",
246 "s3-us-west-1.amazonaws.com" => "s3-us-west-1.amazonaws.com",
247 "s3-eu-west-1.amazonaws.com" => "s3-eu-west-1.amazonaws.com",
248 "s3.eu-central-1.amazonaws.com" => "s3.eu-central-1.amazonaws.com",
249 "s3-eu-central-1.amazonaws.com" => "s3-eu-central-1.amazonaws.com",
250 "s3-ap-southeast-1.amazonaws.com" => "s3-ap-southeast-1.amazonaws.com",
251 "s3-ap-southeast-2.amazonaws.com" => "s3-ap-southeast-2.amazonaws.com",
252 "s3-ap-northeast-1.amazonaws.com" => "s3-ap-northeast-1.amazonaws.com",
253 "s3-sa-east-1.amazonaws.com" => "s3-sa-east-1.amazonaws.com"
255 $mform->addElement('text', 'access_key', get_string('access_key', 'repository_s3'));
256 $mform->setType('access_key', PARAM_RAW_TRIMMED
);
257 $mform->addElement('text', 'secret_key', get_string('secret_key', 'repository_s3'));
258 $mform->setType('secret_key', PARAM_RAW_TRIMMED
);
259 $mform->addElement('select', 'endpoint', get_string('endpoint', 'repository_s3'), $endpointselect);
260 $mform->setDefault('endpoint', 's3.amazonaws.com'); // Default to US Endpoint.
261 $mform->addRule('access_key', $strrequired, 'required', null, 'client');
262 $mform->addRule('secret_key', $strrequired, 'required', null, 'client');
266 * S3 plugins doesn't support return links of files
270 public function supported_returntypes() {
271 return FILE_INTERNAL
;
275 * Is this repository accessing private data?
279 public function contains_private_data() {