source: branches/2.5/admin/include/updates.class.php @ 29905

Last change on this file since 29905 was 16179, checked in by mistic100, 12 years ago

bug 2671: use get_branch_from_version() to find the real branch, however the version looks like

File size: 13.9 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', 'elegant');
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?rand='.md5(uniqid(rand(), true)), $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 = get_branch_from_version($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      return false;
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 = PHPWG_ROOT_PATH.$conf['data_location'].'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(PHPWG_ROOT_PATH.$conf['data_location'].'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, $check_current_version=true)
363  {
364    global $page, $conf, $template;
365
366    if ($check_current_version and !version_compare($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_'.$upgrade_to;
375      $dl_code = str_replace(array('.', '_'), '', $code);
376      $remove_path = $code;
377      $obsolete_list = 'obsolete.list';
378    }
379    else
380    {
381      $code = $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 = PHPWG_ROOT_PATH.$conf['data_location'].'update';
390      $filename = $path.'/'.$code.'.zip';
391      @mkgetdir($path);
392
393      $chunk_num = 0;
394      $end = false;
395      $zip = @fopen($filename, 'w');
396
397      while (!$end)
398      {
399        $chunk_num++;
400        if (@fetchRemote(PHPWG_URL.'/download/dlcounter.php?code='.$dl_code.'&chunk_num='.$chunk_num, $result)
401          and $input = @unserialize($result))
402        {
403          if (0 == $input['remaining'])
404          {
405            $end = true;
406          }
407          @fwrite($zip, base64_decode($input['data']));
408        }
409        else
410        {
411          $end = true;
412        }
413      }
414      @fclose($zip);
415
416      if (@filesize($filename))
417      {
418        $zip = new PclZip($filename);
419        if ($result = $zip->extract(PCLZIP_OPT_PATH, PHPWG_ROOT_PATH,
420                                    PCLZIP_OPT_REMOVE_PATH, $remove_path,
421                                    PCLZIP_OPT_SET_CHMOD, 0755,
422                                    PCLZIP_OPT_REPLACE_NEWER))
423        {
424          //Check if all files were extracted
425          $error = '';
426          foreach($result as $extract)
427          {
428            if (!in_array($extract['status'], array('ok', 'filtered', 'already_a_directory')))
429            {
430              // Try to change chmod and extract
431              if (@chmod(PHPWG_ROOT_PATH.$extract['filename'], 0777)
432                and ($res = $zip->extract(PCLZIP_OPT_BY_NAME, $remove_path.'/'.$extract['filename'],
433                                          PCLZIP_OPT_PATH, PHPWG_ROOT_PATH,
434                                          PCLZIP_OPT_REMOVE_PATH, $remove_path,
435                                          PCLZIP_OPT_SET_CHMOD, 0755,
436                                          PCLZIP_OPT_REPLACE_NEWER))
437                and isset($res[0]['status'])
438                and $res[0]['status'] == 'ok')
439              {
440                continue;
441              }
442              else
443              {
444                $error .= $extract['filename'].': '.$extract['status']."\n";
445              }
446            }
447          }
448
449          if (empty($error))
450          {
451            self::process_obsolete_list($obsolete_list);
452            self::deltree(PHPWG_ROOT_PATH.$conf['data_location'].'update');
453            invalidate_user_cache(true);
454            $template->delete_compiled_templates();
455            unset($_SESSION['need_update']);
456            if ($step == 2)
457            {
458              array_push($page['infos'], l10n('Update Complete'), $upgrade_to);
459              $step = -1;
460            }
461            else
462            {
463              redirect(PHPWG_ROOT_PATH.'upgrade.php?now=');
464            }
465          }
466          else
467          {
468            file_put_contents(PHPWG_ROOT_PATH.$conf['data_location'].'update/log_error.txt', $error);
469            array_push(
470              $page['errors'],
471              sprintf(
472                l10n('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>.'),
473                get_root_url().$conf['data_location'].'update/log_error.txt'
474              )
475            );
476          }
477        }
478        else
479        {
480          self::deltree(PHPWG_ROOT_PATH.$conf['data_location'].'update');
481          array_push($page['errors'], l10n('An error has occured during upgrade.'));
482        }
483      }
484      else
485      {
486        array_push($page['errors'], l10n('Piwigo cannot retrieve upgrade file from server'));
487      }
488    }
489  }
490}
491
492?>
Note: See TracBrowser for help on using the repository browser.