source: trunk/admin/include/languages.class.php @ 10594

Last change on this file since 10594 was 10594, checked in by patdenice, 13 years ago

Change tabsheet place for plugins, themes and languages.
Plugins, themes and languages use same update page.

  • Property svn:eol-style set to LF
File size: 13.6 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2011 Piwigo Team                  http://piwigo.org |
6// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
7// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
8// +-----------------------------------------------------------------------+
9// | This program is free software; you can redistribute it and/or modify  |
10// | it under the terms of the GNU General Public License as published by  |
11// | the Free Software Foundation                                          |
12// |                                                                       |
13// | This program is distributed in the hope that it will be useful, but   |
14// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
15// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
16// | General Public License for more details.                              |
17// |                                                                       |
18// | You should have received a copy of the GNU General Public License     |
19// | along with this program; if not, write to the Free Software           |
20// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
21// | USA.                                                                  |
22// +-----------------------------------------------------------------------+
23
24class languages
25{
26  var $fs_languages = array();
27  var $db_languages = array();
28  var $server_languages = array();
29
30  /**
31   * Initialize $fs_languages and $db_languages
32  */
33  function languages($target_charset = null)
34  {
35    $this->get_fs_languages($target_charset);
36  }
37
38  /**
39   * Perform requested actions
40   * @param string - action
41   * @param string - language id
42   * @param array - errors
43   */
44  function perform_action($action, $language_id)
45  {
46    global $conf;
47
48    if (isset($this->db_languages[$language_id]))
49    {
50      $crt_db_language = $this->db_languages[$language_id];
51    }
52
53    $errors = array();
54
55    switch ($action)
56    {
57      case 'activate':
58        if (isset($crt_db_language))
59        {
60          array_push($errors, 'CANNOT ACTIVATE - LANGUAGE IS ALREADY ACTIVATED');
61          break;
62        }
63
64        $query = '
65INSERT INTO '.LANGUAGES_TABLE.'
66  (id, version, name)
67  VALUES(\''.$language_id.'\',
68         \''.$this->fs_languages[$language_id]['version'].'\',
69         \''.$this->fs_languages[$language_id]['name'].'\')
70;';
71        pwg_query($query);
72        break;
73
74      case 'deactivate':
75        if (!isset($crt_db_language))
76        {
77          array_push($errors, 'CANNOT DEACTIVATE - LANGUAGE IS ALREADY DEACTIVATED');
78          break;
79        }
80
81        if ($language_id == get_default_language())
82        {
83          array_push($errors, 'CANNOT DEACTIVATE - LANGUAGE IS DEFAULT LANGUAGE');
84          break;
85        }
86
87        $query = '
88DELETE
89  FROM '.LANGUAGES_TABLE.'
90  WHERE id= \''.$language_id.'\'
91;';
92        pwg_query($query);
93        break;
94
95      case 'delete':
96        if (!empty($crt_db_language))
97        {
98          array_push($errors, 'CANNOT DELETE - LANGUAGE IS ACTIVATED');
99          break;
100        }
101        if (!isset($this->fs_languages[$language_id]))
102        {
103          array_push($errors, 'CANNOT DELETE - LANGUAGE DOES NOT EXIST');
104          break;
105        }
106
107        // Set default language to user who are using this language
108        $query = '
109UPDATE '.USER_INFOS_TABLE.'
110  SET language = \''.get_default_language().'\'
111  WHERE language = \''.$language_id.'\'
112;';
113        pwg_query($query);
114
115        if (!$this->deltree(PHPWG_ROOT_PATH.'language/'.$language_id))
116        {
117          $this->send_to_trash(PHPWG_ROOT_PATH.'language/'.$language_id);
118        }
119        break;
120
121      case 'set_default':
122        $query = '
123UPDATE '.USER_INFOS_TABLE.'
124  SET language = \''.$language_id.'\'
125  WHERE user_id IN ('.$conf['default_user_id'].', '.$conf['guest_id'].')
126;';
127        pwg_query($query);
128        break;
129    }
130    return $errors;
131  }
132
133  /**
134  *  Get languages defined in the language directory
135  */
136  function get_fs_languages($target_charset = null)
137  {
138    if ( empty($target_charset) )
139    {
140      $target_charset = get_pwg_charset();
141    }
142    $target_charset = strtolower($target_charset);
143
144    $dir = opendir(PHPWG_ROOT_PATH.'language');
145    while ($file = readdir($dir))
146    {
147      if ($file!='.' and $file!='..')
148      {
149        $path = PHPWG_ROOT_PATH.'language/'.$file;
150        if (is_dir($path) and !is_link($path)
151            and preg_match('/^[a-zA-Z0-9-_]+$/', $file )
152            and file_exists($path.'/common.lang.php')
153            )
154        {
155          $language = array(
156              'name'=>$file,
157              'code'=>$file,
158              'version'=>'0',
159              'uri'=>'',
160              'author'=>'',
161            );
162          $plg_data = implode( '', file($path.'/common.lang.php') );
163
164          if ( preg_match("|Language Name: (.*)|", $plg_data, $val) )
165          {
166            $language['name'] = trim( $val[1] );
167            $language['name'] = convert_charset($language['name'], 'utf-8', $target_charset);
168          }
169          if (preg_match("|Version: (.*)|", $plg_data, $val))
170          {
171            $language['version'] = trim($val[1]);
172          }
173          if ( preg_match("|Language URI: (.*)|", $plg_data, $val) )
174          {
175            $language['uri'] = trim($val[1]);
176          }
177          if ( preg_match("|Author: (.*)|", $plg_data, $val) )
178          {
179            $language['author'] = trim($val[1]);
180          }
181          if ( preg_match("|Author URI: (.*)|", $plg_data, $val) )
182          {
183            $language['author uri'] = trim($val[1]);
184          }
185          if (!empty($language['uri']) and strpos($language['uri'] , 'extension_view.php?eid='))
186          {
187            list( , $extension) = explode('extension_view.php?eid=', $language['uri']);
188            if (is_numeric($extension)) $language['extension'] = $extension;
189          }
190          // IMPORTANT SECURITY !
191          $language = array_map('htmlspecialchars', $language);
192          $this->fs_languages[$file] = $language;
193        }
194      }
195    }
196    closedir($dir);
197    @uasort($this->fs_languages, 'name_compare');
198  }
199
200  function get_db_languages()
201  {
202    $query = '
203  SELECT id, name
204    FROM '.LANGUAGES_TABLE.'
205    ORDER BY name ASC
206  ;';
207    $result = pwg_query($query);
208
209    while ($row = pwg_db_fetch_assoc($result))
210    {
211      $this->db_languages[ $row['id'] ] = $row['name'];
212    }
213  }
214
215  /**
216   * Retrieve PEM server datas to $server_languages
217   */
218  function get_server_languages($new=false)
219  {
220    global $user;
221
222    $get_data = array(
223      'category_id' => 8,
224      'format' => 'php',
225    );
226
227    // Retrieve PEM versions
228    $version = PHPWG_VERSION;
229    $versions_to_check = array();
230    $url = PEM_URL . '/api/get_version_list.php';
231    if (fetchRemote($url, $result, $get_data) and $pem_versions = @unserialize($result))
232    {
233      if (!preg_match('/^\d+\.\d+\.\d+/', $version))
234      {
235        $version = $pem_versions[0]['name'];
236      }
237      $branch = substr($version, 0, strrpos($version, '.'));
238      foreach ($pem_versions as $pem_version)
239      {
240        if (strpos($pem_version['name'], $branch) === 0)
241        {
242          $versions_to_check[] = $pem_version['id'];
243        }
244      }
245    }
246    if (empty($versions_to_check))
247    {
248      return false;
249    }
250
251    // Languages to check
252    $languages_to_check = array();
253    foreach($this->fs_languages as $fs_language)
254    {
255      if (isset($fs_language['extension']))
256      {
257        $languages_to_check[] = $fs_language['extension'];
258      }
259    }
260
261    // Retrieve PEM languages infos
262    $url = PEM_URL . '/api/get_revision_list.php';
263    $get_data = array_merge($get_data, array(
264      'last_revision_only' => 'true',
265      'version' => implode(',', $versions_to_check),
266      'lang' => $user['language'],
267      'get_nb_downloads' => 'true',
268      )
269    );
270    if (!empty($languages_to_check))
271    {
272      if ($new)
273      {
274        $get_data['extension_exclude'] = implode(',', $languages_to_check);
275      }
276      else
277      {
278        $get_data['extension_include'] = implode(',', $languages_to_check);
279      }
280    }
281
282    if (fetchRemote($url, $result, $get_data))
283    {
284      $pem_languages = @unserialize($result);
285      if (!is_array($pem_languages))
286      {
287        return false;
288      }
289      foreach ($pem_languages as $language)
290      {
291        if (preg_match('/^.*? \[[A-Z]{2}\]$/', $language['extension_name']))
292        {
293          $this->server_languages[$language['extension_id']] = $language;
294        }
295      }
296      @uasort($this->server_languages, array($this, 'extension_name_compare'));
297      return true;
298    }
299    return false;
300  }
301
302  /**
303   * Extract language files from archive
304   *
305   * @param string - install or upgrade
306   * @param string - remote revision identifier (numeric)
307   * @param string - language id or extension id
308   */
309  function extract_language_files($action, $revision, $dest='')
310  {
311    if ($archive = tempnam( PHPWG_ROOT_PATH.'language', 'zip'))
312    {
313      $url = PEM_URL . '/download.php';
314      $get_data = array(
315        'rid' => $revision,
316        'origin' => 'piwigo_'.$action,
317      );
318
319      if ($handle = @fopen($archive, 'wb') and fetchRemote($url, $handle, $get_data))
320      {
321        fclose($handle);
322        include(PHPWG_ROOT_PATH.'admin/include/pclzip.lib.php');
323        $zip = new PclZip($archive);
324        if ($list = $zip->listContent())
325        {
326          foreach ($list as $file)
327          {
328            // we search common.lang.php in archive
329            if (basename($file['filename']) == 'common.lang.php'
330              and (!isset($main_filepath)
331              or strlen($file['filename']) < strlen($main_filepath)))
332            {
333              $main_filepath = $file['filename'];
334            }
335          }
336          if (isset($main_filepath))
337          {
338            $root = basename(dirname($main_filepath)); // common.lang.php path in archive
339            if (preg_match('/^[a-z]{2}_[A-Z]{2}$/', $root))
340            {
341              if ($action == 'install')
342              {
343                $dest = $root;
344              }
345              $extract_path = PHPWG_ROOT_PATH.'language/'.$dest;
346              if (
347                $result = $zip->extract(
348                  PCLZIP_OPT_PATH, $extract_path,
349                  PCLZIP_OPT_REMOVE_PATH, $root,
350                  PCLZIP_OPT_REPLACE_NEWER
351                  )
352                )
353              {
354                foreach ($result as $file)
355                {
356                  if ($file['stored_filename'] == $main_filepath)
357                  {
358                    $status = $file['status'];
359                    break;
360                  }
361                }
362                if ($status == 'ok')
363                {
364                  $this->get_fs_languages();
365                  if ($action == 'install')
366                  {
367                    $this->perform_action('activate', $dest);
368                  }
369                }
370                if (file_exists($extract_path.'/obsolete.list')
371                  and $old_files = file($extract_path.'/obsolete.list', FILE_IGNORE_NEW_LINES)
372                  and !empty($old_files))
373                {
374                  array_push($old_files, 'obsolete.list');
375                  foreach($old_files as $old_file)
376                  {
377                    $path = $extract_path.'/'.$old_file;
378                    if (is_file($path))
379                    {
380                      @unlink($path);
381                    }
382                    elseif (is_dir($path))
383                    {
384                      if (!$this->deltree($path))
385                      {
386                        $this->send_to_trash($path);
387                      }
388                    }
389                  }
390                }
391              }
392              else $status = 'extract_error';
393            }
394            else $status = 'archive_error';
395          }
396          else $status = 'archive_error';
397        }
398        else $status = 'archive_error';
399      }
400      else $status = 'dl_archive_error';
401    }
402    else $status = 'temp_path_error';
403
404    @unlink($archive);
405    return $status;
406  }
407
408  /**
409   * delete $path directory
410   * @param string - path
411   */
412  function deltree($path)
413  {
414    if (is_dir($path))
415    {
416      $fh = opendir($path);
417      while ($file = readdir($fh))
418      {
419        if ($file != '.' and $file != '..')
420        {
421          $pathfile = $path . '/' . $file;
422          if (is_dir($pathfile))
423          {
424            $this->deltree($pathfile);
425          }
426          else
427          {
428            @unlink($pathfile);
429          }
430        }
431      }
432      closedir($fh);
433      return @rmdir($path);
434    }
435  }
436
437  /**
438   * send $path to trash directory
439   * @param string - path
440   */
441  function send_to_trash($path)
442  {
443    $trash_path = PHPWG_ROOT_PATH . 'language/trash';
444    if (!is_dir($trash_path))
445    {
446      @mkdir($trash_path);
447      $file = @fopen($trash_path . '/.htaccess', 'w');
448      @fwrite($file, 'deny from all');
449      @fclose($file);
450    }
451    while ($r = $trash_path . '/' . md5(uniqid(rand(), true)))
452    {
453      if (!is_dir($r))
454      {
455        @rename($path, $r);
456        break;
457      }
458    }
459  }
460
461  /**
462   * Sort functions
463   */
464  function language_version_compare($a, $b)
465  {
466    $pattern = array('/([a-z])/ei', '/\.+/', '/\.\Z|\A\./');
467    $replacement = array( "'.'.intval('\\1', 36).'.'", '.', '');
468
469    $array = preg_replace($pattern, $replacement, array($a, $b));
470
471    return version_compare($array[0], $array[1], '>=');
472  }
473
474  function extension_name_compare($a, $b)
475  {
476    return strcmp(strtolower($a['extension_name']), strtolower($b['extension_name']));
477  }
478}
479?>
Note: See TracBrowser for help on using the repository browser.