From 491e8adc7467de9f9aa6dbbebfcb8b82c676b46a Mon Sep 17 00:00:00 2001
From: patdenice
Date: Wed, 20 Apr 2011 14:52:52 +0000
Subject: feature:2271 Merge autoupdate plugin into piwigo core.
git-svn-id: http://piwigo.org/svn/trunk@10511 68402e56-0260-453c-a942-63ccdbb3a9ee
---
admin/include/functions.php | 1 +
admin/include/mysqldump.php | 421 +++++++++++++++++++++
admin/include/updates.class.php | 481 ++++++++++++++++++++++++
admin/themes/default/images/ajax-loader-bar.gif | Bin 0 -> 10819 bytes
admin/themes/default/template/admin.tpl | 1 +
admin/themes/default/template/updates_ext.tpl | 272 ++++++++++++++
admin/themes/default/template/updates_pwg.tpl | 99 +++++
admin/updates.php | 44 +++
admin/updates_ext.php | 86 +++++
admin/updates_pwg.php | 166 ++++++++
10 files changed, 1571 insertions(+)
create mode 100644 admin/include/mysqldump.php
create mode 100644 admin/include/updates.class.php
create mode 100644 admin/themes/default/images/ajax-loader-bar.gif
create mode 100644 admin/themes/default/template/updates_ext.tpl
create mode 100644 admin/themes/default/template/updates_pwg.tpl
create mode 100644 admin/updates.php
create mode 100644 admin/updates_ext.php
create mode 100644 admin/updates_pwg.php
(limited to 'admin')
diff --git a/admin/include/functions.php b/admin/include/functions.php
index f5afa9633..3d32e7b0e 100644
--- a/admin/include/functions.php
+++ b/admin/include/functions.php
@@ -2085,6 +2085,7 @@ function get_active_menu($menu_page)
case 'maintenance':
case 'thumbnail':
case 'comments':
+ case 'updates':
return 4;
case 'configuration':
diff --git a/admin/include/mysqldump.php b/admin/include/mysqldump.php
new file mode 100644
index 000000000..515d86ae9
--- /dev/null
+++ b/admin/include/mysqldump.php
@@ -0,0 +1,421 @@
+
+* $connection = @mysql_connect($dbhost,$dbuser,$dbpsw);
+* $dumper = new MySQLDump($dbname,'filename.sql',false,false);
+* $dumper->doDump();
+*
+*
+* Special thanks to:
+* - Andrea Ingaglio helping in development of all class code
+* - Dylan Pugh for precious advices halfing the size of the output file and for helping in debug
+*
+* @name MySQLDump
+* @author Daniele Vigaṇ - CreativeFactory.it
+* @version 2.20 - 02/11/2007
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*/
+
+class MySQLDump {
+ /**
+ * @access private
+ */
+ var $database = null;
+
+ /**
+ * @access private
+ */
+ var $compress = false;
+
+ /**
+ * @access private
+ */
+ var $hexValue = false;
+
+ /**
+ * The output filename
+ * @access private
+ */
+ var $filename = null;
+
+ /**
+ * The pointer of the output file
+ * @access private
+ */
+ var $file = null;
+
+ /**
+ * @access private
+ */
+ var $isWritten = false;
+
+ /**
+ * Class constructor
+ * @param string $db The database name
+ * @param string $filepath The file where the dump will be written
+ * @param boolean $compress It defines if the output file is compress (gzip) or not
+ * @param boolean $hexValue It defines if the outup values are base-16 or not
+ */
+ function MYSQLDump($db = null, $filepath = 'dump.sql', $compress = false, $hexValue = false){
+ $this->compress = $compress;
+ if ( !$this->setOutputFile($filepath) )
+ return false;
+ return $this->setDatabase($db);
+ }
+
+ /**
+ * Sets the database to work on
+ * @param string $db The database name
+ */
+ function setDatabase($db){
+ $this->database = $db;
+ if ( !@mysql_select_db($this->database) )
+ return false;
+ return true;
+ }
+
+ /**
+ * Returns the database where the class is working on
+ * @return string
+ */
+ function getDatabase(){
+ return $this->database;
+ }
+
+ /**
+ * Sets the output file type (It can be made only if the file hasn't been already written)
+ * @param boolean $compress If it's true, the output file will be compressed
+ */
+ function setCompress($compress){
+ if ( $this->isWritten )
+ return false;
+ $this->compress = $compress;
+ $this->openFile($this->filename);
+ return true;
+ }
+
+ /**
+ * Returns if the output file is or not compressed
+ * @return boolean
+ */
+ function getCompress(){
+ return $this->compress;
+ }
+
+ /**
+ * Sets the output file
+ * @param string $filepath The file where the dump will be written
+ */
+ function setOutputFile($filepath){
+ if ( $this->isWritten )
+ return false;
+ $this->filename = $filepath;
+ $this->file = $this->openFile($this->filename);
+ return $this->file;
+ }
+
+ /**
+ * Returns the output filename
+ * @return string
+ */
+ function getOutputFile(){
+ return $this->filename;
+ }
+
+ /**
+ * Writes to file the $table's structure
+ * @param string $table The table name
+ */
+ function getTableStructure($table){
+ if ( !$this->setDatabase($this->database) )
+ return false;
+ // Structure Header
+ $structure = "-- \n";
+ $structure .= "-- Table structure for table `{$table}` \n";
+ $structure .= "-- \n\n";
+ // Dump Structure
+ $structure .= 'DROP TABLE IF EXISTS `'.$table.'`;'."\n";
+ $structure .= "CREATE TABLE `".$table."` (\n";
+ $records = @mysql_query('SHOW FIELDS FROM `'.$table.'`');
+ if ( @mysql_num_rows($records) == 0 )
+ return false;
+ while ( $record = mysql_fetch_assoc($records) ) {
+ $structure .= '`'.$record['Field'].'` '.$record['Type'];
+ if ( isset($record['Default']) )
+ $structure .= ' DEFAULT \''.$record['Default'].'\'';
+ if ( @strcmp($record['Null'],'YES') != 0 )
+ $structure .= ' NOT NULL';
+ elseif ( is_null($record['Default']) )
+ $structure .= ' DEFAULT NULL';
+ if ( !empty($record['Extra']) )
+ $structure .= ' '.$record['Extra'];
+ $structure .= ",\n";
+ }
+ $structure = @ereg_replace(",\n$", null, $structure);
+
+ // Save all Column Indexes
+ $structure .= $this->getSqlKeysTable($table);
+ $structure .= "\n)";
+
+ //Save table engine
+ $records = @mysql_query("SHOW TABLE STATUS LIKE '".$table."'");
+
+ if ( $record = @mysql_fetch_assoc($records) ) {
+ if ( !empty($record['Engine']) )
+ $structure .= ' ENGINE='.$record['Engine'];
+ if ( !empty($record['Auto_increment']) )
+ $structure .= ' AUTO_INCREMENT='.$record['Auto_increment'];
+ }
+
+ $structure .= ";\n\n-- --------------------------------------------------------\n\n";
+ $this->saveToFile($this->file,$structure);
+ }
+
+ /**
+ * Writes to file the $table's data
+ * @param string $table The table name
+ * @param boolean $hexValue It defines if the output is base 16 or not
+ */
+ function getTableData($table,$hexValue = true) {
+ if ( !$this->setDatabase($this->database) )
+ return false;
+ // Header
+ $data = "-- \n";
+ $data .= "-- Dumping data for table `$table` \n";
+ $data .= "-- \n\n";
+
+ $records = mysql_query('SHOW FIELDS FROM `'.$table.'`');
+ $num_fields = @mysql_num_rows($records);
+ if ( $num_fields == 0 )
+ return false;
+ // Field names
+ $selectStatement = "SELECT ";
+ $insertStatement = "INSERT INTO `$table` (";
+ $hexField = array();
+ for ($x = 0; $x < $num_fields; $x++) {
+ $record = @mysql_fetch_assoc($records);
+ if ( ($hexValue) && ($this->isTextValue($record['Type'])) ) {
+ $selectStatement .= 'HEX(`'.$record['Field'].'`)';
+ $hexField [$x] = true;
+ }
+ else
+ $selectStatement .= '`'.$record['Field'].'`';
+ $insertStatement .= '`'.$record['Field'].'`';
+ $insertStatement .= ", ";
+ $selectStatement .= ", ";
+ }
+ $insertStatement = @substr($insertStatement,0,-2).') VALUES'."\n";
+ $selectStatement = @substr($selectStatement,0,-2).' FROM `'.$table.'`';
+
+ $records = @mysql_query($selectStatement);
+ $num_rows = @mysql_num_rows($records);
+ $num_fields = @mysql_num_fields($records);
+ // Dump data
+ if ( $num_rows > 0 ) {
+ $data .= $insertStatement;
+ for ($i = 0; $i < $num_rows; $i++) {
+ $record = @mysql_fetch_assoc($records);
+ $data .= ' (';
+ for ($j = 0; $j < $num_fields; $j++) {
+ $field_name = @mysql_field_name($records, $j);
+ if ( @$hexField[$j] && (@strlen($record[$field_name]) > 0) )
+ $data .= "0x".$record[$field_name];
+ elseif (is_null($record[$field_name]))
+ $data .= "NULL";
+ else
+ $data .= "'".@str_replace('\"','"',@mysql_real_escape_string($record[$field_name]))."'";
+ $data .= ',';
+ }
+ $data = @substr($data,0,-1).")";
+ $data .= ( $i < ($num_rows-1) ) ? ',' : ';';
+ $data .= "\n";
+ //if data in greather than 1MB save
+ if (strlen($data) > 1048576) {
+ $this->saveToFile($this->file,$data);
+ $data = '';
+ }
+ }
+ $data .= "\n-- --------------------------------------------------------\n\n";
+ $this->saveToFile($this->file,$data);
+ }
+ }
+
+ /**
+ * Writes to file all the selected database tables structure
+ * @return boolean
+ */
+ function getDatabaseStructure(){
+ $records = @mysql_query('SHOW TABLES');
+ if ( @mysql_num_rows($records) == 0 )
+ return false;
+ $structure = '';
+ while ( $record = @mysql_fetch_row($records) ) {
+ $structure .= $this->getTableStructure($record[0]);
+ }
+ return true;
+ }
+
+ /**
+ * Writes to file all the selected database tables data
+ * @param boolean $hexValue It defines if the output is base-16 or not
+ */
+ function getDatabaseData($hexValue = true){
+ $records = @mysql_query('SHOW TABLES');
+ if ( @mysql_num_rows($records) == 0 )
+ return false;
+ while ( $record = @mysql_fetch_row($records) ) {
+ $this->getTableData($record[0],$hexValue);
+ }
+ }
+
+ /**
+ * Writes to file the selected database dump
+ */
+ function doDump() {
+ $this->saveToFile($this->file,"SET FOREIGN_KEY_CHECKS = 0;\n\n");
+ $this->getDatabaseStructure();
+ $this->getDatabaseData($this->hexValue);
+ $this->saveToFile($this->file,"SET FOREIGN_KEY_CHECKS = 1;\n\n");
+ $this->closeFile($this->file);
+ return true;
+ }
+
+ /**
+ * @deprecated Look at the doDump() method
+ */
+ function writeDump($filename) {
+ if ( !$this->setOutputFile($filename) )
+ return false;
+ $this->doDump();
+ $this->closeFile($this->file);
+ return true;
+ }
+
+ /**
+ * @access private
+ */
+ function getSqlKeysTable ($table) {
+ $primary = "";
+ $unique = array();
+ $index = array();
+ $fulltext = array();
+ $results = mysql_query("SHOW KEYS FROM `{$table}`");
+ if ( @mysql_num_rows($results) == 0 )
+ return false;
+ while($row = mysql_fetch_object($results)) {
+ if (($row->Key_name == 'PRIMARY') AND ($row->Index_type == 'BTREE')) {
+ if ( $primary == "" )
+ $primary = " PRIMARY KEY (`{$row->Column_name}`";
+ else
+ $primary .= ", `{$row->Column_name}`";
+ }
+ if (($row->Key_name != 'PRIMARY') AND ($row->Non_unique == '0') AND ($row->Index_type == 'BTREE')) {
+ if ( (empty($unique)) OR (empty($unique[$row->Key_name])) )
+ $unique[$row->Key_name] = " UNIQUE KEY `{$row->Key_name}` (`{$row->Column_name}`";
+ else
+ $unique[$row->Key_name] .= ", `{$row->Column_name}`";
+ }
+ if (($row->Key_name != 'PRIMARY') AND ($row->Non_unique == '1') AND ($row->Index_type == 'BTREE')) {
+ if ( (empty($index)) OR (empty($index[$row->Key_name])) )
+ $index[$row->Key_name] = " KEY `{$row->Key_name}` (`{$row->Column_name}`";
+ else
+ $index[$row->Key_name] .= ", `{$row->Column_name}`";
+ }
+ if (($row->Key_name != 'PRIMARY') AND ($row->Non_unique == '1') AND ($row->Index_type == 'FULLTEXT')) {
+ if ( (empty($fulltext)) OR (empty($fulltext[$row->Key_name])) )
+ $fulltext[$row->Key_name] = " FULLTEXT `{$row->Key_name}` (`{$row->Column_name}`";
+ else
+ $fulltext[$row->Key_name] .= ", `{$row->Column_name}`";
+ }
+ }
+ $sqlKeyStatement = '';
+ // generate primary, unique, key and fulltext
+ if ( $primary != "" ) {
+ $sqlKeyStatement .= ",\n";
+ $primary .= ")";
+ $sqlKeyStatement .= $primary;
+ }
+ if (!empty($unique)) {
+ foreach ($unique as $keyName => $keyDef) {
+ $sqlKeyStatement .= ",\n";
+ $keyDef .= ")";
+ $sqlKeyStatement .= $keyDef;
+
+ }
+ }
+ if (!empty($index)) {
+ foreach ($index as $keyName => $keyDef) {
+ $sqlKeyStatement .= ",\n";
+ $keyDef .= ")";
+ $sqlKeyStatement .= $keyDef;
+ }
+ }
+ if (!empty($fulltext)) {
+ foreach ($fulltext as $keyName => $keyDef) {
+ $sqlKeyStatement .= ",\n";
+ $keyDef .= ")";
+ $sqlKeyStatement .= $keyDef;
+ }
+ }
+ return $sqlKeyStatement;
+ }
+
+ /**
+ * @access private
+ */
+ function isTextValue($field_type) {
+ switch ($field_type) {
+ case "tinytext":
+ case "text":
+ case "mediumtext":
+ case "longtext":
+ case "binary":
+ case "varbinary":
+ case "tinyblob":
+ case "blob":
+ case "mediumblob":
+ case "longblob":
+ return True;
+ break;
+ default:
+ return False;
+ }
+ }
+
+ /**
+ * @access private
+ */
+ function openFile($filename) {
+ $file = false;
+ if ( $this->compress )
+ $file = @gzopen($filename, "w9");
+ else
+ $file = @fopen($filename, "w");
+ return $file;
+ }
+
+ /**
+ * @access private
+ */
+ function saveToFile($file, $data) {
+ if ( $this->compress )
+ @gzwrite($file, $data);
+ else
+ @fwrite($file, $data);
+ $this->isWritten = true;
+ }
+
+ /**
+ * @access private
+ */
+ function closeFile($file) {
+ if ( $this->compress )
+ @gzclose($file);
+ else
+ @fclose($file);
+ }
+}
+?>
\ No newline at end of file
diff --git a/admin/include/updates.class.php b/admin/include/updates.class.php
new file mode 100644
index 000000000..b53001488
--- /dev/null
+++ b/admin/include/updates.class.php
@@ -0,0 +1,481 @@
+types = array('plugins', 'themes', 'languages');
+ $this->default_themes = array('clear', 'dark', 'Sylvia');
+ $this->default_plugins = array('admin_multi_view', 'c13y_upgrade', 'language_switch', 'LocalFilesEditor');
+
+ foreach ($this->types as $type)
+ {
+ include_once(PHPWG_ROOT_PATH.'admin/include/'.$type.'.class.php');
+ $this->$type = new $type();
+ }
+ }
+
+ function check_piwigo_upgrade()
+ {
+ $_SESSION['need_update'] = null;
+
+ if (preg_match('/(\d+\.\d+)\.(\d+)/', PHPWG_VERSION, $matches)
+ and @fetchRemote(PHPWG_URL.'/download/all_versions.php', $result))
+ {
+ $all_versions = @explode("\n", $result);
+ $new_version = trim($all_versions[0]);
+ $_SESSION['need_update'] = version_compare(PHPWG_VERSION, $new_version, '<');
+ }
+ }
+
+ function get_server_extensions($version=PHPWG_VERSION)
+ {
+ global $user;
+
+ $get_data = array(
+ 'format' => 'php',
+ );
+
+ // Retrieve PEM versions
+ $versions_to_check = array();
+ $url = PEM_URL . '/api/get_version_list.php';
+ if (fetchRemote($url, $result, $get_data) and $pem_versions = @unserialize($result))
+ {
+ if (!preg_match('/^\d+\.\d+\.\d+/', $version))
+ {
+ $version = $pem_versions[0]['name'];
+ }
+ $branch = substr($version, 0, strrpos($version, '.'));
+ foreach ($pem_versions as $pem_version)
+ {
+ if (strpos($pem_version['name'], $branch) === 0)
+ {
+ $versions_to_check[] = $pem_version['id'];
+ }
+ }
+ }
+ if (empty($versions_to_check))
+ {
+ return false;
+ }
+
+ // Extensions to check
+ $ext_to_check = array();
+ foreach ($this->types as $type)
+ {
+ $fs = 'fs_'.$type;
+ foreach ($this->$type->$fs as $ext)
+ {
+ if (isset($ext['extension']))
+ {
+ $ext_to_check[$ext['extension']] = $type;
+ }
+ }
+ }
+
+ // Retrieve PEM plugins infos
+ $url = PEM_URL . '/api/get_revision_list.php';
+ $get_data = array_merge($get_data, array(
+ 'last_revision_only' => 'true',
+ 'version' => implode(',', $versions_to_check),
+ 'lang' => substr($user['language'], 0, 2),
+ 'get_nb_downloads' => 'true',
+ )
+ );
+
+ $post_data = array();
+ if (!empty($ext_to_check))
+ {
+ $post_data['extension_include'] = implode(',', array_keys($ext_to_check));
+ }
+
+ if (fetchRemote($url, $result, $get_data, $post_data))
+ {
+ $pem_exts = @unserialize($result);
+ if (!is_array($pem_exts))
+ {
+ return false;
+ }
+ foreach ($pem_exts as $ext)
+ {
+ if (isset($ext_to_check[$ext['extension_id']]))
+ {
+ $server = 'server_'.$ext_to_check[$ext['extension_id']];
+ $this->$ext_to_check[$ext['extension_id']]->$server += array($ext['extension_id'] => $ext);
+ unset($ext_to_check[$ext['extension_id']]);
+ }
+ }
+ $this->check_missing_extensions($ext_to_check);
+ return true;
+ }
+ return false;
+ }
+
+ // Check all extensions upgrades
+ function check_extensions()
+ {
+ global $conf;
+
+ if (!$this->get_server_extensions())
+ {
+ autoupdate_error();
+ }
+
+ $_SESSION['extensions_need_update'] = array();
+
+ foreach ($this->types as $type)
+ {
+ $fs = 'fs_'.$type;
+ $server = 'server_'.$type;
+ $server_ext = $this->$type->$server;
+ $fs_ext = $this->$type->$fs;
+
+ $ignore_list = array();
+ $need_upgrade = array();
+
+ foreach($fs_ext as $ext_id => $fs_ext)
+ {
+ if (isset($fs_ext['extension']) and isset($server_ext[$fs_ext['extension']]))
+ {
+ $ext_info = $server_ext[$fs_ext['extension']];
+
+ if (!$this->version_compare($fs_ext['version'], $ext_info['revision_name'], $type))
+ {
+ if (in_array($ext_id, $conf['updates_ignored'][$type]))
+ {
+ array_push($ignore_list, $ext_id);
+ }
+ else
+ {
+ $_SESSION['extensions_need_update'][$type][$ext_id] = $ext_info['revision_name'];
+ }
+ }
+ }
+ }
+ $conf['updates_ignored'][$type] = $ignore_list;
+ }
+ conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored'])));
+ }
+
+ // Check if extension have been upgraded since last check
+ function check_updated_extensions()
+ {
+ foreach ($this->types as $type)
+ {
+ if (!empty($_SESSION['extensions_need_update'][$type]))
+ {
+ $fs = 'fs_'.$type;
+ foreach($this->$type->$fs as $ext_id => $fs_ext)
+ {
+ if (isset($_SESSION['extensions_need_update'][$type][$ext_id])
+ and $this->version_compare($fs_ext['version'], $_SESSION['extensions_need_update'][$type][$ext_id], $type))
+ {
+ // Extension have been upgraded
+ $this->check_extensions();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ function check_missing_extensions($missing)
+ {
+ foreach ($missing as $id => $type)
+ {
+ $fs = 'fs_'.$type;
+ $default = 'default_'.$type;
+ foreach ($this->$type->$fs as $ext_id => $ext)
+ {
+ if (isset($ext['extension']) and $id == $ext['extension']
+ and !in_array($ext_id, $this->$default)
+ and !in_array($ext['extension'], $this->merged_extensions))
+ {
+ $this->missing[$type][] = $ext;
+ break;
+ }
+ }
+ }
+ }
+
+ function get_merged_extensions($version)
+ {
+ if (fetchRemote($this->merged_extension_url, $result))
+ {
+ $rows = explode("\n", $result);
+ foreach ($rows as $row)
+ {
+ if (preg_match('/^(\d+\.\d+): *(.*)$/', $row, $match))
+ {
+ if (version_compare($version, $match[1], '>='))
+ {
+ $extensions = explode(',', trim($match[2]));
+ $this->merged_extensions = array_merge($this->merged_extensions, $extensions);
+ }
+ }
+ }
+ }
+ }
+
+ function version_compare($a, $b, $type)
+ {
+ $version_compare = rtrim($type, 's').'_version_compare';
+
+ return $this->$type->$version_compare($a, $b);
+ }
+
+ function deltree($path, $move_to_trash=false)
+ {
+ if (is_dir($path))
+ {
+ $fh = opendir($path);
+ while ($file = readdir($fh))
+ {
+ if ($file != '.' and $file != '..')
+ {
+ $pathfile = $path . '/' . $file;
+ if (is_dir($pathfile))
+ {
+ self::deltree($pathfile, $move_to_trash);
+ }
+ else
+ {
+ @unlink($pathfile);
+ }
+ }
+ }
+ closedir($fh);
+ if (@rmdir($path))
+ {
+ return true;
+ }
+ elseif ($move_to_trash)
+ {
+ $trash = PHPWG_ROOT_PATH.'_trash';
+ if (!is_dir($trash))
+ {
+ @mkgetdir($trash);
+ }
+ return @rename($path, $trash . '/'.md5(uniqid(rand(), true)));
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ function process_obsolete_list($file)
+ {
+ if (file_exists(PHPWG_ROOT_PATH.$file)
+ and $old_files = file(PHPWG_ROOT_PATH.$file, FILE_IGNORE_NEW_LINES)
+ and !empty($old_files))
+ {
+ array_push($old_files, $file);
+ foreach($old_files as $old_file)
+ {
+ $path = PHPWG_ROOT_PATH.$old_file;
+ if (is_file($path))
+ {
+ @unlink($path);
+ }
+ elseif (is_dir($path))
+ {
+ self::deltree($path, true);
+ }
+ }
+ }
+ }
+
+ function dump_database($include_history=false)
+ {
+ global $page, $conf, $cfgBase;
+
+ if (version_compare(PHPWG_VERSION, '2.1', '<'))
+ {
+ $conf['db_base'] = $cfgBase;
+ }
+
+ include(PHPWG_ROOT_PATH.'admin/include/mysqldump.php');
+
+ $path = $conf['local_data_dir'].'/update';
+
+ if (@mkgetdir($path)
+ and ($backupFile = tempnam($path, 'sql'))
+ and ($dumper = new MySQLDump($conf['db_base'],$backupFile,false,false)))
+ {
+ foreach (get_defined_constants() as $constant => $value)
+ {
+ if (preg_match('/_TABLE$/', $constant))
+ {
+ $dumper->getTableStructure($value);
+ if ($constant == 'HISTORY_TABLE' and !$include_history)
+ {
+ continue;
+ }
+ $dumper->getTableData($value);
+ }
+ }
+ }
+
+ if (@filesize($backupFile))
+ {
+ $http_headers = array(
+ 'Content-Length: '.@filesize($backupFile),
+ 'Content-Type: text/x-sql',
+ 'Content-Disposition: attachment; filename="database.sql";',
+ 'Content-Transfer-Encoding: binary',
+ );
+
+ foreach ($http_headers as $header) {
+ header($header);
+ }
+
+ @readfile($backupFile);
+ self::deltree($conf['local_data_dir'].'/update');
+ exit();
+ }
+ else
+ {
+ array_push($page['errors'], l10n('Unable to dump database.'));
+ }
+ }
+
+ function upgrade_to($upgrade_to, &$step)
+ {
+ global $page, $conf, $template;
+
+ if (!version_compare($_POST['upgrade_to'], PHPWG_VERSION, '>'))
+ {
+ redirect(get_root_url().'admin.php?page=plugin-'.basename(dirname(__FILE__)));
+ }
+
+ if ($step == 2)
+ {
+ preg_match('/(\d+\.\d+)\.(\d+)/', PHPWG_VERSION, $matches);
+ $code = $matches[1].'.x_to_'.$_POST['upgrade_to'];
+ $dl_code = str_replace(array('.', '_'), '', $code);
+ $remove_path = $code;
+ $obsolete_list = 'obsolete.list';
+ }
+ else
+ {
+ $code = $_POST['upgrade_to'];
+ $dl_code = $code;
+ $remove_path = version_compare($code, '2.0.8', '>=') ? 'piwigo' : 'piwigo-'.$code;
+ $obsolete_list = PHPWG_ROOT_PATH.'install/obsolete.list';
+ }
+
+ if (empty($page['errors']))
+ {
+ $path = $conf['local_data_dir'].'/update';
+ $filename = $path.'/'.$code.'.zip';
+ @mkgetdir($path);
+
+ $chunk_num = 0;
+ $end = false;
+ $zip = @fopen($filename, 'w');
+ while (!$end)
+ {
+ $chunk_num++;
+ if (@fetchRemote(PHPWG_URL.'/download/dlcounter.php?code='.$dl_code.'&chunk_num='.$chunk_num, $result)
+ and $input = @unserialize($result))
+ {
+ if (0 == $input['remaining'])
+ {
+ $end = true;
+ }
+ @fwrite($zip, base64_decode($input['data']));
+ }
+ else
+ {
+ $end = true;
+ }
+ }
+ @fclose($zip);
+
+ if (@filesize($filename))
+ {
+ $zip = new PclZip($filename);
+ if ($result = $zip->extract(PCLZIP_OPT_PATH, PHPWG_ROOT_PATH,
+ PCLZIP_OPT_REMOVE_PATH, $remove_path,
+ PCLZIP_OPT_SET_CHMOD, 0755,
+ PCLZIP_OPT_REPLACE_NEWER))
+ {
+ //Check if all files were extracted
+ $error = '';
+ foreach($result as $extract)
+ {
+ if (!in_array($extract['status'], array('ok', 'filtered', 'already_a_directory')))
+ {
+ // Try to change chmod and extract
+ if (@chmod(PHPWG_ROOT_PATH.$extract['filename'], 0777)
+ and ($res = $zip->extract(PCLZIP_OPT_BY_NAME, $remove_path.'/'.$extract['filename'],
+ PCLZIP_OPT_PATH, PHPWG_ROOT_PATH,
+ PCLZIP_OPT_REMOVE_PATH, $remove_path,
+ PCLZIP_OPT_SET_CHMOD, 0755,
+ PCLZIP_OPT_REPLACE_NEWER))
+ and isset($res[0]['status'])
+ and $res[0]['status'] == 'ok')
+ {
+ continue;
+ }
+ else
+ {
+ $error .= $extract['filename'].': '.$extract['status']."\n";
+ }
+ }
+ }
+
+ if (empty($error))
+ {
+ self::obsolete_list($obsolete_list);
+ self::deltree($conf['local_data_dir'].'/update');
+ invalidate_user_cache(true);
+ $template->delete_compiled_templates();
+ unset($_SESSION['need_update']);
+ if ($step == 2)
+ {
+ array_push($page['infos'], sprintf(l10n('autoupdate_success'), $upgrade_to));
+ $step = -1;
+ }
+ else
+ {
+ redirect(PHPWG_ROOT_PATH.'upgrade.php?now=');
+ }
+ }
+ else
+ {
+ file_put_contents($conf['local_data_dir'].'/update/log_error.txt', $error);
+ $relative_path = trim(str_replace(dirname(dirname(dirname(dirname(__FILE__)))), '', $conf['local_data_dir']), '/\\');
+ array_push($page['errors'], sprintf(l10n('autoupdate_extract_fail'), PHPWG_ROOT_PATH.$relative_path.'/update/log_error.txt'));
+ }
+ }
+ else
+ {
+ self::deltree($conf['local_data_dir'].'/update');
+ array_push($page['errors'], l10n('autoupdate_fail'));
+ }
+ }
+ else
+ {
+ array_push($page['errors'], l10n('Piwigo cannot retrieve upgrade file from server'));
+ }
+ }
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/admin/themes/default/images/ajax-loader-bar.gif b/admin/themes/default/images/ajax-loader-bar.gif
new file mode 100644
index 000000000..d84f65378
Binary files /dev/null and b/admin/themes/default/images/ajax-loader-bar.gif differ
diff --git a/admin/themes/default/template/admin.tpl b/admin/themes/default/template/admin.tpl
index 2daad8118..56a92a75e 100644
--- a/admin/themes/default/template/admin.tpl
+++ b/admin/themes/default/template/admin.tpl
@@ -75,6 +75,7 @@ jQuery(document).ready(function(){ldelim}
{/if}
{'Maintenance'|@translate}
{'Pending Comments'|@translate}
+ {'Updates'|@translate}
diff --git a/admin/themes/default/template/updates_ext.tpl b/admin/themes/default/template/updates_ext.tpl
new file mode 100644
index 000000000..d0cd7a2a7
--- /dev/null
+++ b/admin/themes/default/template/updates_ext.tpl
@@ -0,0 +1,272 @@
+{combine_script id='jquery.ajaxmanager' load='footer' require='jquery' path='themes/default/js/plugins/jquery.ajaxmanager.js'}
+{combine_script id='jquery.jgrowl' load='footer' require='jquery' path='themes/default/js/plugins/jquery.jgrowl_minimized.js'}
+{combine_css path="admin/themes/default/uploadify.jGrowl.css"}
+
+{footer_script require='jquery.effects.blind,jquery.ajaxmanager,jquery.jgrowl'}
+var pwg_token = '{$PWG_TOKEN}';
+var extList = new Array();
+var confirmMsg = '{'Are you sure?'|@translate|@escape:'javascript'}';
+var errorHead = '{'ERROR'|@translate|@escape:'javascript'}';
+var successHead = '{'Update Complete'|@translate|@escape:'javascript'}';
+var errorMsg = '{'an error happened'|@translate|@escape:'javascript'}';
+var restoreMsg = '{'Reset ignored updates'|@translate|@escape:'javascript'}';
+
+{literal}
+var todo = 0;
+var queuedManager = $.manageAjax.create('queued', {
+ queue: true,
+ maxRequests: 1,
+ beforeSend: function() { autoupdate_bar_toggle(1); },
+ complete: function() { autoupdate_bar_toggle(-1); }
+});
+
+function updateAll() {
+ if (confirm(confirmMsg)) {
+ jQuery('.updateExtension').each( function() {
+ if (jQuery(this).parents('div').css('display') == 'block')
+ jQuery(this).click();
+ });
+ }
+};
+
+function resetIgnored() {
+ jQuery.ajax({
+ type: 'GET',
+ url: 'ws.php',
+ dataType: 'json',
+ data: { method: 'pwg.extensions.ignoreUpdate', reset: true, pwg_token: pwg_token, format: 'json' },
+ success: function(data) {
+ if (data['stat'] == 'ok') {
+ jQuery(".pluginBox, fieldset").show();
+ jQuery("#update_all").show();
+ jQuery("#up_to_date").hide();
+ jQuery("#reset_ignore").hide();
+ jQuery("#ignored").hide();
+ checkFieldsets();
+ }
+ }
+ });
+};
+
+function checkFieldsets() {
+ var types = new Array('plugins', 'themes', 'languages');
+ var total = 0;
+ var ignored = 0;
+ for (i=0;i<3;i++) {
+ nbExtensions = 0;
+ jQuery("div[id^='"+types[i]+"_']").each(function(index) {
+ if (jQuery(this).css('display') == 'block')
+ nbExtensions++;
+ else
+ ignored++;
+ });
+ total = total + nbExtensions;
+ if (nbExtensions == 0)
+ jQuery("#"+types[i]).hide();
+ }
+
+ if (total == 0) {
+ jQuery("#update_all").hide();
+ jQuery("#up_to_date").show();
+ }
+ if (ignored > 0) {
+ jQuery("#reset_ignore").val(restoreMsg + ' (' + ignored + ')');
+ }
+};
+
+function updateExtension(type, id, revision) {
+ queuedManager.add({
+ type: 'GET',
+ dataType: 'json',
+ url: 'ws.php',
+ data: { method: 'pwg.extensions.update', type: type, id: id, revision: revision, pwg_token: pwg_token, format: 'json' },
+ success: function(data) {
+ if (data['stat'] == 'ok') {
+ jQuery.jGrowl( data['result'], { theme: 'success', header: successHead, life: 4000, sticky: false });
+ jQuery("#"+type+"_"+id).remove();
+ checkFieldsets();
+ } else {
+ jQuery.jGrowl( data['result'], { theme: 'error', header: errorHead, sticky: true });
+ }
+ },
+ error: function(data) {
+ jQuery.jGrowl( errorMsg, { theme: 'error', header: errorHead, sticky: true });
+ }
+ });
+};
+
+function ignoreExtension(type, id) {
+ jQuery.ajax({
+ type: 'GET',
+ url: 'ws.php',
+ dataType: 'json',
+ data: { method: 'pwg.extensions.ignoreUpdate', type: type, id: id, pwg_token: pwg_token, format: 'json' },
+ success: function(data) {
+ if (data['stat'] == 'ok') {
+ jQuery("#"+type+"_"+id).hide();
+ jQuery("#reset_ignore").show();
+ checkFieldsets();
+ }
+ }
+ });
+};
+
+function autoupdate_bar_toggle(i) {
+ todo = todo + i;
+ if ((i == 1 && todo == 1) || (i == -1 && todo == 0))
+ jQuery('.autoupdate_bar').toggle();
+}
+
+jQuery(document).ready(function() {
+ jQuery("td[id^='desc_'], p[id^='revdesc_']").click(function() {
+ id = this.id.split('_');
+ jQuery("#revdesc_"+id[1]).toggle('blind');
+ jQuery(".button_"+id[1]).toggle();
+ return false;
+ });
+});
+
+checkFieldsets();
+{/literal}
+{/footer_script}
+
+
+
{'Updates'|@translate}
+
+
+
+
+
+
+
+
+{'Update in progress... Please wait.'|@translate}
+
+
+{'All extensions are up to date.'|@translate}
+
+{if not empty($update_plugins)}
+
+
+{'Plugins'|@translate}
+{foreach from=$update_plugins item=plugin name=plugins_loop}
+
+
+
+
+ {$plugin.EXT_NAME}
+
+
+ {'Install'|@translate}
+ | {'Download'|@translate}
+ | {'Ignore this update'|@translate}
+
+
+
+
+ {'Version'|@translate} {$plugin.CURRENT_VERSION}
+
+
+ {'Downloads'|@translate}: {$plugin.DOWNLOADS}
+
+
+ {'New Version'|@translate} : {$plugin.NEW_VERSION}
+ | {'By %s'|@translate|@sprintf:$plugin.AUTHOR}
+
+
+
+
+
+ {$plugin.REV_DESC|htmlspecialchars|nl2br}
+
+
+
+
+{/foreach}
+
+
+{/if}
+
+{if not empty($update_themes)}
+
+
+{'Themes'|@translate}
+{foreach from=$update_themes item=theme name=themes_loop}
+
+
+
+
+ {$theme.EXT_NAME}
+
+
+ {'Install'|@translate}
+ | {'Download'|@translate}
+ | {'autoupdate_ignore'|@translate}
+
+
+
+
+ {'Version'|@translate} {$theme.CURRENT_VERSION}
+
+
+ {'Downloads'|@translate}: {$theme.DOWNLOADS}
+
+
+ {'New Version'|@translate} : {$theme.NEW_VERSION}
+ | {'By %s'|@translate|@sprintf:$theme.AUTHOR}
+
+
+
+
+
+ {$theme.REV_DESC|htmlspecialchars|nl2br}
+
+
+
+
+{/foreach}
+
+
+{/if}
+
+{if not empty($update_languages)}
+
+
+{'Languages'|@translate}
+{foreach from=$update_languages item=language name=languages_loop}
+
+
+
+
+ {$language.EXT_NAME}
+
+
+ {'Install'|@translate}
+ | {'Download'|@translate}
+ | {'autoupdate_ignore'|@translate}
+
+
+
+
+ {'Version'|@translate} {$language.CURRENT_VERSION}
+
+
+ {'Downloads'|@translate}: {$language.DOWNLOADS}
+
+
+ {'New Version'|@translate} : {$language.NEW_VERSION}
+ | {'By %s'|@translate|@sprintf:$language.AUTHOR}
+
+
+
+
+
+ {$language.REV_DESC|htmlspecialchars|nl2br}
+
+
+
+
+{/foreach}
+
+
+{/if}
diff --git a/admin/themes/default/template/updates_pwg.tpl b/admin/themes/default/template/updates_pwg.tpl
new file mode 100644
index 000000000..c85e1fb6b
--- /dev/null
+++ b/admin/themes/default/template/updates_pwg.tpl
@@ -0,0 +1,99 @@
+{footer_script}
+jQuery(document).ready(function() {ldelim}
+ jQuery('input[name="submit"]').click(function() {ldelim}
+ if(!confirm('{'autoupdate_alert'|@translate}'))
+ return false;
+ jQuery(this).hide();
+ jQuery('.autoupdate_bar').show();
+ });
+ jQuery('[name="understand"]').click(function() {ldelim}
+ jQuery('[name="submit"]').attr('disabled', !this.checked);
+ });
+});
+{/footer_script}
+
+{html_head}
+{literal}
+
+{/literal}
+{/html_head}
+
+
+
{'Updates'|@translate}
+
+
+{if $STEP == 0}
+ {if $CHECK_VERSION}
+ {'You are running the latest version of Piwigo.'|@translate}
+ {elseif $DEV_VERSION}
+ {'You are running on development sources, no check possible.'|@translate}
+ {else}
+ {'Check for update failed for unknown reasons.'|@translate}
+ {/if}
+{/if}
+
+{if $STEP == 1}
+{'Two updates are available'|@translate}:
+
+
+
+{'You can update to Piwigo %s directly, without upgrading to Piwigo %s (recommended).'|@translate|@sprintf:$MAJOR_VERSION:$MINOR_VERSION}
+{/if}
+
+{if $STEP == 2}
+
+ {'A new version of Piwigo is available.'|@translate}
+ {'This is a minor update, with only bug corrections.'|@translate}
+
+
+{/if}
+
+{if $STEP == 3}
+
+ {'A new version of Piwigo is available.'|@translate}
+ {'This is a major update, with new exciting features .'|@translate|@sprintf:$RELEASE_URL} {'Some themes and plugins may be not available yet.'|@translate}
+
+
+{/if}
\ No newline at end of file
diff --git a/admin/updates.php b/admin/updates.php
new file mode 100644
index 000000000..97c56a2cd
--- /dev/null
+++ b/admin/updates.php
@@ -0,0 +1,44 @@
+add('pwg', l10n('Piwigo Update'), $my_base_url);
+$tabsheet->add('ext', l10n('Extensions Update'), $my_base_url.'&tab=ext');
+$tabsheet->select($page['tab']);
+$tabsheet->assign();
+
+include(PHPWG_ROOT_PATH.'admin/updates_'.$page['tab'].'.php');
+
+?>
\ No newline at end of file
diff --git a/admin/updates_ext.php b/admin/updates_ext.php
new file mode 100644
index 000000000..4ce47b83f
--- /dev/null
+++ b/admin/updates_ext.php
@@ -0,0 +1,86 @@
+get_server_extensions())
+{
+ array_push($page['errors'], l10n('Can\'t connect to server.'));
+ return;
+}
+
+foreach ($autoupdate->types as $type)
+{
+ $fs = 'fs_'.$type;
+ $server = 'server_'.$type;
+ $server_ext = $autoupdate->$type->$server;
+ $fs_ext = $autoupdate->$type->$fs;
+
+ if (empty($server_ext))
+ {
+ continue;
+ }
+
+ foreach($fs_ext as $ext_id => $fs_ext)
+ {
+ if (!isset($fs_ext['extension']) or !isset($server_ext[$fs_ext['extension']]))
+ {
+ continue;
+ }
+
+ $ext_info = $server_ext[$fs_ext['extension']];
+
+ if (!$autoupdate->version_compare($fs_ext['version'], $ext_info['revision_name'], $type))
+ {
+ $template->append('update_'.$type, array(
+ 'ID' => $ext_info['extension_id'],
+ 'REVISION_ID' => $ext_info['revision_id'],
+ 'EXT_ID' => $ext_id,
+ 'EXT_NAME' => $fs_ext['name'],
+ 'EXT_URL' => PEM_URL.'/extension_view.php?eid='.$ext_info['extension_id'],
+ 'EXT_DESC' => trim($ext_info['extension_description'], " \n\r"),
+ 'REV_DESC' => trim($ext_info['revision_description'], " \n\r"),
+ 'CURRENT_VERSION' => $fs_ext['version'],
+ 'NEW_VERSION' => $ext_info['revision_name'],
+ 'AUTHOR' => $ext_info['author_name'],
+ 'DOWNLOADS' => $ext_info['extension_nb_downloads'],
+ 'URL_DOWNLOAD' => $ext_info['download_url'] . '&origin=piwigo_download',
+ 'IGNORED' => in_array($ext_id, $conf['updates_ignored'][$type]),
+ )
+ );
+ }
+ }
+}
+
+$template->assign('SHOW_RESET', (!empty($conf['updates_ignored']['plugins']) or !empty($conf['updates_ignored']['themes']) or !empty($conf['updates_ignored']['languages'])));
+$template->assign('PWG_TOKEN', get_pwg_token());
+$template->set_filename('plugin_admin_content', 'updates_ext.tpl');
+$template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
+
+?>
\ No newline at end of file
diff --git a/admin/updates_pwg.php b/admin/updates_pwg.php
new file mode 100644
index 000000000..016deeecd
--- /dev/null
+++ b/admin/updates_pwg.php
@@ -0,0 +1,166 @@
+ user may choose upgrade.
+2 = upgrade on same branch
+3 = upgrade on different branch
+*/
+$step = isset($_GET['step']) ? $_GET['step'] : 0;
+$upgrade_to = isset($_GET['to']) ? $_GET['to'] : '';
+
+// +-----------------------------------------------------------------------+
+// | Step 0 |
+// +-----------------------------------------------------------------------+
+if ($step == 0)
+{
+ $template->assign(array(
+ 'CHECK_VERSION' => false,
+ 'DEV_VERSION' => false,
+ )
+ );
+
+ if (preg_match('/(\d+\.\d+)\.(\d+)/', PHPWG_VERSION, $matches))
+ {
+ $url = PHPWG_URL.'/download/all_versions.php';
+ $url .= '?rand='.md5(uniqid(rand(), true)); // Avoid server cache
+
+ if (@fetchRemote($url, $result)
+ and $all_versions = @explode("\n", $result)
+ and is_array($all_versions))
+ {
+ $template->assign('CHECK_VERSION', true);
+
+ $last_version = trim($all_versions[0]);
+ $upgrade_to = $last_version;
+
+ if (version_compare(PHPWG_VERSION, $last_version, '<'))
+ {
+ $new_branch = preg_replace('/(\d+\.\d+)\.\d+/', '$1', $last_version);
+ $actual_branch = $matches[1];
+
+ if ($new_branch == $actual_branch)
+ {
+ $step = 2;
+ }
+ else
+ {
+ $step = 3;
+
+ // Check if new version exists in same branch
+ foreach ($all_versions as $version)
+ {
+ $new_branch = preg_replace('/(\d+\.\d+)\.\d+/', '$1', $version);
+
+ if ($new_branch == $actual_branch)
+ {
+ if (version_compare(PHPWG_VERSION, $version, '<'))
+ {
+ $step = 1;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ $template->assign('DEV_VERSION', true);
+ }
+}
+
+// +-----------------------------------------------------------------------+
+// | Step 1 |
+// +-----------------------------------------------------------------------+
+if ($step == 1)
+{
+ $template->assign(array(
+ 'MINOR_VERSION' => $version,
+ 'MAJOR_VERSION' => $last_version,
+ )
+ );
+}
+
+// +-----------------------------------------------------------------------+
+// | Step 2 |
+// +-----------------------------------------------------------------------+
+if ($step == 2 and is_webmaster())
+{
+ if (isset($_POST['submit']) and isset($_POST['upgrade_to']))
+ {
+ updates::upgrade_to($_POST['upgrade_to'], $step);
+ }
+}
+
+// +-----------------------------------------------------------------------+
+// | Step 3 |
+// +-----------------------------------------------------------------------+
+if ($step == 3 and is_webmaster())
+{
+ if (isset($_POST['dumpDatabase']))
+ {
+ updates::dump_database(isset($_POST['includeHistory']));
+ }
+
+ if (isset($_POST['submit']) and isset($_POST['upgrade_to']))
+ {
+ updates::upgrade_to($_POST['upgrade_to'], $step);
+ }
+
+ $updates = new updates();
+ $updates->get_merged_extensions($upgrade_to);
+ $updates->get_server_extensions($upgrade_to);
+ $template->assign('missing', $updates->missing);
+}
+
+// +-----------------------------------------------------------------------+
+// | Process template |
+// +-----------------------------------------------------------------------+
+
+if (!is_webmaster())
+{
+ array_push($page['errors'], l10n('Webmaster status is required.'));
+}
+
+$template->assign(array(
+ 'STEP' => $step,
+ 'PHPWG_VERSION' => PHPWG_VERSION,
+ 'UPGRADE_TO' => $upgrade_to,
+ 'RELEASE_URL' => PHPWG_URL.'/releases/'.$upgrade_to,
+ )
+);
+
+$template->set_filename('plugin_admin_content', 'updates_pwg.tpl');
+$template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
+
+?>
\ No newline at end of file
--
cgit v1.2.3