diff options
author | patdenice <patdenice@piwigo.org> | 2011-04-20 14:52:52 +0000 |
---|---|---|
committer | patdenice <patdenice@piwigo.org> | 2011-04-20 14:52:52 +0000 |
commit | 491e8adc7467de9f9aa6dbbebfcb8b82c676b46a (patch) | |
tree | aad72cf4b73fa2bd6ffb6e91c174d18547410741 | |
parent | fede13ce419b40ca22cf58b76f74d44d6d564dac (diff) |
feature:2271
Merge autoupdate plugin into piwigo core.
git-svn-id: http://piwigo.org/svn/trunk@10511 68402e56-0260-453c-a942-63ccdbb3a9ee
-rw-r--r-- | admin.php | 1 | ||||
-rw-r--r-- | admin/include/functions.php | 1 | ||||
-rw-r--r-- | admin/include/mysqldump.php | 421 | ||||
-rw-r--r-- | admin/include/updates.class.php | 481 | ||||
-rw-r--r-- | admin/themes/default/images/ajax-loader-bar.gif | bin | 0 -> 10819 bytes | |||
-rw-r--r-- | admin/themes/default/template/admin.tpl | 1 | ||||
-rw-r--r-- | admin/themes/default/template/updates_ext.tpl | 272 | ||||
-rw-r--r-- | admin/themes/default/template/updates_pwg.tpl | 99 | ||||
-rw-r--r-- | admin/updates.php | 44 | ||||
-rw-r--r-- | admin/updates_ext.php | 86 | ||||
-rw-r--r-- | admin/updates_pwg.php | 166 | ||||
-rw-r--r-- | include/ws_functions.inc.php | 136 | ||||
-rw-r--r-- | install/config.sql | 1 | ||||
-rw-r--r-- | install/db/103-database.php | 42 | ||||
-rw-r--r-- | language/en_UK/admin.lang.php | 26 | ||||
-rw-r--r-- | language/fr_FR/admin.lang.php | 26 | ||||
-rw-r--r-- | ws.php | 27 |
17 files changed, 1830 insertions, 0 deletions
@@ -168,6 +168,7 @@ $template->assign( 'U_ADD_PHOTOS' => $link_start.'photos_add', 'U_CHANGE_THEME' => PHPWG_ROOT_PATH.'admin.php?change_theme=1', 'U_PENDING_COMMENTS' => $link_start.'comments', + 'U_UPDATES' => $link_start.'updates', ) ); 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 @@ +<?php
+/**
+* Dump MySQL database
+*
+* Here is an inline example:
+* <code>
+* $connection = @mysql_connect($dbhost,$dbuser,$dbpsw);
+* $dumper = new MySQLDump($dbname,'filename.sql',false,false);
+* $dumper->doDump();
+* </code>
+*
+* Special thanks to:
+* - Andrea Ingaglio <andrea@coders4fun.com> 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 Viganò - CreativeFactory.it <daniele.vigano@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 @@ +<?php
+
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+class updates
+{
+ var $types = array();
+ var $plugins;
+ var $themes;
+ var $languages;
+ var $missing = array();
+ var $default_plugins = array();
+ var $default_themes = array();
+ var $default_languages = array();
+ var $merged_extensions = array();
+ var $merged_extension_url = 'http://piwigo.org/download/merged_extensions.txt';
+
+ function __construct()
+ {
+ $this->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 Binary files differnew file mode 100644 index 000000000..d84f65378 --- /dev/null +++ b/admin/themes/default/images/ajax-loader-bar.gif 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} <li><a href="{$U_MAINTENANCE}">{'Maintenance'|@translate}</a></li> <li><a href="{$U_PENDING_COMMENTS}">{'Pending Comments'|@translate}</a></li> + <li><a href="{$U_UPDATES}">{'Updates'|@translate}</a></li> </ul> </dd> </dl> 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} + +<div class="titrePage"> + <h2>{'Updates'|@translate}</h2> +</div> + +<div class="autoupdate_bar"> +<br> +<input type="submit" id="update_all" value="{'Update All'|@translate}" onClick="updateAll(); return false;"> +<input type="submit" id="reset_ignore" value="{'Reset ignored updates'|@translate}" onClick="resetIgnored(); return false;" {if !$SHOW_RESET}style="display:none;"{/if}> +</div> +<div class="autoupdate_bar" style="display:none;"> +{'Update in progress... Please wait.'|@translate}<br><img src="admin/themes/default/images/ajax-loader-bar.gif"> +</div> + +<p id="up_to_date" style="display:none; text-align:left; margin-left:20px;">{'All extensions are up to date.'|@translate}</p> + +{if not empty($update_plugins)} +<div> +<fieldset id="plugins"> +<legend>{'Plugins'|@translate}</legend> +{foreach from=$update_plugins item=plugin name=plugins_loop} +<div class="pluginBox" id="plugins_{$plugin.EXT_ID}" {if $plugin.IGNORED}style="display:none;"{/if}> + <table> + <tr> + <td class="pluginBoxNameCell"> + {$plugin.EXT_NAME} + </td> + <td> + <a href="#" onClick="updateExtension('plugins', '{$plugin.EXT_ID}', {$plugin.REVISION_ID});" class="updateExtension">{'Install'|@translate}</a> + | <a href="{$plugin.URL_DOWNLOAD}">{'Download'|@translate}</a> + | <a href="#" onClick="ignoreExtension('plugins', '{$plugin.EXT_ID}'); return false;">{'Ignore this update'|@translate}</a> + </td> + </tr> + <tr> + <td> + {'Version'|@translate} {$plugin.CURRENT_VERSION} + </td> + <td class="pluginDesc" id="desc_{$plugin.ID}"> + <em>{'Downloads'|@translate}: {$plugin.DOWNLOADS}</em> + <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/plus.gif" alt="" class="button_{$plugin.ID}"> + <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/minus.gif" alt="" class="button_{$plugin.ID}" style="display:none;"> + {'New Version'|@translate} : {$plugin.NEW_VERSION} + | {'By %s'|@translate|@sprintf:$plugin.AUTHOR} + </td> + </tr> + <tr> + <td></td> + <td class="pluginDesc"> + <p id="revdesc_{$plugin.ID}" style="display:none;">{$plugin.REV_DESC|htmlspecialchars|nl2br}</p> + </td> + </tr> + </table> +</div> +{/foreach} +</fieldset> +</div> +{/if} + +{if not empty($update_themes)} +<div> +<fieldset id="themes"> +<legend>{'Themes'|@translate}</legend> +{foreach from=$update_themes item=theme name=themes_loop} +<div class="pluginBox" id="themes_{$theme.EXT_ID}" {if $theme.IGNORED}style="display:none;"{/if}> + <table> + <tr> + <td class="pluginBoxNameCell"> + {$theme.EXT_NAME} + </td> + <td> + <a href="#" onClick="updateExtension('themes', '{$theme.EXT_ID}', {$theme.REVISION_ID});" class="updateExtension">{'Install'|@translate}</a> + | <a href="{$theme.URL_DOWNLOAD}">{'Download'|@translate}</a> + | <a href="#" onClick="ignoreExtension('themes', '{$theme.EXT_ID}'); return false;">{'autoupdate_ignore'|@translate}</a> + </td> + </tr> + <tr> + <td> + {'Version'|@translate} {$theme.CURRENT_VERSION} + </td> + <td class="pluginDesc" id="desc_{$theme.ID}"> + <em>{'Downloads'|@translate}: {$theme.DOWNLOADS}</em> + <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/plus.gif" alt="" class="button_{$theme.ID}"> + <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/minus.gif" alt="" class="button_{$theme.ID}" style="display:none;"> + {'New Version'|@translate} : {$theme.NEW_VERSION} + | {'By %s'|@translate|@sprintf:$theme.AUTHOR} + </td> + </tr> + <tr> + <td></td> + <td class="pluginDesc"> + <p id="revdesc_{$theme.ID}" style="display:none;">{$theme.REV_DESC|htmlspecialchars|nl2br}</p> + </td> + </tr> + </table> +</div> +{/foreach} +</fieldset> +</div> +{/if} + +{if not empty($update_languages)} +<div> +<fieldset id="languages"> +<legend>{'Languages'|@translate}</legend> +{foreach from=$update_languages item=language name=languages_loop} +<div class="pluginBox" id="languages_{$language.EXT_ID}" {if $language.IGNORED}style="display:none;"{/if}> + <table> + <tr> + <td class="pluginBoxNameCell"> + {$language.EXT_NAME} + </td> + <td> + <a href="#" onClick="updateExtension('languages', '{$language.EXT_ID}', {$language.REVISION_ID});" class="updateExtension">{'Install'|@translate}</a> + | <a href="{$language.URL_DOWNLOAD}">{'Download'|@translate}</a> + | <a href="#" onClick="ignoreExtension('languages', '{$language.EXT_ID}'); return false;">{'autoupdate_ignore'|@translate}</a> + </td> + </tr> + <tr> + <td> + {'Version'|@translate} {$language.CURRENT_VERSION} + </td> + <td class="pluginDesc" id="desc_{$language.ID}"> + <em>{'Downloads'|@translate}: {$language.DOWNLOADS}</em> + <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/plus.gif" alt="" class="button_{$language.ID}"> + <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/minus.gif" alt="" class="button_{$language.ID}" style="display:none;"> + {'New Version'|@translate} : {$language.NEW_VERSION} + | {'By %s'|@translate|@sprintf:$language.AUTHOR} + </td> + </tr> + <tr> + <td></td> + <td class="pluginDesc"> + <p id="revdesc_{$language.ID}" style="display:none;">{$language.REV_DESC|htmlspecialchars|nl2br}</p> + </td> + </tr> + </table> +</div> +{/foreach} +</fieldset> +</div> +{/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} +<style type="text/css"> +form { width: 750px; } +fieldset { padding-bottom: 30px; } +p, form p { text-align: left; margin-left:20px; } +li { margin: 5px; } +</style> +{/literal} +{/html_head} + +<div class="titrePage"> +<h2>{'Updates'|@translate}</h2> +</div> + +{if $STEP == 0} + {if $CHECK_VERSION} + <p>{'You are running the latest version of Piwigo.'|@translate}</p> + {elseif $DEV_VERSION} + <p>{'You are running on development sources, no check possible.'|@translate}</p> + {else} + <p>{'Check for update failed for unknown reasons.'|@translate}</p> + {/if} +{/if} + +{if $STEP == 1} +<h4>{'Two updates are available'|@translate}:</h4> +<p> +<ul> + <li><a href="admin.php?page=updates&step=2&to={$MINOR_VERSION}"><strong>{'Update to Piwigo %s'|@translate|@sprintf:$MINOR_VERSION}</strong></a>: {'This is a minor update, with only bug corrections.'|@translate}</li> + <li><a href="admin.php?page=updates&step=3&to={$MAJOR_VERSION}"><strong>{'Update to Piwigo %s'|@translate|@sprintf:$MAJOR_VERSION}</strong></a>: {'This is a major update, with <a href="%s">new exciting features</a>.'|@translate|@sprintf:$RELEASE_URL} {'Some themes and plugins may be not available yet.'|@translate}</li> +</ul> +</p> +<p>{'You can update to Piwigo %s directly, without upgrading to Piwigo %s (recommended).'|@translate|@sprintf:$MAJOR_VERSION:$MINOR_VERSION}</p> +{/if} + +{if $STEP == 2} +<p> + {'A new version of Piwigo is available.'|@translate}<br> + {'This is a minor update, with only bug corrections.'|@translate} +</p> +<form action="" method="post"> +<p><input type="submit" name="submit" value="{'Update to Piwigo %s'|@translate|@sprintf:$UPGRADE_TO}"></p> +<p class="autoupdate_bar" style="display:none;"> {'Update in progress...'|@translate}<br><img src="admin/themes/default/images/ajax-loader-bar.gif"></p> +<p><input type="hidden" name="upgrade_to" value="{$UPGRADE_TO}"></p> +</form> +{/if} + +{if $STEP == 3} +<p> + {'A new version of Piwigo is available.'|@translate}<br> + {'This is a major update, with <a href="%s">new exciting features</a>.'|@translate|@sprintf:$RELEASE_URL} {'Some themes and plugins may be not available yet.'|@translate} +</p> +<form action="" method="post"> + +{counter assign=i} +<fieldset> + <legend>{'Dump Database'|@translate}</legend> + <p><input type="checkbox" name="includeHistory"> {'Include history data (Warning: server memory limit may be exceeded)'|@translate}</p> + <p><input type="submit" name="dumpDatabase" value="{'Dump Database'|@translate}"></p> +</fieldset> + +{counter assign=i} +<fieldset> + <legend>{'Update to Piwigo %s'|@translate|@sprintf:$UPGRADE_TO}</legend> + {if !empty($missing.plugins)} + <p><i>{'Following plugins may not be compatible with the new version of Piwigo:'|@translate}</i></p> + <p><ul>{foreach from=$missing.plugins item=plugin}<li><a href="{$plugin.uri}" class="externalLink">{$plugin.name}</a></li>{/foreach}</ul><br></p> + {/if} + {if !empty($missing.themes)} + <p><i>{'Following themes may not be compatible with the new version of Piwigo:'|@translate}</i></p> + <p><ul>{foreach from=$missing.themes item=theme}<li><a href="{$theme.uri}" class="externalLink">{$theme.name}</a></li>{/foreach}</ul><br></p> + {/if} + <p> + {if !empty($missing.plugins) or !empty($missing.themes)} + <p><label><input type="checkbox" name="understand"> {'I decide to update anyway'|@translate}</label></p> + {/if} + <p><input type="submit" name="submit" value="{'Update to Piwigo %s'|@translate|@sprintf:$UPGRADE_TO}" {if !empty($missing.plugins) or !empty($missing.themes)}disabled="disabled"{/if}> + </p> + <p class="autoupdate_bar" style="display:none;"> {'Update in progress...'|@translate}<br><img src="admin/themes/default/images/ajax-loader-bar.gif"></p> +</fieldset> + +<p><input type="hidden" name="upgrade_to" value="{$UPGRADE_TO}"></p> +</form> +{/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 @@ +<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2010 Pierrick LE GALL http://piwigo.org |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+ die ("Hacking attempt!");
+}
+
+include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
+
+$my_base_url = get_root_url().'admin.php?page=updates';
+
+if (isset($_GET['tab']))
+ $page['tab'] = $_GET['tab'];
+else
+ $page['tab'] = 'pwg';
+
+$tabsheet = new tabsheet();
+$tabsheet->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 @@ +<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2010 Pierrick LE GALL http://piwigo.org |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+ die ("Hacking attempt!");
+}
+
+$conf['updates_ignored'] = unserialize($conf['updates_ignored']);
+
+include_once(PHPWG_ROOT_PATH.'admin/include/updates.class.php');
+$autoupdate = new updates();
+
+if (!$autoupdate->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 @@ +<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2010 Pierrick LE GALL http://piwigo.org |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+ die ("Hacking attempt!");
+}
+
+include_once(PHPWG_ROOT_PATH.'admin/include/updates.class.php');
+include_once(PHPWG_ROOT_PATH.'admin/include/pclzip.lib.php');
+
+/*
+STEP:
+0 = check is needed. If version is latest or check fail, we stay on step 0
+1 = new version on same branch AND new branch are available => 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 diff --git a/include/ws_functions.inc.php b/include/ws_functions.inc.php index 0bf39d61b..0aaa5f561 100644 --- a/include/ws_functions.inc.php +++ b/include/ws_functions.inc.php @@ -2735,4 +2735,140 @@ WHERE id = '.(int)$params['image_id'].' } return false; } + +function ws_extensions_update($params, &$service) +{ + if (!is_webmaster()) + { + return new PwgError(401, l10n('Webmaster status is required.')); + } + + if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token']) + { + return new PwgError(403, 'Invalid security token'); + } + + if (empty($params['type']) or !in_array($params['type'], array('plugins', 'themes', 'languages'))) + { + return new PwgError(403, "invalid extension type"); + } + + if (empty($params['id']) or empty($params['revision'])) + { + return new PwgError(null, 'Wrong parameters'); + } + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + include_once(PHPWG_ROOT_PATH.'admin/include/'.$params['type'].'.class.php'); + + $type = $params['type']; + $extension_id = $params['id']; + $revision = $params['revision']; + + $extension = new $type(); + + if ($type == 'plugins') + { + if (isset($extension->db_plugins_by_id[$extension_id]) and $extension->db_plugins_by_id[$extension_id]['state'] == 'active') + { + $extension->perform_action('deactivate', $extension_id); + + redirect(PHPWG_ROOT_PATH + . 'ws.php' + . '?method=pwg.extensions.update' + . '&type=plugins' + . '&id=' . $extension_id + . '&revision=' . $revision + . '&reactivate=true' + . '&pwg_token=' . get_pwg_token() + . '&format=json' + ); + } + + $upgrade_status = $extension->extract_plugin_files('upgrade', $revision, $extension_id); + $extension_name = $extension->fs_plugins[$extension_id]['name']; + + if (isset($params['reactivate'])) + { + $extension->perform_action('activate', $extension_id); + } + } + elseif ($type == 'themes') + { + $upgrade_status = $extension->extract_theme_files('upgrade', $revision, $extension_id); + $extension_name = $extension->fs_themes[$extension_id]['name']; + } + elseif ($type == 'languages') + { + $upgrade_status = $extension->extract_language_files('upgrade', $revision, $extension_id); + $extension_name = $extension->fs_languages[$extension_id]['name']; + } + + global $template; + $template->delete_compiled_templates(); + + switch ($upgrade_status) + { + case 'ok': + return sprintf(l10n('%s has been successfully updated.'), $extension_name); + + case 'temp_path_error': + return new PwgError(null, l10n('Can\'t create temporary file.')); + + case 'dl_archive_error': + return new PwgError(null, l10n('Can\'t download archive.')); + + case 'archive_error': + return new PwgError(null, l10n('Can\'t read or extract archive.')); + + default: + return new PwgError(null, sprintf(l10n('An error occured during extraction (%s).'), $upgrade_status)); + } +} + +function ws_extensions_ignoreupdate($params, &$service) +{ + global $conf; + + define('IN_ADMIN', true); + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + + if (!is_webmaster()) + { + return new PwgError(401, 'Access denied'); + } + + if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token']) + { + return new PwgError(403, 'Invalid security token'); + } + + $conf['updates_ignored'] = unserialize($conf['updates_ignored']); + + if ($params['reset']) + { + $conf['updates_ignored'] = array( + 'plugins'=>array(), + 'themes'=>array(), + 'languages'=>array() + ); + conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored']))); + unset($_SESSION['extensions_need_update']); + return true; + } + + if (empty($params['id']) or empty($params['type']) or !in_array($params['type'], array('plugins', 'themes', 'languages'))) + { + return new PwgError(403, 'Invalid parameters'); + } + + // Add or remove extension from ignore list + if (!in_array($params['id'], $conf['updates_ignored'][$params['type']])) + { + array_push($conf['updates_ignored'][$params['type']], $params['id']); + } + conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored']))); + unset($_SESSION['extensions_need_update']); + return true; +} ?> diff --git a/install/config.sql b/install/config.sql index dd8c94c67..205e06481 100644 --- a/install/config.sql +++ b/install/config.sql @@ -49,3 +49,4 @@ INSERT INTO piwigo_config (param,value,comment) 'Information displayed on picture page' ); INSERT INTO piwigo_config (param,value,comment) VALUES ('week_starts_on','monday','Monday may not be the first day of the week'); +INSERT INTO piwigo_config (param,value,comment) VALUES ('updates_ignored','a:3:{s:7:"plugins";a:0:{}s:6:"themes";a:0:{}s:9:"languages";a:0:{}}','Extensions ignored for update'); diff --git a/install/db/103-database.php b/install/db/103-database.php new file mode 100644 index 000000000..15424370d --- /dev/null +++ b/install/db/103-database.php @@ -0,0 +1,42 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based photo gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008-2011 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die('Hacking attempt!'); +} + +$upgrade_description = 'Extensions ignored for update'; + +$query = ' +INSERT INTO '.PREFIX_TABLE.'config (param,value,comment) + VALUES (\'updates_ignored\',\'a:3:{s:7:"plugins";a:0:{}s:6:"themes";a:0:{}s:9:"languages";a:0:{}}\', \''.$upgrade_description.'\') +;'; +pwg_query($query); + +echo +"\n" +. $upgrade_description +."\n" +; +?>
\ No newline at end of file diff --git a/language/en_UK/admin.lang.php b/language/en_UK/admin.lang.php index 3b8459058..5b70871c3 100644 --- a/language/en_UK/admin.lang.php +++ b/language/en_UK/admin.lang.php @@ -796,4 +796,30 @@ $lang['%s thumbnails can not be regenerated'] = '%s thumbnails can not be regene $lang['%s photos have been regenerated'] = '%s photos have been regenerated'; $lang['%s photos can not be regenerated'] = '%s photos can not be regenerated'; $lang['Only photos with HD can be regenerated!'] = 'Only photos with HD can be regenerated!'; + +$lang['Updates'] = 'Updates'; +$lang['Update in progress... Please wait.'] = 'Update in progress... Please wait.'; +$lang['Ignore this update'] = 'Ignore this update'; +$lang['Reset ignored updates'] = 'Reset ignored updates'; +$lang['Update All'] = 'Update All'; +$lang['ERROR'] = 'ERROR'; +$lang['Update Complete'] = 'Update Complete'; +$lang['Piwigo Update'] = 'Piwigo Update'; +$lang['Extensions Update'] = 'Extensions Update'; +$lang['All extensions are up to date.'] = 'All extensions are up to date.'; +$lang['Following plugins may not be compatible with the new version of Piwigo:'] = 'Following plugins may not be compatible with the new version of Piwigo:'; +$lang['Following themes may not be compatible with the new version of Piwigo:'] = 'Following themes may not be compatible with the new version of Piwigo:'; +$lang['I decide to update anyway'] = 'I decide to update anyway'; +$lang['Update to Piwigo %s'] = 'Update to Piwigo %s'; +$lang['Two updates are available'] = 'Two updates are available'; +$lang['This is a minor update, with only bug corrections.'] = 'This is a minor update, with only bug corrections.'; +$lang['This is a major update, with <a href="%s">new exciting features</a>.'] = 'This is a major update, with <a href="%s">new exciting features</a>.'; +$lang['Some themes and plugins may be not available yet.'] = 'Some themes and plugins may be not available yet.'; +$lang['You can update to Piwigo %s directly, without upgrading to Piwigo %s (recommended).'] = 'You can update to Piwigo %s directly, without upgrading to Piwigo %s (recommended).'; +$lang['Save Template Directory'] = 'Save template directory'; +$lang['Dump Database'] = 'Dump Database'; +$lang['Include history data (Warning: server memory limit may be exceeded)'] = 'Include history data (Warning: server memory limit may be exceeded)'; +$lang['Unable to write new local directory.'] = 'Unable to write new local directory.'; +$lang['Unable to send template directory.'] = 'Unable to send template directory.'; +$lang['Unable to dump database.'] = 'Unable to dump database.'; ?>
\ No newline at end of file diff --git a/language/fr_FR/admin.lang.php b/language/fr_FR/admin.lang.php index 298a0b56c..92239633c 100644 --- a/language/fr_FR/admin.lang.php +++ b/language/fr_FR/admin.lang.php @@ -807,4 +807,30 @@ $lang['%s thumbnails can not be regenerated'] = '%s miniatures ne peuvent pas ĂȘ $lang['%s photos have been regenerated'] = '%s photos ont Ă©tĂ© rĂ©gĂ©nĂ©rĂ©es'; $lang['%s photos can not be regenerated'] = '%s photos ne peuvent pas ĂȘtre rĂ©gĂ©nĂ©rĂ©es'; $lang['Only photos with HD can be regenerated!'] = 'Seules les photos avec HD peuvent ĂȘtre rĂ©gĂ©nĂ©rĂ©es'; + +$lang['Updates'] = 'Mises Ă jour'; +$lang['Update in progress... Please wait.'] = 'Mise Ă jour en cours... Veuillez patienter.'; +$lang['Ignore this update'] = 'Ignorer cette mise Ă jour'; +$lang['Reset ignored updates'] = 'RĂ©initialiser les mises Ă jour ignorĂ©es'; +$lang['Update All'] = 'Tout mettre Ă jour'; +$lang['ERROR'] = 'ERREUR'; +$lang['Update Complete'] = 'Mise Ă jour effectuĂ©e'; +$lang['Piwigo Update'] = 'Mise Ă jour de Piwigo'; +$lang['Extensions Update'] = 'Mise Ă jour des extensions'; +$lang['All extensions are up to date.'] = 'Toutes les extensions sont Ă jour.'; +$lang['Following plugins may not be compatible with the new version of Piwigo:'] = 'Les plugins suivants ne seront peut-ĂȘtre pas compatibles avec la nouvelle version de Piwigo:'; +$lang['Following themes may not be compatible with the new version of Piwigo:'] = 'Les thĂšmes suivants ne seront peut-ĂȘtre pas compatibles avec la nouvelle version de Piwigo:'; +$lang['I decide to update anyway'] = 'Je dĂ©cide de migrer quand mĂȘme'; +$lang['Update to Piwigo %s'] = 'Mettre Ă jour vers Piwigo %s'; +$lang['Two updates are available'] = 'Deux mises Ă jour sont disponibles'; +$lang['This is a minor update, with only bug corrections.'] = 'Ceci est une mise Ă jour mineure, avec uniquement des corrections de bugs.'; +$lang['This is a major update, with <a href="%s">new exciting features</a>.'] = 'Ceci est une mise Ă jour majeure, qui contient <a href="%s">un tas de nouveautĂ©s</a>.'; +$lang['Some themes and plugins may be not available yet.'] = 'Certains thĂšmes ou plugins ne sont peut-ĂȘtre pas encore disponibles.'; +$lang['You can update to Piwigo %s directly, without upgrading to Piwigo %s (recommended).'] = 'Vous pouvez mettre Ă jour vers Piwigo %s directement, sans passer par Piwigo %s (recommandĂ©).'; +$lang['Save Template Directory'] = 'Sauvegarder le dossier template'; +$lang['Dump Database'] = 'Sauvegarder la base de donnĂ©es'; +$lang['Include history data (Warning: server memory limit may be exceeded)'] = 'Inclure les donnĂ©es de l\'historique (Attention: risque de dĂ©passement de la limite mĂ©moire du serveur)'; +$lang['Unable to write new local directory.'] = 'Impossible d\'Ă©crire le nouveau dossier local.'; +$lang['Unable to send template directory.'] = 'Impossible d\'envoyer le dossier template.'; +$lang['Unable to dump database.'] = 'Impossible de sauvegarder la base de donnĂ©es.'; ?>
\ No newline at end of file @@ -418,6 +418,33 @@ function ws_addDefaultMethods( $arr ) <br>Argument "type" can be "thumbnail" or "websize". Default is "thumbnail". <br>If maxwidth, maxheight or quality are missing, default parameters of upload will be used.' ); + + $service->addMethod( + 'pwg.extensions.update', + 'ws_extensions_update', + array( + 'type' => array(), + 'id' => array(), + 'revision'=> array(), + 'pwg_token' => array(), + ), + 'Update an extension. Webmaster only. +<br>Parameter type must be "plugins", "languages" or "themes".' + ); + + $service->addMethod( + 'pwg.extensions.ignoreUpdate', + 'ws_extensions_ignoreupdate', + array( + 'type' => array('default'=>null), + 'id' => array('default'=>null), + 'reset' => array('default'=>null), + 'pwg_token' => array(), + ), + 'Ignore an extension if it need update. +<br>Parameter type must be "plugins", "languages" or "themes". +<br>If reset parameter is true, all ignored extensions will be reinitilized.' + ); } add_event_handler('ws_add_methods', 'ws_addDefaultMethods'); |