source: trunk/admin/include/updates.class.php @ 26922

Last change on this file since 26922 was 26461, checked in by mistic100, 11 years ago

Update headers to 2014. Happy new year!!

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