Merge branch 'wip-MDL-62351-master' of git://github.com/marinaglancy/moodle
[moodle.git] / repository / s3 / lib.php
blob5b721dae9cf6cfb48468937b21f92375415d60fc
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 // 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);
34 /**
35 * This is a repository class used to browse Amazon S3 content.
37 * @since Moodle 2.0
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 /**
45 * Constructor
46 * @param int $repositoryid
47 * @param object $context
48 * @param array $options
50 public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
51 global $CFG;
52 parent::__construct($repositoryid, $context, $options);
53 $this->access_key = get_config('s3', 'access_key');
54 $this->secret_key = get_config('s3', 'secret_key');
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';
59 $this->s = new S3($this->access_key, $this->secret_key, false, $this->endpoint);
60 $this->s->setExceptions(true);
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;
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;
76 if (!empty($CFG->proxytype) && $CFG->proxytype == 'SOCKS5') {
77 $proxytype = CURLPROXY_SOCKS5;
79 $this->s->setProxy($proxyhost, $proxyuser, $proxypass, $proxytype);
83 /**
84 * Extracts the Bucket and URI from the path
86 * @param string $path path in this format 'bucket/path/to/folder/and/file'
87 * @return array including bucket and uri
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 = '';
97 return array($bucket, $uri);
101 * Get S3 file list
103 * @param string $path
104 * @return array The file list and options
106 public function get_listing($path = '', $page = '') {
107 global $CFG, $OUTPUT;
108 if (empty($this->access_key)) {
109 throw new moodle_exception('needaccesskey', 'repository_s3');
112 $list = array();
113 $list['list'] = array();
114 $list['path'] = array(
115 array('name' => get_string('pluginname', 'repository_s3'), 'path' => '')
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;
128 $tree = array();
130 if (empty($path)) {
131 try {
132 $buckets = $this->s->listBuckets();
133 } catch (S3Exception $e) {
134 throw new moodle_exception(
135 'errorwhilecommunicatingwith',
136 'repository',
138 $this->get_name(),
139 $e->getMessage()
142 foreach ($buckets as $bucket) {
143 $folder = array(
144 'title' => $bucket,
145 'children' => array(),
146 'thumbnail' => $OUTPUT->image_url(file_folder_icon(90))->out(false),
147 'path' => $bucket
149 $tree[] = $folder;
151 } else {
152 $files = array();
153 $folders = array();
154 list($bucket, $uri) = $this->explode_path($path);
156 try {
157 $contents = $this->s->getBucket($bucket, $uri, null, null, '/', true);
158 } catch (S3Exception $e) {
159 throw new moodle_exception(
160 'errorwhilecommunicatingwith',
161 'repository',
163 $this->get_name(),
164 $e->getMessage()
167 foreach ($contents as $object) {
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'];
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;
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->image_url(file_folder_icon(90))->out(false),
192 'path' => $bucket . '/' . $object['prefix']
194 } else {
195 $files[] = array(
196 'title' => $title,
197 'size' => $object['size'],
198 'datemodified' => $object['time'],
199 'source' => $bucket . '/' . $object['name'],
200 'thumbnail' => $OUTPUT->image_url(file_extension_icon($title, 90))->out(false)
204 $tree = array_merge($folders, $files);
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);
217 } else {
218 $list['path'][] = array('name' => $path, 'path' => $path);
222 $list['list'] = $tree;
224 return $list;
228 * Download S3 files to moodle
230 * @param string $filepath
231 * @param string $file The file path in moodle
232 * @return array The local stored path
234 public function get_file($filepath, $file = '') {
235 list($bucket, $uri) = $this->explode_path($filepath);
236 $path = $this->prepare_file($file);
237 try {
238 $this->s->getObject($bucket, $uri, $path);
239 } catch (S3Exception $e) {
240 throw new moodle_exception(
241 'errorwhilecommunicatingwith',
242 'repository',
244 $this->get_name(),
245 $e->getMessage()
248 return array('path' => $path);
252 * Return the source information
254 * @param stdClass $filepath
255 * @return string
257 public function get_file_source_info($filepath) {
258 return 'Amazon S3: ' . $filepath;
262 * S3 doesn't require login
264 * @return bool
266 public function check_login() {
267 return true;
271 * S3 doesn't provide search
273 * @return bool
275 public function global_search() {
276 return false;
279 public static function get_type_option_names() {
280 return array('access_key', 'secret_key', 'endpoint', 'pluginname');
283 public static function type_config_form($mform, $classname = 'repository') {
284 parent::type_config_form($mform);
285 $strrequired = get_string('required');
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"
299 $mform->addElement('text', 'access_key', get_string('access_key', 'repository_s3'));
300 $mform->setType('access_key', PARAM_RAW_TRIMMED);
301 $mform->addElement('text', 'secret_key', get_string('secret_key', 'repository_s3'));
302 $mform->setType('secret_key', PARAM_RAW_TRIMMED);
303 $mform->addElement('select', 'endpoint', get_string('endpoint', 'repository_s3'), $endpointselect);
304 $mform->setDefault('endpoint', 's3.amazonaws.com'); // Default to US Endpoint.
305 $mform->addRule('access_key', $strrequired, 'required', null, 'client');
306 $mform->addRule('secret_key', $strrequired, 'required', null, 'client');
310 * S3 plugins doesn't support return links of files
312 * @return int
314 public function supported_returntypes() {
315 return FILE_INTERNAL;
319 * Is this repository accessing private data?
321 * @return bool
323 public function contains_private_data() {
324 return false;