source: moodle/trunk/fuentes/lib/classes/filetypes.php @ 1331

Last change on this file since 1331 was 1331, checked in by jrpelegrina, 3 years ago

Updated to moodle 3.0.3

File size: 37.6 KB
Line 
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Class to manage the custom filetypes list that is stored in a config variable.
19 *
20 * @package core
21 * @copyright 2014 The Open University
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25defined('MOODLE_INTERNAL') || die();
26
27require_once($CFG->libdir . '/filelib.php');
28
29/**
30 * Class to manage the custom filetypes list that is stored in a config variable.
31 *
32 * @copyright 2014 The Open University
33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34 */
35abstract class core_filetypes {
36    /** @var array Cached MIME types for current request */
37    protected static $cachedtypes;
38
39    /**
40     * Gets default MIME types that are included as standard.
41     *
42     * Note: Use the function get_mimetypes_array to access this data including
43     * any customisations the user might have made.
44     *
45     * @return array Default (pre-installed) MIME type information
46     */
47    protected static function get_default_types() {
48        return array(
49            'xxx' => array('type' => 'document/unknown', 'icon' => 'unknown'),
50            '3gp' => array('type' => 'video/quicktime', 'icon' => 'quicktime', 'groups' => array('video'), 'string' => 'video'),
51            '7z' => array('type' => 'application/x-7z-compressed', 'icon' => 'archive',
52                    'groups' => array('archive'), 'string' => 'archive'),
53            'aac' => array('type' => 'audio/aac', 'icon' => 'audio', 'groups' => array('audio'), 'string' => 'audio'),
54            'accdb' => array('type' => 'application/msaccess', 'icon' => 'base'),
55            'ai' => array('type' => 'application/postscript', 'icon' => 'eps', 'groups' => array('image'), 'string' => 'image'),
56            'aif' => array('type' => 'audio/x-aiff', 'icon' => 'audio', 'groups' => array('audio'), 'string' => 'audio'),
57            'aiff' => array('type' => 'audio/x-aiff', 'icon' => 'audio', 'groups' => array('audio'), 'string' => 'audio'),
58            'aifc' => array('type' => 'audio/x-aiff', 'icon' => 'audio', 'groups' => array('audio'), 'string' => 'audio'),
59            'applescript' => array('type' => 'text/plain', 'icon' => 'text'),
60            'asc' => array('type' => 'text/plain', 'icon' => 'sourcecode'),
61            'asm' => array('type' => 'text/plain', 'icon' => 'sourcecode'),
62            'au' => array('type' => 'audio/au', 'icon' => 'audio', 'groups' => array('audio'), 'string' => 'audio'),
63            'avi' => array('type' => 'video/x-ms-wm', 'icon' => 'avi',
64                    'groups' => array('video', 'web_video'), 'string' => 'video'),
65            'bmp' => array('type' => 'image/bmp', 'icon' => 'bmp', 'groups' => array('image'), 'string' => 'image'),
66            'c' => array('type' => 'text/plain', 'icon' => 'sourcecode'),
67            'cct' => array('type' => 'shockwave/director', 'icon' => 'flash'),
68            'cpp' => array('type' => 'text/plain', 'icon' => 'sourcecode'),
69            'cs' => array('type' => 'application/x-csh', 'icon' => 'sourcecode'),
70            'css' => array('type' => 'text/css', 'icon' => 'text', 'groups' => array('web_file')),
71            'csv' => array('type' => 'text/csv', 'icon' => 'spreadsheet', 'groups' => array('spreadsheet')),
72            'dv' => array('type' => 'video/x-dv', 'icon' => 'quicktime', 'groups' => array('video'), 'string' => 'video'),
73            'dmg' => array('type' => 'application/octet-stream', 'icon' => 'unknown'),
74
75            'doc' => array('type' => 'application/msword', 'icon' => 'document', 'groups' => array('document')),
76            'bdoc' => array('type' => 'application/x-digidoc', 'icon' => 'document', 'groups' => array('archive')),
77            'cdoc' => array('type' => 'application/x-digidoc', 'icon' => 'document', 'groups' => array('archive')),
78            'ddoc' => array('type' => 'application/x-digidoc', 'icon' => 'document', 'groups' => array('archive')),
79            'docx' => array('type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
80                    'icon' => 'document', 'groups' => array('document')),
81            'docm' => array('type' => 'application/vnd.ms-word.document.macroEnabled.12', 'icon' => 'document'),
82            'dotx' => array('type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
83                    'icon' => 'document'),
84            'dotm' => array('type' => 'application/vnd.ms-word.template.macroEnabled.12', 'icon' => 'document'),
85
86            'dcr' => array('type' => 'application/x-director', 'icon' => 'flash'),
87            'dif' => array('type' => 'video/x-dv', 'icon' => 'quicktime', 'groups' => array('video'), 'string' => 'video'),
88            'dir' => array('type' => 'application/x-director', 'icon' => 'flash'),
89            'dxr' => array('type' => 'application/x-director', 'icon' => 'flash'),
90            'eps' => array('type' => 'application/postscript', 'icon' => 'eps'),
91            'epub' => array('type' => 'application/epub+zip', 'icon' => 'epub', 'groups' => array('document')),
92            'fdf' => array('type' => 'application/pdf', 'icon' => 'pdf'),
93            'flv' => array('type' => 'video/x-flv', 'icon' => 'flash',
94                    'groups' => array('video', 'web_video'), 'string' => 'video'),
95            'f4v' => array('type' => 'video/mp4', 'icon' => 'flash', 'groups' => array('video', 'web_video'), 'string' => 'video'),
96
97            'gallery' => array('type' => 'application/x-smarttech-notebook', 'icon' => 'archive'),
98            'galleryitem' => array('type' => 'application/x-smarttech-notebook', 'icon' => 'archive'),
99            'gallerycollection' => array('type' => 'application/x-smarttech-notebook', 'icon' => 'archive'),
100            'gif' => array('type' => 'image/gif', 'icon' => 'gif', 'groups' => array('image', 'web_image'), 'string' => 'image'),
101            'gtar' => array('type' => 'application/x-gtar', 'icon' => 'archive',
102                    'groups' => array('archive'), 'string' => 'archive'),
103            'tgz' => array('type' => 'application/g-zip', 'icon' => 'archive', 'groups' => array('archive'), 'string' => 'archive'),
104            'gz' => array('type' => 'application/g-zip', 'icon' => 'archive', 'groups' => array('archive'), 'string' => 'archive'),
105            'gzip' => array('type' => 'application/g-zip', 'icon' => 'archive',
106                    'groups' => array('archive'), 'string' => 'archive'),
107            'h' => array('type' => 'text/plain', 'icon' => 'sourcecode'),
108            'hpp' => array('type' => 'text/plain', 'icon' => 'sourcecode'),
109            'hqx' => array('type' => 'application/mac-binhex40', 'icon' => 'archive',
110                    'groups' => array('archive'), 'string' => 'archive'),
111            'htc' => array('type' => 'text/x-component', 'icon' => 'markup'),
112            'html' => array('type' => 'text/html', 'icon' => 'html', 'groups' => array('web_file')),
113            'xhtml' => array('type' => 'application/xhtml+xml', 'icon' => 'html', 'groups' => array('web_file')),
114            'htm' => array('type' => 'text/html', 'icon' => 'html', 'groups' => array('web_file')),
115            'ico' => array('type' => 'image/vnd.microsoft.icon', 'icon' => 'image',
116                    'groups' => array('image'), 'string' => 'image'),
117            'ics' => array('type' => 'text/calendar', 'icon' => 'text'),
118            'isf' => array('type' => 'application/inspiration', 'icon' => 'isf'),
119            'ist' => array('type' => 'application/inspiration.template', 'icon' => 'isf'),
120            'java' => array('type' => 'text/plain', 'icon' => 'sourcecode'),
121            'jar' => array('type' => 'application/java-archive', 'icon' => 'archive'),
122            'jcb' => array('type' => 'text/xml', 'icon' => 'markup'),
123            'jcl' => array('type' => 'text/xml', 'icon' => 'markup'),
124            'jcw' => array('type' => 'text/xml', 'icon' => 'markup'),
125            'jmt' => array('type' => 'text/xml', 'icon' => 'markup'),
126            'jmx' => array('type' => 'text/xml', 'icon' => 'markup'),
127            'jnlp' => array('type' => 'application/x-java-jnlp-file', 'icon' => 'markup'),
128            'jpe' => array('type' => 'image/jpeg', 'icon' => 'jpeg', 'groups' => array('image', 'web_image'), 'string' => 'image'),
129            'jpeg' => array('type' => 'image/jpeg', 'icon' => 'jpeg', 'groups' => array('image', 'web_image'), 'string' => 'image'),
130            'jpg' => array('type' => 'image/jpeg', 'icon' => 'jpeg', 'groups' => array('image', 'web_image'), 'string' => 'image'),
131            'jqz' => array('type' => 'text/xml', 'icon' => 'markup'),
132            'js' => array('type' => 'application/x-javascript', 'icon' => 'text', 'groups' => array('web_file')),
133            'latex' => array('type' => 'application/x-latex', 'icon' => 'text'),
134            'm' => array('type' => 'text/plain', 'icon' => 'sourcecode'),
135            'mbz' => array('type' => 'application/vnd.moodle.backup', 'icon' => 'moodle'),
136            'mdb' => array('type' => 'application/x-msaccess', 'icon' => 'base'),
137            'mht' => array('type' => 'message/rfc822', 'icon' => 'archive'),
138            'mhtml' => array('type' => 'message/rfc822', 'icon' => 'archive'),
139            'mov' => array('type' => 'video/quicktime', 'icon' => 'quicktime',
140                    'groups' => array('video', 'web_video'), 'string' => 'video'),
141            'movie' => array('type' => 'video/x-sgi-movie', 'icon' => 'quicktime', 'groups' => array('video'), 'string' => 'video'),
142            'mw' => array('type' => 'application/maple', 'icon' => 'math'),
143            'mws' => array('type' => 'application/maple', 'icon' => 'math'),
144            'm3u' => array('type' => 'audio/x-mpegurl', 'icon' => 'mp3', 'groups' => array('audio'), 'string' => 'audio'),
145            'mp3' => array('type' => 'audio/mp3', 'icon' => 'mp3', 'groups' => array('audio', 'web_audio'), 'string' => 'audio'),
146            'mp4' => array('type' => 'video/mp4', 'icon' => 'mpeg', 'groups' => array('video', 'web_video'), 'string' => 'video'),
147            'm4v' => array('type' => 'video/mp4', 'icon' => 'mpeg', 'groups' => array('video', 'web_video'), 'string' => 'video'),
148            'm4a' => array('type' => 'audio/mp4', 'icon' => 'mp3', 'groups' => array('audio'), 'string' => 'audio'),
149            'mpeg' => array('type' => 'video/mpeg', 'icon' => 'mpeg', 'groups' => array('video', 'web_video'), 'string' => 'video'),
150            'mpe' => array('type' => 'video/mpeg', 'icon' => 'mpeg', 'groups' => array('video', 'web_video'), 'string' => 'video'),
151            'mpg' => array('type' => 'video/mpeg', 'icon' => 'mpeg', 'groups' => array('video', 'web_video'), 'string' => 'video'),
152            'mpr' => array('type' => 'application/vnd.moodle.profiling', 'icon' => 'moodle'),
153
154            'nbk' => array('type' => 'application/x-smarttech-notebook', 'icon' => 'archive'),
155            'notebook' => array('type' => 'application/x-smarttech-notebook', 'icon' => 'archive'),
156
157            'odt' => array('type' => 'application/vnd.oasis.opendocument.text', 'icon' => 'writer', 'groups' => array('document')),
158            'ott' => array('type' => 'application/vnd.oasis.opendocument.text-template',
159                    'icon' => 'writer', 'groups' => array('document')),
160            'oth' => array('type' => 'application/vnd.oasis.opendocument.text-web', 'icon' => 'oth', 'groups' => array('document')),
161            'odm' => array('type' => 'application/vnd.oasis.opendocument.text-master', 'icon' => 'writer'),
162            'odg' => array('type' => 'application/vnd.oasis.opendocument.graphics', 'icon' => 'draw'),
163            'otg' => array('type' => 'application/vnd.oasis.opendocument.graphics-template', 'icon' => 'draw'),
164            'odp' => array('type' => 'application/vnd.oasis.opendocument.presentation', 'icon' => 'impress'),
165            'otp' => array('type' => 'application/vnd.oasis.opendocument.presentation-template', 'icon' => 'impress'),
166            'ods' => array('type' => 'application/vnd.oasis.opendocument.spreadsheet',
167                    'icon' => 'calc', 'groups' => array('spreadsheet')),
168            'ots' => array('type' => 'application/vnd.oasis.opendocument.spreadsheet-template',
169                    'icon' => 'calc', 'groups' => array('spreadsheet')),
170            'odc' => array('type' => 'application/vnd.oasis.opendocument.chart', 'icon' => 'chart'),
171            'odf' => array('type' => 'application/vnd.oasis.opendocument.formula', 'icon' => 'math'),
172            'odb' => array('type' => 'application/vnd.oasis.opendocument.database', 'icon' => 'base'),
173            'odi' => array('type' => 'application/vnd.oasis.opendocument.image', 'icon' => 'draw'),
174            'oga' => array('type' => 'audio/ogg', 'icon' => 'audio', 'groups' => array('audio'), 'string' => 'audio'),
175            'ogg' => array('type' => 'audio/ogg', 'icon' => 'audio', 'groups' => array('audio'), 'string' => 'audio'),
176            'ogv' => array('type' => 'video/ogg', 'icon' => 'video', 'groups' => array('video'), 'string' => 'video'),
177
178            'pct' => array('type' => 'image/pict', 'icon' => 'image', 'groups' => array('image'), 'string' => 'image'),
179            'pdf' => array('type' => 'application/pdf', 'icon' => 'pdf'),
180            'php' => array('type' => 'text/plain', 'icon' => 'sourcecode'),
181            'pic' => array('type' => 'image/pict', 'icon' => 'image', 'groups' => array('image'), 'string' => 'image'),
182            'pict' => array('type' => 'image/pict', 'icon' => 'image', 'groups' => array('image'), 'string' => 'image'),
183            'png' => array('type' => 'image/png', 'icon' => 'png', 'groups' => array('image', 'web_image'), 'string' => 'image'),
184            'pps' => array('type' => 'application/vnd.ms-powerpoint', 'icon' => 'powerpoint', 'groups' => array('presentation')),
185            'ppt' => array('type' => 'application/vnd.ms-powerpoint', 'icon' => 'powerpoint', 'groups' => array('presentation')),
186            'pptx' => array('type' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
187                    'icon' => 'powerpoint'),
188            'pptm' => array('type' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', 'icon' => 'powerpoint'),
189            'potx' => array('type' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
190                    'icon' => 'powerpoint'),
191            'potm' => array('type' => 'application/vnd.ms-powerpoint.template.macroEnabled.12', 'icon' => 'powerpoint'),
192            'ppam' => array('type' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12', 'icon' => 'powerpoint'),
193            'ppsx' => array('type' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
194                    'icon' => 'powerpoint'),
195            'ppsm' => array('type' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', 'icon' => 'powerpoint'),
196            'ps' => array('type' => 'application/postscript', 'icon' => 'pdf'),
197            'pub' => array('type' => 'application/x-mspublisher', 'icon' => 'publisher', 'groups' => array('presentation')),
198
199            'qt' => array('type' => 'video/quicktime', 'icon' => 'quicktime',
200                    'groups' => array('video', 'web_video'), 'string' => 'video'),
201            'ra' => array('type' => 'audio/x-realaudio-plugin', 'icon' => 'audio',
202                    'groups' => array('audio', 'web_audio'), 'string' => 'audio'),
203            'ram' => array('type' => 'audio/x-pn-realaudio-plugin', 'icon' => 'audio',
204                    'groups' => array('audio'), 'string' => 'audio'),
205            'rar' => array('type' => 'application/x-rar-compressed', 'icon' => 'archive',
206                    'groups' => array('archive'), 'string' => 'archive'),
207            'rhb' => array('type' => 'text/xml', 'icon' => 'markup'),
208            'rm' => array('type' => 'audio/x-pn-realaudio-plugin', 'icon' => 'audio',
209                    'groups' => array('audio'), 'string' => 'audio'),
210            'rmvb' => array('type' => 'application/vnd.rn-realmedia-vbr', 'icon' => 'video',
211                    'groups' => array('video'), 'string' => 'video'),
212            'rtf' => array('type' => 'text/rtf', 'icon' => 'text', 'groups' => array('document')),
213            'rtx' => array('type' => 'text/richtext', 'icon' => 'text'),
214            'rv' => array('type' => 'audio/x-pn-realaudio-plugin', 'icon' => 'audio',
215                    'groups' => array('video'), 'string' => 'video'),
216            'sh' => array('type' => 'application/x-sh', 'icon' => 'sourcecode'),
217            'sit' => array('type' => 'application/x-stuffit', 'icon' => 'archive',
218                    'groups' => array('archive'), 'string' => 'archive'),
219            'smi' => array('type' => 'application/smil', 'icon' => 'text'),
220            'smil' => array('type' => 'application/smil', 'icon' => 'text'),
221            'sqt' => array('type' => 'text/xml', 'icon' => 'markup'),
222            'svg' => array('type' => 'image/svg+xml', 'icon' => 'image',
223                    'groups' => array('image', 'web_image'), 'string' => 'image'),
224            'svgz' => array('type' => 'image/svg+xml', 'icon' => 'image',
225                    'groups' => array('image', 'web_image'), 'string' => 'image'),
226            'swa' => array('type' => 'application/x-director', 'icon' => 'flash'),
227            'swf' => array('type' => 'application/x-shockwave-flash', 'icon' => 'flash', 'groups' => array('video', 'web_video')),
228            'swfl' => array('type' => 'application/x-shockwave-flash', 'icon' => 'flash', 'groups' => array('video', 'web_video')),
229
230            'sxw' => array('type' => 'application/vnd.sun.xml.writer', 'icon' => 'writer'),
231            'stw' => array('type' => 'application/vnd.sun.xml.writer.template', 'icon' => 'writer'),
232            'sxc' => array('type' => 'application/vnd.sun.xml.calc', 'icon' => 'calc'),
233            'stc' => array('type' => 'application/vnd.sun.xml.calc.template', 'icon' => 'calc'),
234            'sxd' => array('type' => 'application/vnd.sun.xml.draw', 'icon' => 'draw'),
235            'std' => array('type' => 'application/vnd.sun.xml.draw.template', 'icon' => 'draw'),
236            'sxi' => array('type' => 'application/vnd.sun.xml.impress', 'icon' => 'impress'),
237            'sti' => array('type' => 'application/vnd.sun.xml.impress.template', 'icon' => 'impress'),
238            'sxg' => array('type' => 'application/vnd.sun.xml.writer.global', 'icon' => 'writer'),
239            'sxm' => array('type' => 'application/vnd.sun.xml.math', 'icon' => 'math'),
240
241            'tar' => array('type' => 'application/x-tar', 'icon' => 'archive', 'groups' => array('archive'), 'string' => 'archive'),
242            'tif' => array('type' => 'image/tiff', 'icon' => 'tiff', 'groups' => array('image'), 'string' => 'image'),
243            'tiff' => array('type' => 'image/tiff', 'icon' => 'tiff', 'groups' => array('image'), 'string' => 'image'),
244            'tex' => array('type' => 'application/x-tex', 'icon' => 'text'),
245            'texi' => array('type' => 'application/x-texinfo', 'icon' => 'text'),
246            'texinfo' => array('type' => 'application/x-texinfo', 'icon' => 'text'),
247            'tsv' => array('type' => 'text/tab-separated-values', 'icon' => 'text'),
248            'txt' => array('type' => 'text/plain', 'icon' => 'text', 'defaulticon' => true),
249            'wav' => array('type' => 'audio/wav', 'icon' => 'wav', 'groups' => array('audio'), 'string' => 'audio'),
250            'webm' => array('type' => 'video/webm', 'icon' => 'video', 'groups' => array('video'), 'string' => 'video'),
251            'wmv' => array('type' => 'video/x-ms-wmv', 'icon' => 'wmv', 'groups' => array('video'), 'string' => 'video'),
252            'asf' => array('type' => 'video/x-ms-asf', 'icon' => 'wmv', 'groups' => array('video'), 'string' => 'video'),
253            'wma' => array('type' => 'audio/x-ms-wma', 'icon' => 'audio', 'groups' => array('audio'), 'string' => 'audio'),
254
255            'xbk' => array('type' => 'application/x-smarttech-notebook', 'icon' => 'archive'),
256            'xdp' => array('type' => 'application/pdf', 'icon' => 'pdf'),
257            'xfd' => array('type' => 'application/pdf', 'icon' => 'pdf'),
258            'xfdf' => array('type' => 'application/pdf', 'icon' => 'pdf'),
259
260            'xls' => array('type' => 'application/vnd.ms-excel', 'icon' => 'spreadsheet', 'groups' => array('spreadsheet')),
261            'xlsx' => array('type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'icon' => 'spreadsheet'),
262            'xlsm' => array('type' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
263                    'icon' => 'spreadsheet', 'groups' => array('spreadsheet')),
264            'xltx' => array('type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
265                    'icon' => 'spreadsheet'),
266            'xltm' => array('type' => 'application/vnd.ms-excel.template.macroEnabled.12', 'icon' => 'spreadsheet'),
267            'xlsb' => array('type' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', 'icon' => 'spreadsheet'),
268            'xlam' => array('type' => 'application/vnd.ms-excel.addin.macroEnabled.12', 'icon' => 'spreadsheet'),
269
270            'xml' => array('type' => 'application/xml', 'icon' => 'markup'),
271            'xsl' => array('type' => 'text/xml', 'icon' => 'markup'),
272
273            'zip' => array('type' => 'application/zip', 'icon' => 'archive', 'groups' => array('archive'), 'string' => 'archive')
274        );
275    }
276
277    /**
278     * Gets all the current types.
279     *
280     * @return array Associative array from extension to array of data about type
281     */
282    public static function &get_types() {
283        // If it was already done in this request, use cache.
284        if (self::$cachedtypes) {
285            return self::$cachedtypes;
286        }
287
288        // Get defaults.
289        $mimetypes = self::get_default_types();
290
291        // If there are no custom types, just return.
292        $custom = self::get_custom_types();
293        if (empty($custom)) {
294            return $mimetypes;
295        }
296
297        // Check value is an array.
298        if (!is_array($custom)) {
299            debugging('Invalid $CFG->customfiletypes (not array)', DEBUG_DEVELOPER);
300            return $mimetypes;
301        }
302
303        foreach ($custom as $customentry) {
304            // Each entry is a stdClass object similar to the array values above.
305            if (empty($customentry->extension)) {
306                debugging('Invalid $CFG->customfiletypes entry (extension field required)',
307                        DEBUG_DEVELOPER);
308                continue;
309            }
310
311            // To delete a standard entry, set 'deleted' to true.
312            if (!empty($customentry->deleted)) {
313                unset($mimetypes[$customentry->extension]);
314                continue;
315            }
316
317            // Check required fields.
318            if (empty($customentry->type) || empty($customentry->icon)) {
319                debugging('Invalid $CFG->customfiletypes entry ' . $customentry->extension .
320                        ' (type and icon fields required)', DEBUG_DEVELOPER);
321                continue;
322            }
323
324            // Build result array.
325            $result = array('type' => $customentry->type, 'icon' => $customentry->icon);
326            if (!empty($customentry->groups)) {
327                if (!is_array($customentry->groups)) {
328                    debugging('Invalid $CFG->customfiletypes entry ' . $customentry->extension .
329                            ' (groups field not array)', DEBUG_DEVELOPER);
330                    continue;
331                }
332                $result['groups'] = $customentry->groups;
333            }
334            if (!empty($customentry->string)) {
335                if (!is_string($customentry->string)) {
336                    debugging('Invalid $CFG->customfiletypes entry ' . $customentry->extension .
337                            ' (string field not string)', DEBUG_DEVELOPER);
338                    continue;
339                }
340                $result['string'] = $customentry->string;
341            }
342            if (!empty($customentry->defaulticon)) {
343                if (!is_bool($customentry->defaulticon)) {
344                    debugging('Invalid $CFG->customfiletypes entry ' . $customentry->extension .
345                            ' (defaulticon field not bool)', DEBUG_DEVELOPER);
346                    continue;
347                }
348                $result['defaulticon'] = $customentry->defaulticon;
349            }
350            if (!empty($customentry->customdescription)) {
351                if (!is_string($customentry->customdescription)) {
352                    debugging('Invalid $CFG->customfiletypes entry ' . $customentry->extension .
353                            ' (customdescription field not string)', DEBUG_DEVELOPER);
354                    continue;
355                }
356                // As the name suggests, this field is used only for custom entries.
357                $result['customdescription'] = $customentry->customdescription;
358            }
359
360            // Track whether it is a custom filetype or a modified existing
361            // filetype.
362            if (array_key_exists($customentry->extension, $mimetypes)) {
363                $result['modified'] = true;
364            } else {
365                $result['custom'] = true;
366            }
367
368            // Add result array to list.
369            $mimetypes[$customentry->extension] = $result;
370        }
371
372        self::$cachedtypes = $mimetypes;
373        return self::$cachedtypes;
374    }
375
376    /**
377     * Gets custom types from config variable, after decoding the JSON if required.
378     *
379     * @return array Array of custom types (empty array if none)
380     */
381    protected static function get_custom_types() {
382        global $CFG;
383        if (!empty($CFG->customfiletypes)) {
384            if (is_array($CFG->customfiletypes)) {
385                // You can define this as an array in config.php...
386                return $CFG->customfiletypes;
387            } else {
388                // Or as a JSON string in the config table.
389                return json_decode($CFG->customfiletypes);
390            }
391        } else {
392            return array();
393        }
394    }
395
396    /**
397     * Sets the custom types into config variable, encoding into JSON.
398     *
399     * @param array $types Array of custom types
400     * @throws coding_exception If the custom types are fixed in config.php.
401     */
402    protected static function set_custom_types(array $types) {
403        global $CFG;
404        // Check the setting hasn't been forced.
405        if (array_key_exists('customfiletypes', $CFG->config_php_settings)) {
406            throw new coding_exception('Cannot set custom filetypes because they ' .
407                    'are defined in config.php');
408        }
409        if (empty($types)) {
410            unset_config('customfiletypes');
411        } else {
412            set_config('customfiletypes', json_encode(array_values($types)));
413        }
414
415        // Clear the cached type list.
416        self::reset_caches();
417    }
418
419    /**
420     * Clears the type cache. This is not needed in normal use as the
421     * set_custom_types function automatically clears the cache. Intended for
422     * use in unit tests.
423     */
424    public static function reset_caches() {
425        self::$cachedtypes = null;
426    }
427
428    /**
429     * Gets the default types that have been deleted. Returns an array containing
430     * the defaults of all those types.
431     *
432     * @return array Array (same format as get_mimetypes_array)
433     */
434    public static function get_deleted_types() {
435        $defaults = self::get_default_types();
436        $deleted = array();
437        foreach (self::get_custom_types() as $customentry) {
438            if (!empty($customentry->deleted)) {
439                $deleted[$customentry->extension] = $defaults[$customentry->extension];
440            }
441        }
442        return $deleted;
443    }
444
445    /**
446     * Adds a new entry to the list of custom filetypes.
447     *
448     * @param string $extension File extension without dot, e.g. 'doc'
449     * @param string $mimetype MIME type e.g. 'application/msword'
450     * @param string $coreicon Core icon to use e.g. 'document'
451     * @param array $groups Array of group strings that this type belongs to
452     * @param string $corestring Custom lang string name in mimetypes.php
453     * @param string $customdescription Custom description (plain text/multilang)
454     * @param bool $defaulticon True if this should be the default icon for the type
455     * @throws coding_exception If the extension already exists, or otherwise invalid
456     */
457    public static function add_type($extension, $mimetype, $coreicon,
458            array $groups = array(), $corestring = '', $customdescription = '',
459            $defaulticon = false) {
460        // Check for blank extensions or incorrectly including the dot.
461        $extension = (string)$extension;
462        if ($extension === '' || $extension[0] === '.') {
463            throw new coding_exception('Invalid extension .' . $extension);
464        }
465
466        // Check extension not already used.
467        $mimetypes = get_mimetypes_array();
468        if (array_key_exists($extension, $mimetypes)) {
469            throw new coding_exception('Extension ' . $extension . ' already exists');
470        }
471
472        // For default icon, check there isn't already something with default icon
473        // set for that MIME type.
474        if ($defaulticon) {
475            foreach ($mimetypes as $type) {
476                if ($type['type'] === $mimetype && !empty($type['defaulticon'])) {
477                    throw new coding_exception('MIME type ' . $mimetype .
478                            ' already has a default icon set');
479                }
480            }
481        }
482
483        // Get existing custom filetype list.
484        $customs = self::get_custom_types();
485
486        // Check if there's a 'deleted' entry for the extension, if so then get
487        // rid of it.
488        foreach ($customs as $key => $custom) {
489            if ($custom->extension === $extension) {
490                unset($customs[$key]);
491            }
492        }
493
494        // Set up config record for new type.
495        $newtype = self::create_config_record($extension, $mimetype, $coreicon, $groups,
496                $corestring, $customdescription, $defaulticon);
497
498        // See if there's a default value with this extension.
499        $needsadding = true;
500        $defaults = self::get_default_types();
501        if (array_key_exists($extension, $defaults)) {
502            // If it has the same values, we don't need to add it.
503            $defaultvalue = $defaults[$extension];
504            $modified = (array)$newtype;
505            unset($modified['extension']);
506            ksort($defaultvalue);
507            ksort($modified);
508            if ($modified === $defaultvalue) {
509                $needsadding = false;
510            }
511        }
512
513        // Add to array and set in config.
514        if ($needsadding) {
515            $customs[] = $newtype;
516        }
517        self::set_custom_types($customs);
518    }
519
520    /**
521     * Updates an entry in the list of filetypes in config.
522     *
523     * @param string $extension File extension without dot, e.g. 'doc'
524     * @param string $newextension New file extension (same if not changing)
525     * @param string $mimetype MIME type e.g. 'application/msword'
526     * @param string $coreicon Core icon to use e.g. 'document'
527     * @param array $groups Array of group strings that this type belongs to
528     * @param string $corestring Custom lang string name in mimetypes.php
529     * @param string $customdescription Custom description (plain text/multilang)
530     * @param bool $defaulticon True if this should be the default icon for the type
531     * @throws coding_exception If the new extension already exists, or otherwise invalid
532     */
533    public static function update_type($extension, $newextension, $mimetype, $coreicon,
534            array $groups = array(), $corestring = '', $customdescription = '',
535            $defaulticon = false) {
536
537        // Extension must exist.
538        $extension = (string)$extension;
539        $mimetypes = get_mimetypes_array();
540        if (!array_key_exists($extension, $mimetypes)) {
541            throw new coding_exception('Extension ' . $extension . ' not found');
542        }
543
544        // If there's a new extension then this must not exist.
545        $newextension = (string)$newextension;
546        if ($newextension !== $extension) {
547            if ($newextension === '' || $newextension[0] === '.') {
548                throw new coding_exception('Invalid extension .' . $newextension);
549            }
550            if (array_key_exists($newextension, $mimetypes)) {
551                throw new coding_exception('Extension ' . $newextension . ' already exists');
552            }
553        }
554
555        // For default icon, check there isn't already something with default icon
556        // set for that MIME type (unless it's this).
557        if ($defaulticon) {
558            foreach ($mimetypes as $ext => $type) {
559                if ($ext !== $extension && $type['type'] === $mimetype &&
560                        !empty($type['defaulticon'])) {
561                    throw new coding_exception('MIME type ' . $mimetype .
562                            ' already has a default icon set');
563                }
564            }
565        }
566
567        // Delete the old extension and then add the new one (may be same). This
568        // will correctly handle cases when a default type is involved.
569        self::delete_type($extension);
570        self::add_type($newextension, $mimetype, $coreicon, $groups, $corestring,
571                $customdescription, $defaulticon);
572    }
573
574    /**
575     * Deletes a file type from the config list (or, for a standard one, marks it
576     * as deleted).
577     *
578     * @param string $extension File extension without dot, e.g. 'doc'
579     * @throws coding_exception If the extension does not exist, or otherwise invalid
580     */
581    public static function delete_type($extension) {
582        // Extension must exist.
583        $mimetypes = get_mimetypes_array();
584        if (!array_key_exists($extension, $mimetypes)) {
585            throw new coding_exception('Extension ' . $extension . ' not found');
586        }
587
588        // Get existing custom filetype list.
589        $customs = self::get_custom_types();
590
591        // Remove any entries for this extension.
592        foreach ($customs as $key => $custom) {
593            if ($custom->extension === $extension && empty($custom->deleted)) {
594                unset($customs[$key]);
595            }
596        }
597
598        // If it was a standard entry (doesn't have 'custom' set) then add a
599        // deleted marker.
600        if (empty($mimetypes[$extension]['custom'])) {
601            $customs[] = (object)array('extension' => $extension, 'deleted' => true);
602        }
603
604        // Save and reset cache.
605        self::set_custom_types($customs);
606    }
607
608    /**
609     * Reverts a file type to the default. May only be called on types that have
610     * default values. This will undelete the type if necessary or set its values.
611     * If the type is already at default values, does nothing.
612     *
613     * @param string $extension File extension without dot, e.g. 'doc'
614     * @return bool True if anything was changed, false if it was already default
615     * @throws coding_exception If the extension is not a default type.
616     */
617    public static function revert_type_to_default($extension) {
618        $extension = (string)$extension;
619
620        // Check it actually is a default type.
621        $defaults = self::get_default_types();
622        if (!array_key_exists($extension, $defaults)) {
623            throw new coding_exception('Extension ' . $extension . ' is not a default type');
624        }
625
626        // Loop through all the custom settings.
627        $changed = false;
628        $customs = self::get_custom_types();
629        foreach ($customs as $key => $customentry) {
630            if ($customentry->extension === $extension) {
631                unset($customs[$key]);
632                $changed = true;
633            }
634        }
635
636        // Save changes if any.
637        if ($changed) {
638            self::set_custom_types($customs);
639        }
640        return $changed;
641    }
642
643    /**
644     * Converts function parameters into a record for storing in the JSON value.
645     *
646     * @param string $extension File extension without dot, e.g. 'doc'
647     * @param string $mimetype MIME type e.g. 'application/msword'
648     * @param string $coreicon Core icon to use e.g. 'document'
649     * @param array $groups Array of group strings that this type belongs to
650     * @param string $corestring Custom lang string name in mimetypes.php
651     * @param string $customdescription Custom description (plain text/multilang)
652     * @param bool $defaulticon True if this should be the default icon for the type
653     * @return stdClass Record matching the parameters
654     */
655    protected static function create_config_record($extension, $mimetype,
656            $coreicon, array $groups, $corestring, $customdescription, $defaulticon) {
657        // Construct new entry.
658        $newentry = (object)array('extension' => (string)$extension, 'type' => (string)$mimetype,
659                'icon' => (string)$coreicon);
660        if ($groups) {
661            if (!is_array($groups)) {
662                throw new coding_exception('Groups must be an array');
663            }
664            foreach ($groups as $group) {
665                if (!is_string($group)) {
666                    throw new coding_exception('Groups must be an array of strings');
667                }
668            }
669            $newentry->groups = $groups;
670        }
671        if ($corestring) {
672            $newentry->string = (string)$corestring;
673        }
674        if ($customdescription) {
675            $newentry->customdescription = (string)$customdescription;
676        }
677        if ($defaulticon) {
678            $newentry->defaulticon = true;
679        }
680        return $newentry;
681    }
682}
Note: See TracBrowser for help on using the repository browser.