Merge branch 'MDL-54892-MOODLE_30_STABLE' of https://github.com/tobiasreischmann...
[moodle.git] / repository / s3 / lib.php
blobefb99094f96bac540f7a986c7682ad1d594d79e9
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
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.
9 //
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/>.
18 /**
19 * This plugin is used to access s3 files
21 * @since Moodle 2.0
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 /**
30 * This is a repository class used to browse Amazon S3 content.
32 * @since Moodle 2.0
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 {
39 /**
40 * Constructor
41 * @param int $repositoryid
42 * @param object $context
43 * @param array $options
45 public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
46 global $CFG;
47 parent::__construct($repositoryid, $context, $options);
48 $this->access_key = get_config('s3', 'access_key');
49 $this->secret_key = get_config('s3', 'secret_key');
50 $this->endpoint = get_config('s3', 'endpoint');
51 if ($this->endpoint === false) { // If no endpoint has been set, use the default.
52 $this->endpoint = 's3.amazonaws.com';
54 $this->s = new S3($this->access_key, $this->secret_key, false, $this->endpoint);
55 $this->s->setExceptions(true);
57 // Port of curl::__construct().
58 if (!empty($CFG->proxyhost)) {
59 if (empty($CFG->proxyport)) {
60 $proxyhost = $CFG->proxyhost;
61 } else {
62 $proxyhost = $CFG->proxyhost . ':' . $CFG->proxyport;
64 $proxytype = CURLPROXY_HTTP;
65 $proxyuser = null;
66 $proxypass = null;
67 if (!empty($CFG->proxyuser) and !empty($CFG->proxypassword)) {
68 $proxyuser = $CFG->proxyuser;
69 $proxypass = $CFG->proxypassword;
71 if (!empty($CFG->proxytype) && $CFG->proxytype == 'SOCKS5') {
72 $proxytype = CURLPROXY_SOCKS5;
74 $this->s->setProxy($proxyhost, $proxyuser, $proxypass, $proxytype);
78 /**
79 * Extracts the Bucket and URI from the path
81 * @param string $path path in this format 'bucket/path/to/folder/and/file'
82 * @return array including bucket and uri
84 protected function explode_path($path) {
85 $parts = explode('/', $path, 2);
86 if (isset($parts[1]) && $parts[1] !== '') {
87 list($bucket, $uri) = $parts;
88 } else {
89 $bucket = $parts[0];
90 $uri = '';
92 return array($bucket, $uri);
95 /**
96 * Get S3 file list
98 * @param string $path
99 * @return array The file list and options
101 public function get_listing($path = '', $page = '') {
102 global $CFG, $OUTPUT;
103 if (empty($this->access_key)) {
104 throw new moodle_exception('needaccesskey', 'repository_s3');
107 $list = array();
108 $list['list'] = array();
109 $list['path'] = array(
110 array('name' => get_string('pluginname', 'repository_s3'), 'path' => '')
113 // the management interface url
114 $list['manage'] = false;
115 // dynamically loading
116 $list['dynload'] = true;
117 // the current path of this list.
118 // set to true, the login link will be removed
119 $list['nologin'] = true;
120 // set to true, the search button will be removed
121 $list['nosearch'] = true;
123 $tree = array();
125 if (empty($path)) {
126 try {
127 $buckets = $this->s->listBuckets();
128 } catch (S3Exception $e) {
129 throw new moodle_exception(
130 'errorwhilecommunicatingwith',
131 'repository',
133 $this->get_name(),
134 $e->getMessage()
137 foreach ($buckets as $bucket) {
138 $folder = array(
139 'title' => $bucket,
140 'children' => array(),
141 'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
142 'path' => $bucket
144 $tree[] = $folder;
146 } else {
147 $files = array();
148 $folders = array();
149 list($bucket, $uri) = $this->explode_path($path);
151 try {
152 $contents = $this->s->getBucket($bucket, $uri, null, null, '/', true);
153 } catch (S3Exception $e) {
154 throw new moodle_exception(
155 'errorwhilecommunicatingwith',
156 'repository',
158 $this->get_name(),
159 $e->getMessage()
162 foreach ($contents as $object) {
164 // If object has a prefix, it is a 'CommonPrefix', which we consider a folder
165 if (isset($object['prefix'])) {
166 $title = rtrim($object['prefix'], '/');
167 } else {
168 $title = $object['name'];
171 // Removes the prefix (folder path) from the title
172 if (strlen($uri) > 0) {
173 $title = substr($title, strlen($uri));
174 // Check if title is empty and not zero
175 if (empty($title) && !is_numeric($title)) {
176 // Amazon returns the prefix itself, we skip it
177 continue;
181 // This is a so-called CommonPrefix, we consider it as a folder
182 if (isset($object['prefix'])) {
183 $folders[] = array(
184 'title' => $title,
185 'children' => array(),
186 'thumbnail'=> $OUTPUT->pix_url(file_folder_icon(90))->out(false),
187 'path' => $bucket . '/' . $object['prefix']
189 } else {
190 $files[] = array(
191 'title' => $title,
192 'size' => $object['size'],
193 'datemodified' => $object['time'],
194 'source' => $bucket . '/' . $object['name'],
195 'thumbnail' => $OUTPUT->pix_url(file_extension_icon($title, 90))->out(false)
199 $tree = array_merge($folders, $files);
202 $trail = '';
203 if (!empty($path)) {
204 $parts = explode('/', $path);
205 if (count($parts) > 1) {
206 foreach ($parts as $part) {
207 if (!empty($part)) {
208 $trail .= $part . '/';
209 $list['path'][] = array('name' => $part, 'path' => $trail);
212 } else {
213 $list['path'][] = array('name' => $path, 'path' => $path);
217 $list['list'] = $tree;
219 return $list;
223 * Download S3 files to moodle
225 * @param string $filepath
226 * @param string $file The file path in moodle
227 * @return array The local stored path
229 public function get_file($filepath, $file = '') {
230 list($bucket, $uri) = $this->explode_path($filepath);
231 $path = $this->prepare_file($file);
232 try {
233 $this->s->getObject($bucket, $uri, $path);
234 } catch (S3Exception $e) {
235 throw new moodle_exception(
236 'errorwhilecommunicatingwith',
237 'repository',
239 $this->get_name(),
240 $e->getMessage()
243 return array('path' => $path);
247 * Return the source information
249 * @param stdClass $filepath
250 * @return string
252 public function get_file_source_info($filepath) {
253 return 'Amazon S3: ' . $filepath;
257 * S3 doesn't require login
259 * @return bool
261 public function check_login() {
262 return true;
266 * S3 doesn't provide search
268 * @return bool
270 public function global_search() {
271 return false;
274 public static function get_type_option_names() {
275 return array('access_key', 'secret_key', 'endpoint', 'pluginname');
278 public static function type_config_form($mform, $classname = 'repository') {
279 parent::type_config_form($mform);
280 $strrequired = get_string('required');
281 $endpointselect = array( // List of possible Amazon S3 Endpoints.
282 "s3.amazonaws.com" => "s3.amazonaws.com",
283 "s3-external-1.amazonaws.com" => "s3-external-1.amazonaws.com",
284 "s3-us-west-2.amazonaws.com" => "s3-us-west-2.amazonaws.com",
285 "s3-us-west-1.amazonaws.com" => "s3-us-west-1.amazonaws.com",
286 "s3-eu-west-1.amazonaws.com" => "s3-eu-west-1.amazonaws.com",
287 "s3.eu-central-1.amazonaws.com" => "s3.eu-central-1.amazonaws.com",
288 "s3-eu-central-1.amazonaws.com" => "s3-eu-central-1.amazonaws.com",
289 "s3-ap-southeast-1.amazonaws.com" => "s3-ap-southeast-1.amazonaws.com",
290 "s3-ap-southeast-2.amazonaws.com" => "s3-ap-southeast-2.amazonaws.com",
291 "s3-ap-northeast-1.amazonaws.com" => "s3-ap-northeast-1.amazonaws.com",
292 "s3-sa-east-1.amazonaws.com" => "s3-sa-east-1.amazonaws.com"
294 $mform->addElement('text', 'access_key', get_string('access_key', 'repository_s3'));
295 $mform->setType('access_key', PARAM_RAW_TRIMMED);
296 $mform->addElement('text', 'secret_key', get_string('secret_key', 'repository_s3'));
297 $mform->setType('secret_key', PARAM_RAW_TRIMMED);
298 $mform->addElement('select', 'endpoint', get_string('endpoint', 'repository_s3'), $endpointselect);
299 $mform->setDefault('endpoint', 's3.amazonaws.com'); // Default to US Endpoint.
300 $mform->addRule('access_key', $strrequired, 'required', null, 'client');
301 $mform->addRule('secret_key', $strrequired, 'required', null, 'client');
305 * S3 plugins doesn't support return links of files
307 * @return int
309 public function supported_returntypes() {
310 return FILE_INTERNAL;
314 * Is this repository accessing private data?
316 * @return bool
318 public function contains_private_data() {
319 return false;