source: trunk/admin/include/updates.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.

File size: 13.6 KB
Line 
1<?php
2
3if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
4
5class updates
6{
7  var $types = array();
8  var $plugins;
9  var $themes;
10  var $languages;
11  var $missing = array();
12  var $default_plugins = array();
13  var $default_themes = array();
14  var $default_languages = array();
15  var $merged_extensions = array();
16  var $merged_extension_url = 'http://piwigo.org/download/merged_extensions.txt';
17
18  function __construct($page='updates')
19  {
20    $this->types = array('plugins', 'themes', 'languages');
21
22    if (in_array($page, $this->types))
23    {
24      $this->types = array($page);
25    }
26    $this->default_themes = array('clear', 'dark', 'Sylvia');
27    $this->default_plugins = array('admin_multi_view', 'c13y_upgrade', 'language_switch', 'LocalFilesEditor');
28
29    foreach ($this->types as $type)
30    {
31      include_once(PHPWG_ROOT_PATH.'admin/include/'.$type.'.class.php');
32      $this->$type = new $type();
33    }
34  }
35
36  function check_piwigo_upgrade()
37  {
38    $_SESSION['need_update'] = null;
39
40    if (preg_match('/(\d+\.\d+)\.(\d+)/', PHPWG_VERSION, $matches)
41      and @fetchRemote(PHPWG_URL.'/download/all_versions.php', $result))
42    {
43      $all_versions = @explode("\n", $result);
44      $new_version = trim($all_versions[0]);
45      $_SESSION['need_update'] = version_compare(PHPWG_VERSION, $new_version, '<');
46    }
47  }
48
49  function get_server_extensions($version=PHPWG_VERSION)
50  {
51    global $user;
52
53    $get_data = array(
54      'format' => 'php',
55    );
56
57    // Retrieve PEM versions
58    $versions_to_check = array();
59    $url = PEM_URL . '/api/get_version_list.php';
60    if (fetchRemote($url, $result, $get_data) and $pem_versions = @unserialize($result))
61    {
62      if (!preg_match('/^\d+\.\d+\.\d+/', $version))
63      {
64        $version = $pem_versions[0]['name'];
65      }
66      $branch = substr($version, 0, strrpos($version, '.'));
67      foreach ($pem_versions as $pem_version)
68      {
69        if (strpos($pem_version['name'], $branch) === 0)
70        {
71          $versions_to_check[] = $pem_version['id'];
72        }
73      }
74    }
75    if (empty($versions_to_check))
76    {
77      return false;
78    }
79
80    // Extensions to check
81    $ext_to_check = array();
82    foreach ($this->types as $type)
83    {
84      $fs = 'fs_'.$type;
85      foreach ($this->$type->$fs as $ext)
86      {
87        if (isset($ext['extension']))
88        {
89          $ext_to_check[$ext['extension']] = $type;
90        }
91      }
92    }
93
94    // Retrieve PEM plugins infos
95    $url = PEM_URL . '/api/get_revision_list.php';
96    $get_data = array_merge($get_data, array(
97      'last_revision_only' => 'true',
98      'version' => implode(',', $versions_to_check),
99      'lang' => substr($user['language'], 0, 2),
100      'get_nb_downloads' => 'true',
101      )
102    );
103
104    $post_data = array();
105    if (!empty($ext_to_check))
106    {
107      $post_data['extension_include'] = implode(',', array_keys($ext_to_check));
108    }
109
110    if (fetchRemote($url, $result, $get_data, $post_data))
111    {
112      $pem_exts = @unserialize($result);
113      if (!is_array($pem_exts))
114      {
115        return false;
116      }
117      foreach ($pem_exts as $ext)
118      {
119        if (isset($ext_to_check[$ext['extension_id']]))
120        {
121          $server = 'server_'.$ext_to_check[$ext['extension_id']];
122          $this->$ext_to_check[$ext['extension_id']]->$server += array($ext['extension_id'] => $ext);
123          unset($ext_to_check[$ext['extension_id']]);
124        }
125      }
126      $this->check_missing_extensions($ext_to_check);
127      return true;
128    }
129    return false;
130  }
131
132  // Check all extensions upgrades
133  function check_extensions()
134  {
135    global $conf;
136
137    if (!$this->get_server_extensions())
138    {
139      autoupdate_error();
140    }
141
142    $_SESSION['extensions_need_update'] = array();
143
144    foreach ($this->types as $type)
145    {
146      $fs = 'fs_'.$type;
147      $server = 'server_'.$type;
148      $server_ext = $this->$type->$server;
149      $fs_ext = $this->$type->$fs;
150
151      $ignore_list = array();
152      $need_upgrade = array();
153
154      foreach($fs_ext as $ext_id => $fs_ext)
155      {
156        if (isset($fs_ext['extension']) and isset($server_ext[$fs_ext['extension']]))
157        {
158          $ext_info = $server_ext[$fs_ext['extension']];
159
160          if (!$this->version_compare($fs_ext['version'], $ext_info['revision_name'], $type))
161          {
162            if (in_array($ext_id, $conf['updates_ignored'][$type]))
163            {
164              array_push($ignore_list, $ext_id);
165            }
166            else
167            {
168              $_SESSION['extensions_need_update'][$type][$ext_id] = $ext_info['revision_name'];
169            }
170          }
171        }
172      }
173      $conf['updates_ignored'][$type] = $ignore_list;
174    }
175    conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored'])));
176  }
177
178  // Check if extension have been upgraded since last check
179  function check_updated_extensions()
180  {
181    foreach ($this->types as $type)
182    {
183      if (!empty($_SESSION['extensions_need_update'][$type]))
184      {
185        $fs = 'fs_'.$type;
186        foreach($this->$type->$fs as $ext_id => $fs_ext)
187        {
188          if (isset($_SESSION['extensions_need_update'][$type][$ext_id])
189            and $this->version_compare($fs_ext['version'], $_SESSION['extensions_need_update'][$type][$ext_id], $type))
190          {
191            // Extension have been upgraded
192            $this->check_extensions();
193            break;
194          }
195        }
196      }
197    }
198  }
199
200  function check_missing_extensions($missing)
201  {
202    foreach ($missing as $id => $type)
203    {
204      $fs = 'fs_'.$type;
205      $default = 'default_'.$type;
206      foreach ($this->$type->$fs as $ext_id => $ext)
207      {
208        if (isset($ext['extension']) and $id == $ext['extension']
209          and !in_array($ext_id, $this->$default)
210          and !in_array($ext['extension'], $this->merged_extensions))
211        {
212          $this->missing[$type][] = $ext;
213          break;
214        }
215      }
216    }
217  }
218
219  function get_merged_extensions($version)
220  {
221    if (fetchRemote($this->merged_extension_url, $result))
222    {
223      $rows = explode("\n", $result);
224      foreach ($rows as $row)
225      {
226        if (preg_match('/^(\d+\.\d+): *(.*)$/', $row, $match))
227        {
228          if (version_compare($version, $match[1], '>='))
229          {
230            $extensions = explode(',', trim($match[2]));
231            $this->merged_extensions = array_merge($this->merged_extensions, $extensions);
232          }
233        }
234      }
235    }
236  }
237
238  function version_compare($a, $b, $type)
239  {
240    $version_compare = rtrim($type, 's').'_version_compare';
241
242    return $this->$type->$version_compare($a, $b);
243  }
244
245  function deltree($path, $move_to_trash=false)
246  {
247    if (is_dir($path))
248    {
249      $fh = opendir($path);
250      while ($file = readdir($fh))
251      {
252        if ($file != '.' and $file != '..')
253        {
254          $pathfile = $path . '/' . $file;
255          if (is_dir($pathfile))
256          {
257            self::deltree($pathfile, $move_to_trash);
258          }
259          else
260          {
261            @unlink($pathfile);
262          }
263        }
264      }
265      closedir($fh);
266      if (@rmdir($path))
267      {
268        return true;
269      }
270      elseif ($move_to_trash)
271      {
272        $trash = PHPWG_ROOT_PATH.'_trash';
273        if (!is_dir($trash))
274        {
275          @mkgetdir($trash);
276        }
277        return @rename($path, $trash . '/'.md5(uniqid(rand(), true)));
278      }
279      else
280      {
281        return false;
282      }
283    }
284  }
285
286  function process_obsolete_list($file)
287  {
288    if (file_exists(PHPWG_ROOT_PATH.$file)
289      and $old_files = file(PHPWG_ROOT_PATH.$file, FILE_IGNORE_NEW_LINES)
290      and !empty($old_files))
291    {
292      array_push($old_files, $file);
293      foreach($old_files as $old_file)
294      {
295        $path = PHPWG_ROOT_PATH.$old_file;
296        if (is_file($path))
297        {
298          @unlink($path);
299        }
300        elseif (is_dir($path))
301        {
302          self::deltree($path, true);
303        }
304      }
305    }
306  }
307
308  function dump_database($include_history=false)
309  {
310    global $page, $conf, $cfgBase;
311
312    if (version_compare(PHPWG_VERSION, '2.1', '<'))
313    {
314      $conf['db_base'] = $cfgBase;
315    }
316
317    include(PHPWG_ROOT_PATH.'admin/include/mysqldump.php');
318
319    $path = $conf['local_data_dir'].'/update';
320
321    if (@mkgetdir($path)
322      and ($backupFile = tempnam($path, 'sql'))
323      and ($dumper = new MySQLDump($conf['db_base'],$backupFile,false,false)))
324    {
325      foreach (get_defined_constants() as $constant => $value)
326      {
327        if (preg_match('/_TABLE$/', $constant))
328        {
329          $dumper->getTableStructure($value);
330          if ($constant == 'HISTORY_TABLE' and !$include_history)
331          {
332            continue;
333          }
334          $dumper->getTableData($value);
335        }
336      }
337    }
338
339    if (@filesize($backupFile))
340    {
341      $http_headers = array(
342        'Content-Length: '.@filesize($backupFile),
343        'Content-Type: text/x-sql',
344        'Content-Disposition: attachment; filename="database.sql";',
345        'Content-Transfer-Encoding: binary',
346        );
347
348      foreach ($http_headers as $header) {
349        header($header);
350      }
351
352      @readfile($backupFile);
353      self::deltree($conf['local_data_dir'].'/update');
354      exit();
355    }
356    else
357    {
358      array_push($page['errors'], l10n('Unable to dump database.'));
359    }
360  }
361
362  function upgrade_to($upgrade_to, &$step)
363  {
364    global $page, $conf, $template;
365
366    if (!version_compare($_POST['upgrade_to'], PHPWG_VERSION, '>'))
367    {
368      redirect(get_root_url().'admin.php?page=plugin-'.basename(dirname(__FILE__)));
369    }
370
371    if ($step == 2)
372    {
373      preg_match('/(\d+\.\d+)\.(\d+)/', PHPWG_VERSION, $matches);
374      $code =  $matches[1].'.x_to_'.$_POST['upgrade_to'];
375      $dl_code = str_replace(array('.', '_'), '', $code);
376      $remove_path = $code;
377      $obsolete_list = 'obsolete.list';
378    }
379    else
380    {
381      $code = $_POST['upgrade_to'];
382      $dl_code = $code;
383      $remove_path = version_compare($code, '2.0.8', '>=') ? 'piwigo' : 'piwigo-'.$code;
384      $obsolete_list = PHPWG_ROOT_PATH.'install/obsolete.list';
385    }
386
387    if (empty($page['errors']))
388    {
389      $path = $conf['local_data_dir'].'/update';
390      $filename = $path.'/'.$code.'.zip';
391      @mkgetdir($path);
392
393      $chunk_num = 0;
394      $end = false;
395      $zip = @fopen($filename, 'w');
396      while (!$end)
397      {
398        $chunk_num++;
399        if (@fetchRemote(PHPWG_URL.'/download/dlcounter.php?code='.$dl_code.'&chunk_num='.$chunk_num, $result)
400          and $input = @unserialize($result))
401        {
402          if (0 == $input['remaining'])
403          {
404            $end = true;
405          }
406          @fwrite($zip, base64_decode($input['data']));
407        }
408        else
409        {
410          $end = true;
411        }
412      }
413      @fclose($zip);
414
415      if (@filesize($filename))
416      {
417        $zip = new PclZip($filename);
418        if ($result = $zip->extract(PCLZIP_OPT_PATH, PHPWG_ROOT_PATH,
419                                    PCLZIP_OPT_REMOVE_PATH, $remove_path,
420                                    PCLZIP_OPT_SET_CHMOD, 0755,
421                                    PCLZIP_OPT_REPLACE_NEWER))
422        {
423          //Check if all files were extracted
424          $error = '';
425          foreach($result as $extract)
426          {
427            if (!in_array($extract['status'], array('ok', 'filtered', 'already_a_directory')))
428            {
429              // Try to change chmod and extract
430              if (@chmod(PHPWG_ROOT_PATH.$extract['filename'], 0777)
431                and ($res = $zip->extract(PCLZIP_OPT_BY_NAME, $remove_path.'/'.$extract['filename'],
432                                          PCLZIP_OPT_PATH, PHPWG_ROOT_PATH,
433                                          PCLZIP_OPT_REMOVE_PATH, $remove_path,
434                                          PCLZIP_OPT_SET_CHMOD, 0755,
435                                          PCLZIP_OPT_REPLACE_NEWER))
436                and isset($res[0]['status'])
437                and $res[0]['status'] == 'ok')
438              {
439                continue;
440              }
441              else
442              {
443                $error .= $extract['filename'].': '.$extract['status']."\n";
444              }
445            }
446          }
447
448          if (empty($error))
449          {
450            self::obsolete_list($obsolete_list);
451            self::deltree($conf['local_data_dir'].'/update');
452            invalidate_user_cache(true);
453            $template->delete_compiled_templates();
454            unset($_SESSION['need_update']);
455            if ($step == 2)
456            {
457              array_push($page['infos'], sprintf(l10n('autoupdate_success'), $upgrade_to));
458              $step = -1;
459            }
460            else
461            {
462              redirect(PHPWG_ROOT_PATH.'upgrade.php?now=');
463            }
464          }
465          else
466          {
467            file_put_contents($conf['local_data_dir'].'/update/log_error.txt', $error);
468            $relative_path = trim(str_replace(dirname(dirname(dirname(dirname(__FILE__)))), '', $conf['local_data_dir']), '/\\');
469            array_push($page['errors'], sprintf(l10n('autoupdate_extract_fail'), PHPWG_ROOT_PATH.$relative_path.'/update/log_error.txt'));
470          }
471        }
472        else
473        {
474          self::deltree($conf['local_data_dir'].'/update');
475          array_push($page['errors'], l10n('autoupdate_fail'));
476        }
477      }
478      else
479      {
480        array_push($page['errors'], l10n('Piwigo cannot retrieve upgrade file from server'));
481      }
482    }
483  }
484}
485
486?>
Note: See TracBrowser for help on using the repository browser.