MDL-34047 repository URL downloader must say that it returns only images
[moodle.git] / repository / url / lib.php
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.
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/>.
18 /**
19  * This plugin is used to access files by providing an url
20  *
21  * @since 2.0
22  * @package    repository_url
23  * @copyright  2010 Dongsheng Cai {@link http://dongsheng.org}
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
26 require_once($CFG->dirroot . '/repository/lib.php');
27 require_once(dirname(__FILE__).'/locallib.php');
29 /**
30  * repository_url class
31  * A subclass of repository, which is used to download a file from a specific url
32  *
33  * @since 2.0
34  * @package    repository_url
35  * @copyright  2009 Dongsheng Cai {@link http://dongsheng.org}
36  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37  */
38 class repository_url extends repository {
39     var $processedfiles = array();
41     /**
42      * @param int $repositoryid
43      * @param object $context
44      * @param array $options
45      */
46     public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()){
47         global $CFG;
48         parent::__construct($repositoryid, $context, $options);
49         $this->file_url = optional_param('file', '', PARAM_RAW);
50     }
52     public function check_login() {
53         if (!empty($this->file_url)) {
54             return true;
55         } else {
56             return false;
57         }
58     }
59     /**
60      * @return mixed
61      */
62     public function print_login() {
63         $strdownload = get_string('download', 'repository');
64         $strname     = get_string('rename', 'repository_url');
65         $strurl      = get_string('url', 'repository_url');
66         if ($this->options['ajax']) {
67             $url = new stdClass();
68             $url->label = $strurl.': ';
69             $url->id   = 'fileurl';
70             $url->type = 'text';
71             $url->name = 'file';
73             $ret['login'] = array($url);
74             $ret['login_btn_label'] = get_string('download', 'repository_url');
75             $ret['allowcaching'] = true; // indicates that login form can be cached in filepicker.js
76             return $ret;
77         } else {
78             echo <<<EOD
79 <table>
80 <tr>
81 <td>{$strurl}: </td><td><input name="file" type="text" /></td>
82 </tr>
83 </table>
84 <input type="submit" value="{$strdownload}" />
85 EOD;
87         }
88     }
90     /**
91      * @param mixed $path
92      * @param string $search
93      * @return array
94      */
95     public function get_listing($path='', $page='') {
96         global $CFG, $OUTPUT;
97         $ret = array();
98         $ret['list'] = array();
99         $ret['nosearch'] = true;
100         $ret['norefresh'] = true;
101         $ret['nologin'] = true;
103         $this->parse_file(null, $this->file_url, $ret, true);
104         return $ret;
105     }
107     /**
108      * Parses one file (either html or css)
109      *
110      * @param string $baseurl (optional) URL of the file where link to this file was found
111      * @param string $relativeurl relative or absolute link to the file
112      * @param array $list
113      * @param bool $mainfile true only for main HTML false and false for all embedded/linked files
114      */
115     protected function parse_file($baseurl, $relativeurl, &$list, $mainfile = false) {
116         if (preg_match('/([\'"])(.*)\1/', $relativeurl, $matches)) {
117             $relativeurl = $matches[2];
118         }
119         if (empty($baseurl)) {
120             $url = $relativeurl;
121         } else {
122             $url = htmlspecialchars_decode(url_to_absolute($baseurl, $relativeurl));
123         }
124         if (in_array($url, $this->processedfiles)) {
125             // avoid endless recursion
126             return;
127         }
128         $this->processedfiles[] = $url;
129         $curl = new curl;
130         $msg = $curl->head($url);
131         $info = $curl->get_info();
132         if ($info['http_code'] != 200) {
133             if ($mainfile) {
134                 $list['error'] = $msg;
135             }
136         } else {
137             $csstoanalyze = '';
138             if ($mainfile && (strstr($info['content_type'], 'text/html') || empty($info['content_type']))) {
139                 // parse as html
140                 $htmlcontent = $curl->get($info['url']);
141                 $ddoc = new DOMDocument();
142                 @$ddoc->loadHTML($htmlcontent);
143                 // extract <img>
144                 $tags = $ddoc->getElementsByTagName('img');
145                 foreach ($tags as $tag) {
146                     $url = $tag->getAttribute('src');
147                     $this->add_image_to_list($info['url'], $url, $list);
148                 }
149                 // analyse embedded css (<style>)
150                 $tags = $ddoc->getElementsByTagName('style');
151                 foreach ($tags as $tag) {
152                     if ($tag->getAttribute('type') == 'text/css') {
153                         $csstoanalyze .= $tag->textContent."\n";
154                     }
155                 }
156                 // analyse links to css (<link type='text/css' href='...'>)
157                 $tags = $ddoc->getElementsByTagName('link');
158                 foreach ($tags as $tag) {
159                     if ($tag->getAttribute('type') == 'text/css' && strlen($tag->getAttribute('href'))) {
160                         $this->parse_file($info['url'], $tag->getAttribute('href'), $list);
161                     }
162                 }
163             } else if (strstr($info['content_type'], 'css')) {
164                 // parse as css
165                 $csscontent = $curl->get($info['url']);
166                 $csstoanalyze .= $csscontent."\n";
167             } else if (strstr($info['content_type'], 'image/')) {
168                 // download this file
169                 $this->add_image_to_list($info['url'], $info['url'], $list);
170             }
172             // parse all found css styles
173             if (strlen($csstoanalyze)) {
174                 $urls = extract_css_urls($csstoanalyze);
175                 if (!empty($urls['property'])) {
176                     foreach ($urls['property'] as $url) {
177                         $this->add_image_to_list($info['url'], $url, $list);
178                     }
179                 }
180                 if (!empty($urls['import'])) {
181                     foreach ($urls['import'] as $cssurl) {
182                         $this->parse_file($info['url'], $cssurl, $list);
183                     }
184                 }
185             }
186         }
187     }
188     protected function add_image_to_list($baseurl, $url, &$list) {
189         if (empty($list['list'])) {
190             $list['list'] = array();
191         }
192         $src = url_to_absolute($baseurl, htmlspecialchars_decode($url));
193         foreach ($list['list'] as $image) {
194             if ($image['source'] == $src) {
195                 return;
196             }
197         }
198         $list['list'][] = array(
199             'title'=>$this->guess_filename($url, ''),
200             'source'=>$src,
201             'thumbnail'=>$src,
202             'thumbnail_height'=>84,
203             'thumbnail_width'=>84
204         );
205     }
206     public function guess_filename($url, $type) {
207         $pattern = '#\/([\w_\?\-.]+)$#';
208         $matches = null;
209         preg_match($pattern, $url, $matches);
210         if (empty($matches[1])) {
211             return $url;
212         } else {
213             return $matches[1];
214         }
215     }
217     public function supported_returntypes() {
218         return (FILE_INTERNAL | FILE_EXTERNAL);
219     }
221     /**
222      * Return the source information
223      *
224      * @param stdClass $url
225      * @return string|null
226      */
227     public function get_file_source_info($url) {
228         return $url;
229     }
231     /**
232      * file types supported by url downloader plugin
233      *
234      * @return array
235      */
236     public function supported_filetypes() {
237         return array('web_image');
238     }