MDL-53467 repositories: Upgrade s3 to v0.5.1
[moodle.git] / repository / s3 / lib.php
CommitLineData
4317f92f 1<?php
d2c98296
DC
2
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.
14//
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/>.
17
d2c98296 18/**
67233725 19 * This plugin is used to access s3 files
d2c98296 20 *
5bcfd504 21 * @since Moodle 2.0
67233725
DC
22 * @package repository_s3
23 * @copyright 2010 Dongsheng Cai {@link http://dongsheng.org}
d078f6d3 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
d2c98296 25 */
67233725 26require_once($CFG->dirroot . '/repository/lib.php');
12ca7133 27require_once($CFG->dirroot . '/repository/s3/S3.php');
2e1cfc6e 28
f6592b94
AG
29// This constant is not defined in php 5.4. Set it to avoid errors.
30if (!defined('CURL_SSLVERSION_TLSv1')) {
31 define('CURL_SSLVERSION_TLSv1', 1);
32}
33
67233725
DC
34/**
35 * This is a repository class used to browse Amazon S3 content.
36 *
5bcfd504 37 * @since Moodle 2.0
67233725
DC
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
41 */
2e1cfc6e 42class repository_s3 extends repository {
d2c98296
DC
43
44 /**
45 * Constructor
46 * @param int $repositoryid
47 * @param object $context
48 * @param array $options
49 */
447c7a19 50 public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
2a5920c3 51 global $CFG;
2e1cfc6e 52 parent::__construct($repositoryid, $context, $options);
53 $this->access_key = get_config('s3', 'access_key');
54 $this->secret_key = get_config('s3', 'secret_key');
9b71e3af
DB
55 $this->endpoint = get_config('s3', 'endpoint');
56 if ($this->endpoint === false) { // If no endpoint has been set, use the default.
57 $this->endpoint = 's3.amazonaws.com';
58 }
59 $this->s = new S3($this->access_key, $this->secret_key, false, $this->endpoint);
1fefd1ff 60 $this->s->setExceptions(true);
2a5920c3
FM
61
62 // Port of curl::__construct().
63 if (!empty($CFG->proxyhost)) {
64 if (empty($CFG->proxyport)) {
65 $proxyhost = $CFG->proxyhost;
66 } else {
67 $proxyhost = $CFG->proxyhost . ':' . $CFG->proxyport;
68 }
69 $proxytype = CURLPROXY_HTTP;
70 $proxyuser = null;
71 $proxypass = null;
72 if (!empty($CFG->proxyuser) and !empty($CFG->proxypassword)) {
73 $proxyuser = $CFG->proxyuser;
74 $proxypass = $CFG->proxypassword;
75 }
76 if (!empty($CFG->proxytype) && $CFG->proxytype == 'SOCKS5') {
77 $proxytype = CURLPROXY_SOCKS5;
78 }
79 $this->s->setProxy($proxyhost, $proxyuser, $proxypass, $proxytype);
80 }
2e1cfc6e 81 }
d2c98296 82
b061530d
FM
83 /**
84 * Extracts the Bucket and URI from the path
85 *
86 * @param string $path path in this format 'bucket/path/to/folder/and/file'
87 * @return array including bucket and uri
88 */
89 protected function explode_path($path) {
90 $parts = explode('/', $path, 2);
91 if (isset($parts[1]) && $parts[1] !== '') {
92 list($bucket, $uri) = $parts;
93 } else {
94 $bucket = $parts[0];
95 $uri = '';
96 }
97 return array($bucket, $uri);
98 }
99
d2c98296
DC
100 /**
101 * Get S3 file list
102 *
103 * @param string $path
104 * @return array The file list and options
105 */
58eb9b9f 106 public function get_listing($path = '', $page = '') {
390baf46 107 global $CFG, $OUTPUT;
d2c98296 108 if (empty($this->access_key)) {
1fefd1ff 109 throw new moodle_exception('needaccesskey', 'repository_s3');
d2c98296 110 }
b061530d 111
2e1cfc6e 112 $list = array();
113 $list['list'] = array();
b061530d
FM
114 $list['path'] = array(
115 array('name' => get_string('pluginname', 'repository_s3'), 'path' => '')
116 );
117
2e1cfc6e 118 // the management interface url
119 $list['manage'] = false;
120 // dynamically loading
121 $list['dynload'] = true;
122 // the current path of this list.
123 // set to true, the login link will be removed
124 $list['nologin'] = true;
125 // set to true, the search button will be removed
126 $list['nosearch'] = true;
b061530d 127
2e1cfc6e 128 $tree = array();
b061530d 129
2e1cfc6e 130 if (empty($path)) {
1fefd1ff
FM
131 try {
132 $buckets = $this->s->listBuckets();
133 } catch (S3Exception $e) {
20a263ec
JC
134 throw new moodle_exception(
135 'errorwhilecommunicatingwith',
136 'repository',
137 '',
138 $this->get_name(),
139 $e->getMessage()
140 );
1fefd1ff 141 }
2e1cfc6e 142 foreach ($buckets as $bucket) {
143 $folder = array(
144 'title' => $bucket,
145 'children' => array(),
b061530d
FM
146 'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
147 'path' => $bucket
2e1cfc6e 148 );
149 $tree[] = $folder;
150 }
151 } else {
b061530d
FM
152 $files = array();
153 $folders = array();
154 list($bucket, $uri) = $this->explode_path($path);
155
1fefd1ff
FM
156 try {
157 $contents = $this->s->getBucket($bucket, $uri, null, null, '/', true);
158 } catch (S3Exception $e) {
20a263ec
JC
159 throw new moodle_exception(
160 'errorwhilecommunicatingwith',
161 'repository',
162 '',
163 $this->get_name(),
164 $e->getMessage()
165 );
1fefd1ff 166 }
b061530d
FM
167 foreach ($contents as $object) {
168
169 // If object has a prefix, it is a 'CommonPrefix', which we consider a folder
170 if (isset($object['prefix'])) {
171 $title = rtrim($object['prefix'], '/');
172 } else {
173 $title = $object['name'];
174 }
175
176 // Removes the prefix (folder path) from the title
177 if (strlen($uri) > 0) {
178 $title = substr($title, strlen($uri));
179 // Check if title is empty and not zero
180 if (empty($title) && !is_numeric($title)) {
181 // Amazon returns the prefix itself, we skip it
182 continue;
183 }
184 }
185
186 // This is a so-called CommonPrefix, we consider it as a folder
187 if (isset($object['prefix'])) {
188 $folders[] = array(
189 'title' => $title,
190 'children' => array(),
191 'thumbnail'=> $OUTPUT->pix_url(file_folder_icon(90))->out(false),
192 'path' => $bucket . '/' . $object['prefix']
2e1cfc6e 193 );
b061530d
FM
194 } else {
195 $files[] = array(
196 'title' => $title,
197 'size' => $object['size'],
198 'datemodified' => $object['time'],
199 'source' => $bucket . '/' . $object['name'],
200 'thumbnail' => $OUTPUT->pix_url(file_extension_icon($title, 90))->out(false)
201 );
202 }
203 }
204 $tree = array_merge($folders, $files);
205 }
206
207 $trail = '';
208 if (!empty($path)) {
209 $parts = explode('/', $path);
210 if (count($parts) > 1) {
211 foreach ($parts as $part) {
212 if (!empty($part)) {
213 $trail .= $part . '/';
214 $list['path'][] = array('name' => $part, 'path' => $trail);
215 }
216 }
217 } else {
218 $list['path'][] = array('name' => $path, 'path' => $path);
2e1cfc6e 219 }
220 }
221
222 $list['list'] = $tree;
223
224 return $list;
225 }
d2c98296
DC
226
227 /**
228 * Download S3 files to moodle
229 *
230 * @param string $filepath
231 * @param string $file The file path in moodle
232 * @return array The local stored path
233 */
68a7c9a6 234 public function get_file($filepath, $file = '') {
b061530d 235 list($bucket, $uri) = $this->explode_path($filepath);
a53d4f45 236 $path = $this->prepare_file($file);
1fefd1ff
FM
237 try {
238 $this->s->getObject($bucket, $uri, $path);
239 } catch (S3Exception $e) {
20a263ec
JC
240 throw new moodle_exception(
241 'errorwhilecommunicatingwith',
242 'repository',
243 '',
244 $this->get_name(),
245 $e->getMessage()
246 );
1fefd1ff 247 }
b061530d 248 return array('path' => $path);
2e1cfc6e 249 }
d2c98296 250
d6453211
DC
251 /**
252 * Return the source information
253 *
254 * @param stdClass $filepath
255 * @return string
256 */
257 public function get_file_source_info($filepath) {
83d2700e 258 return 'Amazon S3: ' . $filepath;
d6453211
DC
259 }
260
d2c98296
DC
261 /**
262 * S3 doesn't require login
263 *
264 * @return bool
265 */
2e1cfc6e 266 public function check_login() {
267 return true;
268 }
2f67a9b3 269
d2c98296
DC
270 /**
271 * S3 doesn't provide search
272 *
273 * @return bool
2f67a9b3 274 */
2e1cfc6e 275 public function global_search() {
276 return false;
277 }
d2c98296 278
2e1cfc6e 279 public static function get_type_option_names() {
d9087979 280 return array('access_key', 'secret_key', 'endpoint', 'pluginname');
2e1cfc6e 281 }
d2c98296 282
68a7c9a6 283 public static function type_config_form($mform, $classname = 'repository') {
a5adfa26 284 parent::type_config_form($mform);
2e1cfc6e 285 $strrequired = get_string('required');
9b71e3af
DB
286 $endpointselect = array( // List of possible Amazon S3 Endpoints.
287 "s3.amazonaws.com" => "s3.amazonaws.com",
288 "s3-external-1.amazonaws.com" => "s3-external-1.amazonaws.com",
289 "s3-us-west-2.amazonaws.com" => "s3-us-west-2.amazonaws.com",
290 "s3-us-west-1.amazonaws.com" => "s3-us-west-1.amazonaws.com",
291 "s3-eu-west-1.amazonaws.com" => "s3-eu-west-1.amazonaws.com",
292 "s3.eu-central-1.amazonaws.com" => "s3.eu-central-1.amazonaws.com",
293 "s3-eu-central-1.amazonaws.com" => "s3-eu-central-1.amazonaws.com",
294 "s3-ap-southeast-1.amazonaws.com" => "s3-ap-southeast-1.amazonaws.com",
295 "s3-ap-southeast-2.amazonaws.com" => "s3-ap-southeast-2.amazonaws.com",
296 "s3-ap-northeast-1.amazonaws.com" => "s3-ap-northeast-1.amazonaws.com",
297 "s3-sa-east-1.amazonaws.com" => "s3-sa-east-1.amazonaws.com"
298 );
2e1cfc6e 299 $mform->addElement('text', 'access_key', get_string('access_key', 'repository_s3'));
8077527c 300 $mform->setType('access_key', PARAM_RAW_TRIMMED);
2e1cfc6e 301 $mform->addElement('text', 'secret_key', get_string('secret_key', 'repository_s3'));
8077527c 302 $mform->setType('secret_key', PARAM_RAW_TRIMMED);
9afe4eb5
DM
303 $mform->addElement('select', 'endpoint', get_string('endpoint', 'repository_s3'), $endpointselect);
304 $mform->setDefault('endpoint', 's3.amazonaws.com'); // Default to US Endpoint.
2e1cfc6e 305 $mform->addRule('access_key', $strrequired, 'required', null, 'client');
306 $mform->addRule('secret_key', $strrequired, 'required', null, 'client');
2e1cfc6e 307 }
d2c98296
DC
308
309 /**
310 * S3 plugins doesn't support return links of files
311 *
312 * @return int
2f67a9b3 313 */
41076c58
DC
314 public function supported_returntypes() {
315 return FILE_INTERNAL;
316 }
31581ae6
FM
317
318 /**
319 * Is this repository accessing private data?
320 *
321 * @return bool
322 */
323 public function contains_private_data() {
324 return false;
325 }
2e1cfc6e 326}