MDL-23984 using standard checkdirexists for lang packs
[moodle.git] / admin / langimport.php
CommitLineData
20207b82 1<?php
6e113a15 2
a9e41d3e
DM
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
18/**
19 * Fetches language packages from download.moodle.org server
20 *
21 * Language packages are available at http://download.moodle.org/langpack/2.0/
22 * in ZIP format together with a file languages.md5 containing thir hashes
23 * and meta info.
24 * Locally, language packs are saved into $CFG->dataroot/lang/
25 *
26 * @package core
27 * @copyright 2005 Yu Zhang
28 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 */
30
31require_once(dirname(dirname(__FILE__)).'/config.php');
32require_once($CFG->libdir.'/adminlib.php');
33require_once($CFG->libdir.'/filelib.php');
34require_once($CFG->libdir.'/componentlib.class.php');
35
36$thisversion = '2.0'; // TODO this information should be taken from version.php or similar source
37
38admin_externalpage_setup('langimport');
39
40if (!empty($CFG->skiplangupgrade)) {
41 echo $OUTPUT->header();
42 echo $OUTPUT->box(get_string('langimportdisabled', 'admin'));
43 echo $OUTPUT->footer();
44 die;
45}
46
47$mode = optional_param('mode', 0, PARAM_INT); // action
48$pack = optional_param('pack', array(), PARAM_SAFEDIR); // pack to install
49$uninstalllang = optional_param('uninstalllang', '', PARAM_LANG); // installed pack to uninstall
50$confirm = optional_param('confirm', 0, PARAM_BOOL); // uninstallation confirmation
51
52define('INSTALLATION_OF_SELECTED_LANG', 2);
53define('DELETION_OF_SELECTED_LANG', 4);
54define('UPDATE_ALL_LANG', 5);
55
56//reset and diagnose lang cache permissions
57remove_dir($CFG->dataroot.'/cache/languages');
58if (file_exists($CFG->dataroot.'/cache/languages')) {
59 print_error('cannotdeletelangcache', 'error');
60}
61get_string_manager()->reset_caches();
62
63$notice_ok = array();
64$notice_error = array();
65
66if (($mode == INSTALLATION_OF_SELECTED_LANG) and confirm_sesskey() and !empty($pack)) {
67 set_time_limit(0);
d8fa4550
PS
68 check_dir_exists($CFG->dataroot.'/temp/');
69 check_dir_exists($CFG->dataroot.'/lang/');
a9e41d3e
DM
70
71 if (is_array($pack)) {
72 $packs = $pack;
73 } else {
74 $packs = array($pack);
0a5ce9dd 75 }
d6d04971 76
a9e41d3e
DM
77 foreach ($packs as $pack) {
78 if ($cd = new component_installer('http://download.moodle.org', 'langpack/'.$thisversion, $pack.'.zip', 'languages.md5', 'lang')) {
79 $status = $cd->install();
80 switch ($status) {
81 case COMPONENT_ERROR:
82 if ($cd->get_error() == 'remotedownloaderror') {
83 $a = new object();
84 $a->url = 'http://download.moodle.org/langpack/'.$thisversion.'/'.$pack.'.zip';
85 $a->dest = $CFG->dataroot.'/lang';
86 print_error($cd->get_error(), 'error', 'langimport.php', $a);
7b7b8b36 87 } else {
a9e41d3e 88 print_error($cd->get_error(), 'error', 'langimport.php');
7b7b8b36 89 }
a9e41d3e
DM
90 break;
91 case COMPONENT_INSTALLED:
92 $notice_ok[] = get_string('langpackinstalled','admin',$pack);
93 if ($parentlang = get_parent_language($pack)) {
94 // install also parent pack if specified
95 if ($cd = new component_installer('http://download.moodle.org', 'langpack/'.$thisversion,
96 $parentlang.'.zip', 'languages.md5', 'lang')) {
97 $cd->install();
6e113a15 98 }
99 }
a9e41d3e
DM
100 break;
101 case COMPONENT_UPTODATE:
102 break;
6e113a15 103 }
a9e41d3e
DM
104 } else {
105 echo $OUTPUT->notification('Had an unspecified error with the component installer, sorry.');
106 }
107 }
108}
6e113a15 109
a9e41d3e
DM
110if ($mode == DELETION_OF_SELECTED_LANG and !empty($uninstalllang)) {
111 if ($uninstalllang == 'en') {
112 $notice_error[] = 'English language pack can not be uninstalled';
d6d04971 113
a9e41d3e
DM
114 } else if (!$confirm and confirm_sesskey()) {
115 echo $OUTPUT->header();
116 echo $OUTPUT->confirm(get_string('uninstallconfirm', 'admin', $uninstalllang),
117 'langimport.php?mode='.DELETION_OF_SELECTED_LANG.'&uninstalllang='.$uninstalllang.'&confirm=1',
118 'langimport.php');
119 echo $OUTPUT->footer();
120 die;
6e113a15 121
a9e41d3e
DM
122 } else if (confirm_sesskey()) {
123 $dest1 = $CFG->dataroot.'/lang/'.$uninstalllang;
124 $dest2 = $CFG->dirroot.'/lang/'.$uninstalllang;
125 $rm1 = false;
126 $rm2 = false;
127 if (file_exists($dest1)){
128 $rm1 = remove_dir($dest1);
129 }
130 if (file_exists($dest2)){
131 $rm2 = remove_dir($dest2);
132 }
133 if ($rm1 or $rm2) {
134 $notice_ok[] = get_string('langpackremoved','admin');
135 } else { //nothing deleted, possibly due to permission error
136 $notice_error[] = 'An error has occurred, language pack is not completely uninstalled, please check file permissions';
137 }
138 }
139}
6e113a15 140
a9e41d3e
DM
141if ($mode == UPDATE_ALL_LANG) {
142 set_time_limit(0);
d6d04971 143
a9e41d3e
DM
144 if (!$availablelangs = get_remote_list_of_languages()) {
145 print_error('cannotdownloadlanguageupdatelist', 'error');
146 }
147 $md5array = array(); // (string)langcode => (string)md5
148 foreach ($availablelangs as $alang) {
149 $md5array[$alang[0]] = $alang[1];
150 }
7b7b8b36 151
a9e41d3e
DM
152 // filter out unofficial packs
153 $currentlangs = array_keys(get_string_manager()->get_list_of_translations(true));
154 $updateablelangs = array();
155 foreach ($currentlangs as $clang) {
156 if (!array_key_exists($clang, $md5array)) {
157 $notice_ok[] = get_string('langpackupdateskipped', 'admin', $clang);
7b7b8b36 158 continue;
159 }
a9e41d3e
DM
160 $dest1 = $CFG->dataroot.'/lang/'.$clang;
161 $dest2 = $CFG->dirroot.'/lang/'.$clang;
7b7b8b36 162
a9e41d3e
DM
163 if (file_exists($dest1.'/langconfig.php') || file_exists($dest2.'/langconfig.php')){
164 $updateablelangs[] = $clang;
165 }
a7d43f0d 166 }
6e113a15 167
a9e41d3e
DM
168 // then filter out packs that have the same md5 key
169 $neededlangs = array(); // all the packs that needs updating
170 foreach ($updateablelangs as $ulang) {
171 if (!is_installed_lang($ulang, $md5array[$ulang])) {
172 $neededlangs[] = $ulang;
173 }
a7d43f0d 174 }
6e113a15 175
d8fa4550
PS
176 check_dir_exists($CFG->dataroot.'/temp/');
177 check_dir_exists($CFG->dataroot.'/lang/');
178
a9e41d3e
DM
179 $updated = false; // any packs updated?
180 foreach ($neededlangs as $pack) {
181 if ($pack == 'en') {
182 continue;
183 }
6e113a15 184
a9e41d3e
DM
185 // delete old directories
186 $dest1 = $CFG->dataroot.'/lang/'.$pack;
187 $dest2 = $CFG->dirroot.'/lang/'.$pack;
188 $rm1 = false;
189 $rm2 = false;
190 if (file_exists($dest1)) {
191 if (!remove_dir($dest1)) {
192 $notice_error[] = 'Could not delete old directory '.$dest1.', update of '.$pack.' failed, please check permissions.';
193 continue;
194 }
195 }
196 if (file_exists($dest2)) {
197 if (!remove_dir($dest2)) {
198 $notice_error[] = 'Could not delete old directory '.$dest2.', update of '.$pack.' failed, please check permissions.';
199 continue;
200 }
201 }
a7d43f0d 202
a9e41d3e
DM
203 // copy and unzip new version
204 if ($cd = new component_installer('http://download.moodle.org', 'langpack/'.$thisversion, $pack.'.zip', 'languages.md5', 'lang')) {
205 $status = $cd->install();
206 switch ($status) {
207
208 case COMPONENT_ERROR:
209 if ($cd->get_error() == 'remotedownloaderror') {
210 $a = new stdClass();
211 $a->url = 'http://download.moodle.org/langpack/'.$thisversion.'/'.$pack.'.zip';
212 $a->dest = $CFG->dataroot.'/lang';
213 print_error($cd->get_error(), 'error', 'langimport.php', $a);
214 } else {
215 print_error($cd->get_error(), 'error', 'langimport.php');
7b7b8b36 216 }
a9e41d3e
DM
217 break;
218
219 case COMPONENT_UPTODATE:
220 // should not get here
221 break;
222
223 case COMPONENT_INSTALLED:
224 $notice_ok[] = get_string('langpackupdated', 'admin', $pack);
225 $updated = true;
226 break;
7b7b8b36 227 }
7b7b8b36 228 }
229 }
230
a9e41d3e
DM
231 if ($updated) {
232 $notice_ok[] = get_string('langupdatecomplete','admin');
233 } else {
234 $notice_ok[] = get_string('nolangupdateneeded','admin');
a7d43f0d 235 }
a9e41d3e
DM
236}
237get_string_manager()->reset_caches();
a7d43f0d 238
a9e41d3e
DM
239echo $OUTPUT->header();
240echo $OUTPUT->heading(get_string('langimport', 'admin'));
a7d43f0d 241
a9e41d3e 242$installedlangs = get_string_manager()->get_list_of_translations(true);
a7d43f0d 243
a9e41d3e 244$missingparents = array();
af8d4d91
DM
245foreach ($installedlangs as $installedlang => $unused) {
246 $parent = get_parent_language($installedlang);
a9e41d3e
DM
247 if (empty($parent) or ($parent === 'en')) {
248 continue;
a7d43f0d 249 }
a9e41d3e 250 if (!isset($installedlangs[$parent])) {
af8d4d91 251 $missingparents[$installedlang] = $parent;
a9e41d3e
DM
252 }
253}
a9e41d3e
DM
254
255if ($availablelangs = get_remote_list_of_languages()) {
256 $remote = true;
257} else {
258 $remote = false;
259 $availablelangs = array();
260 echo $OUTPUT->box_start();
261 print_string('remotelangnotavailable', 'admin', $CFG->dataroot.'/lang/');
262 echo $OUTPUT->box_end();
263}
264
265if ($notice_ok) {
266 $info = implode('<br />', $notice_ok);
267 echo $OUTPUT->notification($info, 'notifysuccess');
268}
269
270if ($notice_error) {
271 $info = implode('<br />', $notice_error);
272 echo $OUTPUT->notification($info, 'notifyproblem');
273}
274
275if ($missingparents) {
276 foreach ($missingparents as $l=>$parent) {
277 $a = new object();
278 $a->lang = $installedlangs[$l];
279 $a->parent = $parent;
280 foreach ($availablelangs as $alang) {
281 if ($alang[0] == $parent) {
3a915b06 282 $shortlang = $alang[0];
a9e41d3e 283 $a->parent = $alang[2].' ('.$shortlang.')';
6e113a15 284 }
a7d43f0d 285 }
a9e41d3e
DM
286 $info = get_string('missinglangparent', 'admin', $a);
287 echo $OUTPUT->notification($info, 'notifyproblem');
a7d43f0d 288 }
a9e41d3e
DM
289}
290
291echo $OUTPUT->box_start();
292
293echo html_writer::start_tag('table');
294echo html_writer::start_tag('tr');
295
296// list of installed languages
297$url = new moodle_url('/admin/langimport.php', array('mode' => DELETION_OF_SELECTED_LANG));
298echo html_writer::start_tag('td', array('valign' => 'top'));
299echo html_writer::start_tag('form', array('id' => 'uninstallform', 'action' => $url->out(), 'method' => 'post'));
300echo html_writer::start_tag('fieldset');
995f2d51 301echo html_writer::label(get_string('installedlangs','admin'), 'uninstalllang');
a9e41d3e
DM
302echo html_writer::empty_tag('br');
303echo html_writer::select($installedlangs, 'uninstalllang', '', false, array('size' => 15));
304echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
305echo html_writer::empty_tag('br');
306echo html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('uninstall','admin')));
307echo html_writer::end_tag('fieldset');
308echo html_writer::end_tag('form');
309if ($remote) {
310 $url = new moodle_url('/admin/langimport.php', array('mode' => UPDATE_ALL_LANG));
311 echo html_writer::start_tag('form', array('id' => 'updateform', 'action' => $url->out(), 'method' => 'post'));
312 echo html_writer::tag('fieldset', html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('updatelangs','admin'))));
313 echo html_writer::end_tag('form');
314}
315echo html_writer::end_tag('td');
316
317// list of available languages
318$options = array();
319foreach ($availablelangs as $alang) {
320 if (!empty($alang[0]) and trim($alang[0]) !== 'en' and !is_installed_lang($alang[0], $alang[1])) {
321 $options[$alang[0]] = $alang[2].' ('.$alang[0].')';
a7d43f0d 322 }
a9e41d3e
DM
323}
324if (!empty($options)) {
325 echo html_writer::start_tag('td', array('valign' => 'top'));
326 $url = new moodle_url('/admin/langimport.php', array('mode' => INSTALLATION_OF_SELECTED_LANG));
327 echo html_writer::start_tag('form', array('id' => 'installform', 'action' => $url->out(), 'method' => 'post'));
328 echo html_writer::start_tag('fieldset');
995f2d51 329 echo html_writer::label(get_string('availablelangs','install'), 'pack');
a9e41d3e
DM
330 echo html_writer::empty_tag('br');
331 echo html_writer::select($options, 'pack[]', '', false, array('size' => 15, 'multiple' => 'multiple'));
332 echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
333 echo html_writer::empty_tag('br');
334 echo html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('install','admin')));
335 echo html_writer::end_tag('fieldset');
336 echo html_writer::end_tag('form');
337 echo html_writer::end_tag('td');
338}
339
340echo html_writer::end_tag('tr');
341echo html_writer::end_tag('table');
342echo $OUTPUT->box_end();
343echo $OUTPUT->footer();
344die();
345
346////////////////////////////////////////////////////////////////////////////////
347// Local functions /////////////////////////////////////////////////////////////
348////////////////////////////////////////////////////////////////////////////////
349
350/**
351 * checks the md5 of the zip file, grabbed from download.moodle.org,
352 * against the md5 of the local language file from last update
353 * @param string $lang
354 * @param string $md5check
355 * @return bool
356 */
357function is_installed_lang($lang, $md5check) {
358 global $CFG;
359 $md5file = $CFG->dataroot.'/lang/'.$lang.'/'.$lang.'.md5';
360 if (file_exists($md5file)){
361 return (file_get_contents($md5file) == $md5check);
a7d43f0d 362 }
a9e41d3e
DM
363 return false;
364}
365
366/**
367 * Returns the list of available language packs from download.moodle.org
368 *
369 * @return array|bool false if can not download
370 */
371function get_remote_list_of_languages() {
372 $source = 'http://download.moodle.org/langpack/2.0/languages.md5';
373 $availablelangs = array();
374
375 if ($content = download_file_content($source)) {
c71f3265 376 $alllines = explode("\n", $content);
a9e41d3e
DM
377 foreach($alllines as $line) {
378 if (!empty($line)){
c71f3265 379 $availablelangs[] = explode(',', $line);
6e113a15 380 }
381 }
382 return $availablelangs;
d6d04971 383
a9e41d3e 384 } else {
6e113a15 385 return false;
386 }
a9e41d3e 387}