';
+ }
+
+ if (count($tag_ids) > 0)
+ {
+ $tag_ids = array_unique($tag_ids);
+
+ $query = '
+SELECT
+ id,
+ name
+ FROM '.TAGS_TABLE.'
+ WHERE id IN ('.implode(', ', $tag_ids).')
+;';
+ $name_of_tag = array();
+
+ $result = pwg_query($query);
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $name_of_tag[ $row['id'] ] = $row['name'];
+ }
+ }
+
+ $i = 0;
+ $first_line = $page['start'] + 1;
+ $last_line = $page['start'] + $conf['nb_logs_page'];
+
+ $summary['total_filesize'] = 0;
+ $summary['guests_IP'] = array();
+
+ foreach ($history_lines as $line)
+ {
+ // FIXME when we watch the representative of a non image element, it is
+ // the not the representative filesize that is counted (as it is
+ // unknown) but the non image element filesize. Proposed solution: add
+ // #images.representative_filesize and add 'representative' in the
+ // choices of #history.image_type.
+
+ if (isset($line['image_type']))
+ {
+ if ($line['image_type'] == 'high')
+ {
+ if (isset($high_filesize_of_image[$line['image_id']]))
+ {
+ $summary['total_filesize']+=
+ $high_filesize_of_image[$line['image_id']];
+ }
+ }
+ else
+ {
+ if (isset($filesize_of_image[$line['image_id']]))
+ {
+ $summary['total_filesize']+=
+ $filesize_of_image[$line['image_id']];
+ }
+ }
+ }
+
+ if ($line['user_id'] == $conf['guest_id'])
+ {
+ if (!isset($summary['guests_IP'][ $line['IP'] ]))
+ {
+ $summary['guests_IP'][ $line['IP'] ] = 0;
+ }
+
+ $summary['guests_IP'][ $line['IP'] ]++;
+ }
+
+ $i++;
+
+ if ($i < $first_line or $i > $last_line)
+ {
+ continue;
+ }
+
+ $user_string = '';
+ if (isset($username_of[$line['user_id']]))
+ {
+ $user_string.= $username_of[$line['user_id']];
+ }
+ else
+ {
+ $user_string.= $line['user_id'];
+ }
+ $user_string.= ' +';
+
+ $tags_string = '';
+ if (isset($line['tag_ids']))
+ {
+ $tags_string = preg_replace(
+ '/(\d+)/e',
+ '$name_of_tag["$1"]',
+ str_replace(
+ ',',
+ ', ',
+ $line['tag_ids']
+ )
+ );
+ }
+
+ $image_string = '';
+ if (isset($line['image_id']))
+ {
+ $picture_url = make_picture_url(
+ array(
+ 'image_id' => $line['image_id'],
+ )
+ );
+
+ $element = array(
+ 'id' => $line['image_id'],
+ 'file' => $file_of_image[$line['image_id']],
+ 'path' => $path_of_image[$line['image_id']],
+ 'tn_ext' => $tn_ext_of_image[$line['image_id']],
+ );
+
+ $image_title = '('.$line['image_id'].')';
+
+ if (isset($label_of_image[$line['image_id']]))
+ {
+ $image_title.= ' '.$label_of_image[$line['image_id']];
+ }
+ else
+ {
+ $image_title.= ' unknown filename';
+ }
+
+ $image_string = '';
+
+ switch ($page['search']['fields']['display_thumbnail'])
+ {
+ case 'no_display_thumbnail':
+ {
+ $image_string= ''.$image_title.'';
+ break;
+ }
+ case 'display_thumbnail_classic':
+ {
+ $image_string =
+ ''
+ .''
+ .'';
+ break;
+ }
+ case 'display_thumbnail_hoverbox':
+ {
+ $image_string =
+ ''
+ .''
+ .''.$image_title.'';
+ break;
+ }
+ }
+ }
+
+ $template->append(
+ 'search_results',
+ array(
+ 'DATE' => $line['date'],
+ 'TIME' => $line['time'],
+ 'USER' => $user_string,
+ 'IP' => $line['IP'],
+ 'IMAGE' => $image_string,
+ 'TYPE' => $line['image_type'],
+ 'SECTION' => $line['section'],
+ 'CATEGORY' => isset($line['category_id'])
+ ? ( isset($name_of_category[$line['category_id']])
+ ? $name_of_category[$line['category_id']]
+ : 'deleted '.$line['category_id'] )
+ : '',
+ 'TAGS' => $tags_string,
+ )
+ );
+ }
+
+ $summary['nb_guests'] = 0;
+ if (count(array_keys($summary['guests_IP'])) > 0)
+ {
+ $summary['nb_guests'] = count(array_keys($summary['guests_IP']));
+
+ // we delete the "guest" from the $username_of hash so that it is
+ // avoided in next steps
+ unset($username_of[ $conf['guest_id'] ]);
+ }
+
+ $summary['nb_members'] = count($username_of);
+
+ $member_strings = array();
+ foreach ($username_of as $user_id => $user_name)
+ {
+ $member_string = $user_name.' +';
+
+ $member_strings[] = $member_string;
+ }
+
+ $template->assign(
+ 'search_summary',
+ array(
+ 'NB_LINES' => l10n_dec(
+ '%d line filtered', '%d lines filtered',
+ $page['nb_lines']
+ ),
+ 'FILESIZE' => $summary['total_filesize'].' KB',
+ 'USERS' => l10n_dec(
+ '%d user', '%d users',
+ $summary['nb_members'] + $summary['nb_guests']
+ ),
+ 'MEMBERS' => sprintf(
+ l10n_dec('%d member', '%d members', $summary['nb_members']).': %s',
+ implode(
+ ', ',
+ $member_strings
+ )
+ ),
+ 'GUESTS' => l10n_dec(
+ '%d guest', '%d guests',
+ $summary['nb_guests']
+ ),
+ )
+ );
+}
+
+// +-----------------------------------------------------------------------+
+// | navigation bar |
+// +-----------------------------------------------------------------------+
+
+if (isset($page['search_id']))
+{
+ $navbar = create_navigation_bar(
+ get_root_url().'admin.php'.get_query_string_diff(array('start')),
+ $page['nb_lines'],
+ $page['start'],
+ $conf['nb_logs_page']
+ );
+
+ $template->assign('navbar', $navbar);
+}
+
+// +-----------------------------------------------------------------------+
+// | filter form |
+// +-----------------------------------------------------------------------+
+
+$form = array();
+
+if (isset($page['search']))
+{
+ if (isset($page['search']['fields']['date-after']))
+ {
+ $tokens = explode('-', $page['search']['fields']['date-after']);
+
+ $form['start_year'] = (int)$tokens[0];
+ $form['start_month'] = (int)$tokens[1];
+ $form['start_day'] = (int)$tokens[2];
+ }
+
+ if (isset($page['search']['fields']['date-before']))
+ {
+ $tokens = explode('-', $page['search']['fields']['date-before']);
+
+ $form['end_year'] = (int)$tokens[0];
+ $form['end_month'] = (int)$tokens[1];
+ $form['end_day'] = (int)$tokens[2];
+ }
+
+ $form['types'] = $page['search']['fields']['types'];
+
+ if (isset($page['search']['fields']['user']))
+ {
+ $form['user'] = $page['search']['fields']['user'];
+ }
+ else
+ {
+ $form['user'] = null;
+ }
+
+ $form['image_id'] = @$page['search']['fields']['image_id'];
+ $form['filename'] = @$page['search']['fields']['filename'];
+
+ $form['display_thumbnail'] = @$page['search']['fields']['display_thumbnail'];
+}
+else
+{
+ // by default, at page load, we want the selected date to be the current
+ // date
+ $form['start_year'] = $form['end_year'] = date('Y');
+ $form['start_month'] = $form['end_month'] = date('n');
+ $form['start_day'] = $form['end_day'] = date('j');
+ $form['types'] = $types;
+ // Hoverbox by default
+ $form['display_thumbnail'] =
+ pwg_get_cookie_var('display_thumbnail', 'no_display_thumbnail');
+}
+
+
+$month_list = $lang['month'];
+$month_list[0]='------------';
+ksort($month_list);
+
+$template->assign(
+ array(
+ 'IMAGE_ID' => @$form['image_id'],
+ 'FILENAME' => @$form['filename'],
+
+ 'month_list' => $month_list,
+
+ 'START_DAY_SELECTED' => @$form['start_day'],
+ 'START_MONTH_SELECTED' => @$form['start_month'],
+ 'START_YEAR' => @$form['start_year'],
+
+ 'END_DAY_SELECTED' => @$form['end_day'],
+ 'END_MONTH_SELECTED' => @$form['end_month'],
+ 'END_YEAR' => @$form['end_year'],
+ )
+ );
+
+$template->assign(
+ array(
+ 'type_option_values' => $types,
+ 'type_option_selected' => $form['types']
+ )
+ );
+
+
+$query = '
+SELECT
+ '.$conf['user_fields']['id'].' AS id,
+ '.$conf['user_fields']['username'].' AS username
+ FROM '.USERS_TABLE.'
+ ORDER BY username ASC
+;';
+$template->assign(
+ array(
+ 'user_options' => simple_hash_from_query($query, 'id','username'),
+ 'user_options_selected' => array(@$form['user'])
+ )
+);
+
+$template->assign('display_thumbnails', $display_thumbnails);
+$template->assign('display_thumbnail_selected', $form['display_thumbnail']);
+
+// +-----------------------------------------------------------------------+
+// | html code display |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'history');
+?>
Index: /tags/2.1.0/admin/include/c13y_internal.class.php
===================================================================
--- /tags/2.1.0/admin/include/c13y_internal.class.php (revision 6217)
+++ /tags/2.1.0/admin/include/c13y_internal.class.php (revision 6217)
@@ -0,0 +1,254 @@
+ 'PHP', 'current' => phpversion(), 'required' => REQUIRED_PHP_VERSION);
+
+ $db_version = pwg_get_db_version();
+ $check_list[] = array('type' => $conf['dblayer'],
+ 'current' => $db_version,
+ 'required' => constant('REQUIRED_'.str_replace('-', '_', strtoupper($conf['dblayer'])).'_VERSION')
+ );
+
+ foreach ($check_list as $elem)
+ {
+ if (version_compare($elem['current'], $elem['required'], '<'))
+ {
+ $c13y->add_anomaly(
+ sprintf(l10n('The version of %s [%s] installed is not compatible with the version required [%s]'), $elem['type'], $elem['current'], $elem['required']),
+ null,
+ null,
+ l10n('You need to upgrade your system to take full advantage of the application else the application will not work correctly, or not at all')
+ .' '.
+ $c13y->get_htlm_links_more_info());
+ }
+ }
+ }
+
+ /**
+ * Check exif
+ *
+ * @param c13y object
+ * @return void
+ */
+ function c13y_exif($c13y)
+ {
+ global $conf;
+
+ foreach (array('show_exif', 'use_exif') as $value)
+ {
+ if (($conf[$value]) and (!function_exists('read_exif_data')))
+ {
+ $c13y->add_anomaly(
+ sprintf(l10n('%s value is not correct file because exif are not supported'), '$conf[\''.$value.'\']'),
+ null,
+ null,
+ sprintf(l10n('%s must be to set to false in your local/config/config.inc.php file'), '$conf[\''.$value.'\']')
+ .' '.
+ $c13y->get_htlm_links_more_info());
+ }
+ }
+ }
+
+ /**
+ * Check user
+ *
+ * @param c13y object
+ * @return void
+ */
+ function c13y_user($c13y)
+ {
+ global $conf;
+
+ $c13y_users = array();
+ $c13y_users[$conf['guest_id']] = array(
+ 'status' => 'guest',
+ 'l10n_non_existent' => 'Main "guest" user does not exist',
+ 'l10n_bad_status' => 'Main "guest" user status is incorrect');
+
+ if ($conf['guest_id'] != $conf['default_user_id'])
+ {
+ $c13y_users[$conf['default_user_id']] = array(
+ 'password' => null,
+ 'l10n_non_existent' => 'Default user does not exist');
+ }
+
+ $c13y_users[$conf['webmaster_id']] = array(
+ 'status' => 'webmaster',
+ 'l10n_non_existent' => 'Main "webmaster" user does not exist',
+ 'l10n_bad_status' => 'Main "webmaster" user status is incorrect');
+
+ $query = '
+ select u.'.$conf['user_fields']['id'].' as id, ui.status
+ from '.USERS_TABLE.' as u
+ left join '.USER_INFOS_TABLE.' as ui
+ on u.'.$conf['user_fields']['id'].' = ui.user_id
+ where
+ u.'.$conf['user_fields']['id'].' in ('.implode(',', array_keys($c13y_users)).')
+ ;';
+
+
+ $status = array();
+
+ $result = pwg_query($query);
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $status[$row['id']] = $row['status'];
+ }
+
+ foreach ($c13y_users as $id => $data)
+ {
+ if (!array_key_exists($id, $status))
+ {
+ $c13y->add_anomaly(l10n($data['l10n_non_existent']), 'c13y_correction_user',
+ array('id' => $id, 'action' => 'creation'));
+ }
+ else
+ if (!empty($data['status']) and $status[$id] != $data['status'])
+ {
+ $c13y->add_anomaly(l10n($data['l10n_bad_status']), 'c13y_correction_user',
+ array('id' => $id, 'action' => 'status'));
+ }
+ }
+ }
+
+ /**
+ * Do correction user
+ *
+ * @param user_id, action
+ * @return boolean true if ok else false
+ */
+ function c13y_correction_user($id, $action)
+ {
+ global $conf, $page;
+
+ $result = false;
+
+ if (!empty($id))
+ {
+ switch ($action)
+ {
+ case 'creation':
+ if ($id == $conf['guest_id'])
+ {
+ $name = 'guest';
+ $password = null;
+ }
+ else if ($id == $conf['default_user_id'])
+ {
+ $name = 'guest';
+ $password = null;
+ }
+ else if ($id == $conf['webmaster_id'])
+ {
+ $name = 'webmaster';
+ $password = generate_key(6);
+ }
+
+ if (isset($name))
+ {
+ $name_ok = false;
+ while (!$name_ok)
+ {
+ $name_ok = (get_userid($name) === false);
+ if (!$name_ok)
+ {
+ $name .= generate_key(1);
+ }
+ }
+
+ $inserts = array(
+ array(
+ 'id' => $id,
+ 'username' => addslashes($name),
+ 'password' => $password
+ ),
+ );
+ mass_inserts(USERS_TABLE, array_keys($inserts[0]), $inserts);
+
+ create_user_infos($id);
+
+ $page['infos'][] = sprintf(l10n('User "%s" created with "%s" like password'), $name, $password);
+
+ $result = true;
+ }
+ break;
+ case 'status':
+ if ($id == $conf['guest_id'])
+ {
+ $status = 'guest';
+ }
+ else if ($id == $conf['default_user_id'])
+ {
+ $status = 'guest';
+ }
+ else if ($id == $conf['webmaster_id'])
+ {
+ $status = 'webmaster';
+ }
+
+ if (isset($status))
+ {
+ $updates = array(
+ array(
+ 'user_id' => $id,
+ 'status' => $status
+ ),
+ );
+ mass_updates(USER_INFOS_TABLE,
+ array('primary' => array('user_id'),'update' => array('status')),
+ $updates);
+
+ $page['infos'][] = sprintf(l10n('Status of user "%s" updated'), get_username($id));
+
+ $result = true;
+ }
+ break;
+ }
+ }
+
+ return $result;
+ }
+}
+
+?>
Index: /tags/2.1.0/admin/include/check_integrity.class.php
===================================================================
--- /tags/2.1.0/admin/include/check_integrity.class.php (revision 6217)
+++ /tags/2.1.0/admin/include/check_integrity.class.php (revision 6217)
@@ -0,0 +1,345 @@
+ignore_list = array();
+ $this->retrieve_list = array();
+ $this->build_ignore_list = array();
+ }
+
+ /**
+ * Check integrities
+ *
+ * @param void
+ * @return void
+ */
+ function check()
+ {
+ global $page, $header_notes, $conf;
+
+ // Ignore list
+ $conf_c13y_ignore = unserialize($conf['c13y_ignore']);
+ if (
+ is_array($conf_c13y_ignore) and
+ isset($conf_c13y_ignore['version']) and
+ ($conf_c13y_ignore['version'] == PHPWG_VERSION) and
+ is_array($conf_c13y_ignore['list'])
+ )
+ {
+ $ignore_list_changed = false;
+ $this->ignore_list = $conf_c13y_ignore['list'];
+ }
+ else
+ {
+ $ignore_list_changed = true;
+ $this->ignore_list = array();
+ }
+
+ // Retrieve list
+ $this->retrieve_list = array();
+ $this->build_ignore_list = array();
+
+ trigger_action('list_check_integrity', $this);
+
+ // Information
+ if (count($this->retrieve_list) > 0)
+ {
+ $header_notes[] =
+ l10n_dec('%d anomaly has been detected.', '%d anomalies have been detected.',
+ count($this->retrieve_list));
+ }
+
+ // Treatments
+ if (!is_adviser())
+ {
+ if (isset($_POST['c13y_submit_correction']) and isset($_POST['c13y_selection']))
+ {
+ $corrected_count = 0;
+ $not_corrected_count = 0;
+
+ foreach ($this->retrieve_list as $i => $c13y)
+ {
+ if (!empty($c13y['correction_fct']) and
+ $c13y['is_callable'] and
+ in_array($c13y['id'], $_POST['c13y_selection']))
+ {
+ if (is_array($c13y['correction_fct_args']))
+ {
+ $args = $c13y['correction_fct_args'];
+ }
+ else
+ if (!is_null($c13y['correction_fct_args']))
+ {
+ $args = array($c13y['correction_fct_args']);
+ }
+ else
+ {
+ $args = array();
+ }
+ $this->retrieve_list[$i]['corrected'] = call_user_func_array($c13y['correction_fct'], $args);
+
+ if ($this->retrieve_list[$i]['corrected'])
+ {
+ $corrected_count += 1;
+ }
+ else
+ {
+ $not_corrected_count += 1;
+ }
+ }
+ }
+
+ if ($corrected_count > 0)
+ {
+ $page['infos'][] =
+ l10n_dec('%d anomaly has been corrected.', '%d anomalies have been detected corrected.',
+ $corrected_count);
+ }
+ if ($not_corrected_count > 0)
+ {
+ $page['errors'][] =
+ l10n_dec('%d anomaly has not been corrected.', '%d anomalies have not been corrected.',
+ $not_corrected_count);
+ }
+ }
+ else
+ {
+ if (isset($_POST['c13y_submit_ignore']) and isset($_POST['c13y_selection']))
+ {
+ $ignored_count = 0;
+
+ foreach ($this->retrieve_list as $i => $c13y)
+ {
+ if (in_array($c13y['id'], $_POST['c13y_selection']))
+ {
+ $this->build_ignore_list[] = $c13y['id'];
+ $this->retrieve_list[$i]['ignored'] = true;
+ $ignored_count += 1;
+ }
+ }
+
+ if ($ignored_count > 0)
+ {
+ $page['infos'][] =
+ l10n_dec('%d anomaly has been ignored.', '%d anomalies have been ignored.',
+ $ignored_count);
+ }
+ }
+ }
+ }
+
+ $ignore_list_changed =
+ (
+ ($ignore_list_changed) or
+ (count(array_diff($this->ignore_list, $this->build_ignore_list)) > 0) or
+ (count(array_diff($this->build_ignore_list, $this->ignore_list)) > 0)
+ );
+
+ if ($ignore_list_changed)
+ {
+ $this->update_conf($this->build_ignore_list);
+ }
+ }
+
+ /**
+ * Display anomalies list
+ *
+ * @param void
+ * @return void
+ */
+ function display()
+ {
+ global $template;
+
+ $check_automatic_correction = false;
+ $submit_automatic_correction = false;
+ $submit_ignore = false;
+
+ if (isset($this->retrieve_list) and count($this->retrieve_list) > 0)
+ {
+ $template->set_filenames(array('check_integrity' => 'check_integrity.tpl'));
+
+ foreach ($this->retrieve_list as $i => $c13y)
+ {
+ $can_select = false;
+ $c13y_display = array(
+ 'id' => $c13y['id'],
+ 'anomaly' => $c13y['anomaly'],
+ 'show_ignore_msg' => false,
+ 'show_correction_success_fct' => false,
+ 'correction_error_fct' => '',
+ 'show_correction_fct' => false,
+ 'correction_error_fct' => '',
+ 'show_correction_bad_fct' => false,
+ 'correction_msg' => ''
+ );
+
+ if (isset($c13y['ignored']))
+ {
+ if ($c13y['ignored'])
+ {
+ $c13y_display['show_ignore_msg'] = true;
+ }
+ else
+ {
+ die('$c13y[\'ignored\'] cannot be false');
+ }
+ }
+ else
+ {
+ if (!empty($c13y['correction_fct']))
+ {
+ if (isset($c13y['corrected']))
+ {
+ if ($c13y['corrected'])
+ {
+ $c13y_display['show_correction_success_fct'] = true;
+ }
+ else
+ {
+ $c13y_display['correction_error_fct'] = $this->get_htlm_links_more_info();
+ }
+ }
+ else if ($c13y['is_callable'])
+ {
+ $c13y_display['show_correction_fct'] = true;
+ $template->append('c13y_do_check', $c13y['id']);
+ $submit_automatic_correction = true;
+ $can_select = true;
+ }
+ else
+ {
+ $c13y_display['show_correction_bad_fct'] = true;
+ $can_select = true;
+ }
+ }
+ else
+ {
+ $can_select = true;
+ }
+
+ if (!empty($c13y['correction_msg']) and !isset($c13y['corrected']))
+ {
+ $c13y_display['correction_msg'] = $c13y['correction_msg'];
+ }
+ }
+
+ $c13y_display['can_select'] = $can_select;
+ if ($can_select)
+ {
+ $submit_ignore = true;
+ }
+
+ $template->append('c13y_list', $c13y_display);
+ }
+
+ $template->assign('c13y_show_submit_automatic_correction', $submit_automatic_correction);
+ $template->assign('c13y_show_submit_ignore', $submit_ignore);
+
+ $template->concat('ADMIN_CONTENT', $template->parse('check_integrity', true));
+
+ }
+ }
+
+ /**
+ * Add anomaly data
+ *
+ * @param anomaly arguments
+ * @return void
+ */
+ function add_anomaly($anomaly, $correction_fct = null, $correction_fct_args = null, $correction_msg = null)
+ {
+ $id = md5($anomaly.$correction_fct.serialize($correction_fct_args).$correction_msg);
+
+ if (in_array($id, $this->ignore_list))
+ {
+ $this->build_ignore_list[] = $id;
+ }
+ else
+ {
+ $this->retrieve_list[] =
+ array(
+ 'id' => $id,
+ 'anomaly' => $anomaly,
+ 'correction_fct' => $correction_fct,
+ 'correction_fct_args' => $correction_fct_args,
+ 'correction_msg' => $correction_msg,
+ 'is_callable' => is_callable($correction_fct));
+ }
+ }
+
+ /**
+ * Update table config
+ *
+ * @param ignore list array
+ * @return void
+ */
+ function update_conf($conf_ignore_list = array())
+ {
+ $conf_c13y_ignore = array();
+ $conf_c13y_ignore['version'] = PHPWG_VERSION;
+ $conf_c13y_ignore['list'] = $conf_ignore_list;
+ $query = 'update '.CONFIG_TABLE.' set value =\''.serialize($conf_c13y_ignore).'\'where param = \'c13y_ignore\';';
+ pwg_query($query);
+ }
+
+ /**
+ * Apply maintenance
+ *
+ * @param void
+ * @return void
+ */
+ function maintenance()
+ {
+ $this->update_conf();
+ }
+
+ /**
+ * Returns links more informations
+ *
+ * @param void
+ * @return html links
+ */
+ function get_htlm_links_more_info()
+ {
+ $pwg_links = pwg_URL();
+ $link_fmt = '%s';
+ return
+ sprintf
+ (
+ l10n('Go to %s or %s for more informations'),
+ sprintf($link_fmt, $pwg_links['FORUM'], l10n('the forum')),
+ sprintf($link_fmt, $pwg_links['WIKI'], l10n('the wiki'))
+ );
+ }
+
+}
+
+?>
Index: /tags/2.1.0/admin/include/functions.php
===================================================================
--- /tags/2.1.0/admin/include/functions.php (revision 6217)
+++ /tags/2.1.0/admin/include/functions.php (revision 6217)
@@ -0,0 +1,2007 @@
+ 0)
+ {
+ update_category($category_ids);
+ }
+
+ trigger_action('delete_elements', $ids);
+}
+
+// The delete_user function delete a user identified by the $user_id
+// It also deletes :
+// - all the access linked to this user
+// - all the links to any group
+// - all the favorites linked to this user
+// - calculated permissions linked to the user
+// - all datas about notifications for the user
+function delete_user($user_id)
+{
+ global $conf;
+ $tables = array(
+ // destruction of the access linked to the user
+ USER_ACCESS_TABLE,
+ // destruction of data notification by mail for this user
+ USER_MAIL_NOTIFICATION_TABLE,
+ // destruction of data RSS notification for this user
+ USER_FEED_TABLE,
+ // deletion of calculated permissions linked to the user
+ USER_CACHE_TABLE,
+ // deletion of computed cache data linked to the user
+ USER_CACHE_CATEGORIES_TABLE,
+ // destruction of the group links for this user
+ USER_GROUP_TABLE,
+ // destruction of the favorites associated with the user
+ FAVORITES_TABLE,
+ // destruction of the caddie associated with the user
+ CADDIE_TABLE,
+ // deletion of piwigo specific informations
+ USER_INFOS_TABLE,
+ );
+
+ foreach ($tables as $table)
+ {
+ $query = '
+DELETE FROM '.$table.'
+ WHERE user_id = '.$user_id.'
+;';
+ pwg_query($query);
+ }
+
+ // destruction of the user
+ $query = '
+DELETE FROM '.SESSIONS_TABLE.'
+ WHERE data LIKE "pwg_uid|i:'.(int)$user_id.';%"
+;';
+ pwg_query($query);
+
+ // destruction of the user
+ $query = '
+DELETE FROM '.USERS_TABLE.'
+ WHERE '.$conf['user_fields']['id'].' = '.$user_id.'
+;';
+ pwg_query($query);
+
+ trigger_action('delete_user', $user_id);
+}
+
+/**
+ * Verifies that the representative picture really exists in the db and
+ * picks up a random represantive if possible and based on config.
+ *
+ * @param mixed category id
+ * @returns void
+ */
+function update_category($ids = 'all')
+{
+ global $conf;
+
+ if ($ids=='all')
+ {
+ $where_cats = '1=1';
+ }
+ elseif ( !is_array($ids) )
+ {
+ $where_cats = '%s='.$ids;
+ }
+ else
+ {
+ if (count($ids) == 0)
+ {
+ return false;
+ }
+ $where_cats = '%s IN('.wordwrap(implode(', ', $ids), 120, "\n").')';
+ }
+
+ // find all categories where the setted representative is not possible :
+ // the picture does not exist
+ $query = '
+SELECT DISTINCT c.id
+ FROM '.CATEGORIES_TABLE.' AS c LEFT JOIN '.IMAGES_TABLE.' AS i
+ ON c.representative_picture_id = i.id
+ WHERE representative_picture_id IS NOT NULL
+ AND '.sprintf($where_cats, 'c.id').'
+ AND i.id IS NULL
+;';
+ $wrong_representant = array_from_query($query, 'id');
+
+ if (count($wrong_representant) > 0)
+ {
+ $query = '
+UPDATE '.CATEGORIES_TABLE.'
+ SET representative_picture_id = NULL
+ WHERE id IN ('.wordwrap(implode(', ', $wrong_representant), 120, "\n").')
+;';
+ pwg_query($query);
+ }
+
+ if (!$conf['allow_random_representative'])
+ {
+ // If the random representant is not allowed, we need to find
+ // categories with elements and with no representant. Those categories
+ // must be added to the list of categories to set to a random
+ // representant.
+ $query = '
+SELECT DISTINCT id
+ FROM '.CATEGORIES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.'
+ ON id = category_id
+ WHERE representative_picture_id IS NULL
+ AND '.sprintf($where_cats, 'category_id').'
+;';
+ $to_rand = array_from_query($query, 'id');
+ if (count($to_rand) > 0)
+ {
+ set_random_representant($to_rand);
+ }
+ }
+}
+
+/**
+ * returns an array containing sub-directories which can be a category,
+ * recursive by default
+ *
+ * directories nammed "thumbnail", "pwg_high" or "pwg_representative" are
+ * omitted
+ *
+ * @param string $basedir
+ * @return array
+ */
+function get_fs_directories($path, $recursive = true)
+{
+ $dirs = array();
+
+ if (is_dir($path))
+ {
+ if ($contents = opendir($path))
+ {
+ while (($node = readdir($contents)) !== false)
+ {
+ if (is_dir($path.'/'.$node)
+ and $node != '.'
+ and $node != '..'
+ and $node != '.svn'
+ and $node != 'thumbnail'
+ and $node != 'pwg_high'
+ and $node != 'pwg_representative')
+ {
+ array_push($dirs, $path.'/'.$node);
+ if ($recursive)
+ {
+ $dirs = array_merge($dirs, get_fs_directories($path.'/'.$node));
+ }
+ }
+ }
+ closedir($contents);
+ }
+ }
+
+ return $dirs;
+}
+
+/**
+ * order categories (update categories.rank and global_rank database fields)
+ * so that rank field are consecutive integers starting at 1 for each child
+ * @return void
+ */
+function update_global_rank()
+{
+ $query = '
+SELECT id, id_uppercat, uppercats, rank, global_rank
+ FROM '.CATEGORIES_TABLE.'
+ ORDER BY id_uppercat,rank,name';
+
+ $cat_map = array();
+
+ $current_rank = 0;
+ $current_uppercat = '';
+
+ $result = pwg_query($query);
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ if ($row['id_uppercat'] != $current_uppercat)
+ {
+ $current_rank = 0;
+ $current_uppercat = $row['id_uppercat'];
+ }
+ ++$current_rank;
+ $cat =
+ array(
+ 'rank' => $current_rank,
+ 'rank_changed' =>$current_rank!=$row['rank'],
+ 'global_rank' => $row['global_rank'],
+ 'uppercats' => $row['uppercats'],
+ );
+ $cat_map[ $row['id'] ] = $cat;
+ }
+
+ $datas = array();
+
+ foreach( $cat_map as $id=>$cat )
+ {
+ $new_global_rank = preg_replace(
+ '/(\d+)/e',
+ "\$cat_map['$1']['rank']",
+ str_replace(',', '.', $cat['uppercats'] )
+ );
+ if ( $cat['rank_changed']
+ or $new_global_rank!=$cat['global_rank']
+ )
+ {
+ $datas[] = array(
+ 'id' => $id,
+ 'rank' => $cat['rank'],
+ 'global_rank' => $new_global_rank,
+ );
+ }
+ }
+
+ mass_updates(
+ CATEGORIES_TABLE,
+ array(
+ 'primary' => array('id'),
+ 'update' => array('rank', 'global_rank')
+ ),
+ $datas
+ );
+ return count($datas);
+}
+
+/**
+ * change the visible property on a set of categories
+ *
+ * @param array categories
+ * @param string value
+ * @return void
+ */
+function set_cat_visible($categories, $value)
+{
+ if (!in_array($value, array('true', 'false')))
+ {
+ trigger_error("set_cat_visible invalid param $value", E_USER_WARNING);
+ return false;
+ }
+
+ // unlocking a category => all its parent categories become unlocked
+ if ($value == 'true')
+ {
+ $uppercats = get_uppercat_ids($categories);
+ $query = '
+UPDATE '.CATEGORIES_TABLE.'
+ SET visible = \'true\'
+ WHERE id IN ('.implode(',', $uppercats).')';
+ pwg_query($query);
+ }
+ // locking a category => all its child categories become locked
+ if ($value == 'false')
+ {
+ $subcats = get_subcat_ids($categories);
+ $query = '
+UPDATE '.CATEGORIES_TABLE.'
+ SET visible = \'false\'
+ WHERE id IN ('.implode(',', $subcats).')';
+ pwg_query($query);
+ }
+}
+
+/**
+ * change the status property on a set of categories : private or public
+ *
+ * @param array categories
+ * @param string value
+ * @return void
+ */
+function set_cat_status($categories, $value)
+{
+ if (!in_array($value, array('public', 'private')))
+ {
+ trigger_error("set_cat_status invalid param $value", E_USER_WARNING);
+ return false;
+ }
+
+ // make public a category => all its parent categories become public
+ if ($value == 'public')
+ {
+ $uppercats = get_uppercat_ids($categories);
+ $query = '
+UPDATE '.CATEGORIES_TABLE.'
+ SET status = \'public\'
+ WHERE id IN ('.implode(',', $uppercats).')
+;';
+ pwg_query($query);
+ }
+ // make a category private => all its child categories become private
+ if ($value == 'private')
+ {
+ $subcats = get_subcat_ids($categories);
+ $query = '
+UPDATE '.CATEGORIES_TABLE.'
+ SET status = \'private\'
+ WHERE id IN ('.implode(',', $subcats).')';
+ pwg_query($query);
+ }
+}
+
+/**
+ * returns all uppercats category ids of the given category ids
+ *
+ * @param array cat_ids
+ * @return array
+ */
+function get_uppercat_ids($cat_ids)
+{
+ if (!is_array($cat_ids) or count($cat_ids) < 1)
+ {
+ return array();
+ }
+
+ $uppercats = array();
+
+ $query = '
+SELECT uppercats
+ FROM '.CATEGORIES_TABLE.'
+ WHERE id IN ('.implode(',', $cat_ids).')
+;';
+ $result = pwg_query($query);
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $uppercats = array_merge($uppercats,
+ explode(',', $row['uppercats']));
+ }
+ $uppercats = array_unique($uppercats);
+
+ return $uppercats;
+}
+
+/**
+ * set a new random representant to the categories
+ *
+ * @param array categories
+ */
+function set_random_representant($categories)
+{
+ $datas = array();
+ foreach ($categories as $category_id)
+ {
+ $query = '
+SELECT image_id
+ FROM '.IMAGE_CATEGORY_TABLE.'
+ WHERE category_id = '.$category_id.'
+ ORDER BY '.DB_RANDOM_FUNCTION.'()
+ LIMIT 1
+;';
+ list($representative) = pwg_db_fetch_row(pwg_query($query));
+
+ array_push(
+ $datas,
+ array(
+ 'id' => $category_id,
+ 'representative_picture_id' => $representative,
+ )
+ );
+ }
+
+ mass_updates(
+ CATEGORIES_TABLE,
+ array(
+ 'primary' => array('id'),
+ 'update' => array('representative_picture_id')
+ ),
+ $datas
+ );
+}
+
+/**
+ * returns the fulldir for each given category id
+ *
+ * @param array cat_ids
+ * @return array
+ */
+function get_fulldirs($cat_ids)
+{
+ if (count($cat_ids) == 0)
+ {
+ return array();
+ }
+
+ // caching directories of existing categories
+ $query = '
+SELECT id, dir
+ FROM '.CATEGORIES_TABLE.'
+ WHERE dir IS NOT NULL
+;';
+ $cat_dirs = simple_hash_from_query($query, 'id', 'dir');
+
+ // caching galleries_url
+ $query = '
+SELECT id, galleries_url
+ FROM '.SITES_TABLE.'
+;';
+ $galleries_url = simple_hash_from_query($query, 'id', 'galleries_url');
+
+ // categories : id, site_id, uppercats
+ $categories = array();
+
+ $query = '
+SELECT id, uppercats, site_id
+ FROM '.CATEGORIES_TABLE.'
+ WHERE dir IS NOT NULL
+ AND id IN (
+'.wordwrap(implode(', ', $cat_ids), 80, "\n").')
+;';
+ $result = pwg_query($query);
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ array_push($categories, $row);
+ }
+
+ // filling $cat_fulldirs
+ $cat_fulldirs = array();
+ foreach ($categories as $category)
+ {
+ $uppercats = str_replace(',', '/', $category['uppercats']);
+ $cat_fulldirs[$category['id']] = $galleries_url[$category['site_id']];
+ $cat_fulldirs[$category['id']].= preg_replace('/(\d+)/e',
+ "\$cat_dirs['$1']",
+ $uppercats);
+ }
+
+ return $cat_fulldirs;
+}
+
+/**
+ * returns an array with all file system files according to
+ * $conf['file_ext']
+ *
+ * @param string $path
+ * @param bool recursive
+ * @return array
+ */
+function get_fs($path, $recursive = true)
+{
+ global $conf;
+
+ // because isset is faster than in_array...
+ if (!isset($conf['flip_picture_ext']))
+ {
+ $conf['flip_picture_ext'] = array_flip($conf['picture_ext']);
+ }
+ if (!isset($conf['flip_file_ext']))
+ {
+ $conf['flip_file_ext'] = array_flip($conf['file_ext']);
+ }
+
+ $fs['elements'] = array();
+ $fs['thumbnails'] = array();
+ $fs['representatives'] = array();
+ $subdirs = array();
+
+ if (is_dir($path))
+ {
+ if ($contents = opendir($path))
+ {
+ while (($node = readdir($contents)) !== false)
+ {
+ if (is_file($path.'/'.$node))
+ {
+ $extension = get_extension($node);
+
+// if (in_array($extension, $conf['picture_ext']))
+ if (isset($conf['flip_picture_ext'][$extension]))
+ {
+ if (basename($path) == 'thumbnail')
+ {
+ array_push($fs['thumbnails'], $path.'/'.$node);
+ }
+ else if (basename($path) == 'pwg_representative')
+ {
+ array_push($fs['representatives'], $path.'/'.$node);
+ }
+ else
+ {
+ array_push($fs['elements'], $path.'/'.$node);
+ }
+ }
+// else if (in_array($extension, $conf['file_ext']))
+ else if (isset($conf['flip_file_ext'][$extension]))
+ {
+ array_push($fs['elements'], $path.'/'.$node);
+ }
+ }
+ else if (is_dir($path.'/'.$node)
+ and $node != '.'
+ and $node != '..'
+ and $node != 'pwg_high'
+ and $recursive)
+ {
+ array_push($subdirs, $node);
+ }
+ }
+ }
+ closedir($contents);
+
+ foreach ($subdirs as $subdir)
+ {
+ $tmp_fs = get_fs($path.'/'.$subdir);
+
+ $fs['elements'] = array_merge($fs['elements'],
+ $tmp_fs['elements']);
+
+ $fs['thumbnails'] = array_merge($fs['thumbnails'],
+ $tmp_fs['thumbnails']);
+
+ $fs['representatives'] = array_merge($fs['representatives'],
+ $tmp_fs['representatives']);
+ }
+ }
+ return $fs;
+}
+
+/**
+ * stupidly returns the current microsecond since Unix epoch
+ */
+function micro_seconds()
+{
+ $t1 = explode(' ', microtime());
+ $t2 = explode('.', $t1[0]);
+ $t2 = $t1[1].substr($t2[1], 0, 6);
+ return $t2;
+}
+
+/**
+ * synchronize base users list and related users list
+ *
+ * compares and synchronizes base users table (USERS_TABLE) with its child
+ * tables (USER_INFOS_TABLE, USER_ACCESS, USER_CACHE, USER_GROUP) : each
+ * base user must be present in child tables, users in child tables not
+ * present in base table must be deleted.
+ *
+ * @return void
+ */
+function sync_users()
+{
+ global $conf;
+
+ $query = '
+SELECT '.$conf['user_fields']['id'].' AS id
+ FROM '.USERS_TABLE.'
+;';
+ $base_users = array_from_query($query, 'id');
+
+ $query = '
+SELECT user_id
+ FROM '.USER_INFOS_TABLE.'
+;';
+ $infos_users = array_from_query($query, 'user_id');
+
+ // users present in $base_users and not in $infos_users must be added
+ $to_create = array_diff($base_users, $infos_users);
+
+ if (count($to_create) > 0)
+ {
+ create_user_infos($to_create);
+ }
+
+ // users present in user related tables must be present in the base user
+ // table
+ $tables = array(
+ USER_MAIL_NOTIFICATION_TABLE,
+ USER_FEED_TABLE,
+ USER_INFOS_TABLE,
+ USER_ACCESS_TABLE,
+ USER_CACHE_TABLE,
+ USER_CACHE_CATEGORIES_TABLE,
+ USER_GROUP_TABLE
+ );
+
+ foreach ($tables as $table)
+ {
+ $query = '
+SELECT DISTINCT user_id
+ FROM '.$table.'
+;';
+ $to_delete = array_diff(
+ array_from_query($query, 'user_id'),
+ $base_users
+ );
+
+ if (count($to_delete) > 0)
+ {
+ $query = '
+DELETE
+ FROM '.$table.'
+ WHERE user_id in ('.implode(',', $to_delete).')
+;';
+ pwg_query($query);
+ }
+ }
+}
+
+/**
+ * updates categories.uppercats field based on categories.id +
+ * categories.id_uppercat
+ *
+ * @return void
+ */
+function update_uppercats()
+{
+ $query = '
+SELECT id, id_uppercat, uppercats
+ FROM '.CATEGORIES_TABLE.'
+;';
+ $cat_map = hash_from_query($query, 'id');
+
+ $datas = array();
+ foreach ($cat_map as $id => $cat)
+ {
+ $upper_list = array();
+
+ $uppercat = $id;
+ while ($uppercat)
+ {
+ array_push($upper_list, $uppercat);
+ $uppercat = $cat_map[$uppercat]['id_uppercat'];
+ }
+
+ $new_uppercats = implode(',', array_reverse($upper_list));
+ if ($new_uppercats != $cat['uppercats'])
+ {
+ array_push(
+ $datas,
+ array(
+ 'id' => $id,
+ 'uppercats' => $new_uppercats
+ )
+ );
+ }
+ }
+ $fields = array('primary' => array('id'), 'update' => array('uppercats'));
+ mass_updates(CATEGORIES_TABLE, $fields, $datas);
+}
+
+/**
+ * update images.path field
+ *
+ * @return void
+ */
+function update_path()
+{
+ $query = '
+SELECT DISTINCT(storage_category_id)
+ FROM '.IMAGES_TABLE.'
+ WHERE storage_category_id IS NOT NULL
+;';
+ $cat_ids = array_from_query($query, 'storage_category_id');
+ $fulldirs = get_fulldirs($cat_ids);
+
+ foreach ($cat_ids as $cat_id)
+ {
+ $query = '
+UPDATE '.IMAGES_TABLE.'
+ SET path = '.pwg_db_concat(array("'".$fulldirs[$cat_id]."/'",'file')).'
+ WHERE storage_category_id = '.$cat_id.'
+;';
+ pwg_query($query);
+ }
+}
+
+/**
+ * update images.average_rate field
+ * param int $element_id optional, otherwise applies to all
+ * @return void
+ */
+function update_average_rate( $element_id=-1 )
+{
+ $query = '
+SELECT element_id,
+ ROUND(AVG(rate),2) AS average_rate
+ FROM '.RATE_TABLE;
+ if ( $element_id != -1 )
+ {
+ $query .= ' WHERE element_id=' . $element_id;
+ }
+ $query .= ' GROUP BY element_id;';
+
+ $result = pwg_query($query);
+
+ $datas = array();
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ array_push(
+ $datas,
+ array(
+ 'id' => $row['element_id'],
+ 'average_rate' => $row['average_rate']
+ )
+ );
+ }
+
+ mass_updates(
+ IMAGES_TABLE,
+ array(
+ 'primary' => array('id'),
+ 'update' => array('average_rate')
+ ),
+ $datas
+ );
+
+ $query='
+SELECT id FROM '.IMAGES_TABLE .'
+ LEFT JOIN '.RATE_TABLE.' ON id=element_id
+ WHERE element_id IS NULL AND average_rate IS NOT NULL';
+ if ( $element_id != -1 )
+ {
+ $query .= ' AND id=' . $element_id;
+ }
+ $to_update = array_from_query( $query, 'id');
+
+ if ( !empty($to_update) )
+ {
+ $query='
+UPDATE '.IMAGES_TABLE .'
+ SET average_rate=NULL
+ WHERE id IN (' . implode(',',$to_update) . ')';
+ pwg_query($query);
+ }
+}
+
+/**
+ * change the parent category of the given categories. The categories are
+ * supposed virtual.
+ *
+ * @param array category identifiers
+ * @param int parent category identifier
+ * @return void
+ */
+function move_categories($category_ids, $new_parent = -1)
+{
+ global $page;
+
+ if (count($category_ids) == 0)
+ {
+ return;
+ }
+
+ $new_parent = $new_parent < 1 ? 'NULL' : $new_parent;
+
+ $categories = array();
+
+ $query = '
+SELECT id, id_uppercat, status, uppercats
+ FROM '.CATEGORIES_TABLE.'
+ WHERE id IN ('.implode(',', $category_ids).')
+;';
+ $result = pwg_query($query);
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $categories[$row['id']] =
+ array(
+ 'parent' => empty($row['id_uppercat']) ? 'NULL' : $row['id_uppercat'],
+ 'status' => $row['status'],
+ 'uppercats' => $row['uppercats']
+ );
+ }
+
+ // is the movement possible? The movement is impossible if you try to move
+ // a category in a sub-category or itself
+ if ('NULL' != $new_parent)
+ {
+ $query = '
+SELECT uppercats
+ FROM '.CATEGORIES_TABLE.'
+ WHERE id = '.$new_parent.'
+;';
+ list($new_parent_uppercats) = pwg_db_fetch_row(pwg_query($query));
+
+ foreach ($categories as $category)
+ {
+ // technically, you can't move a category with uppercats 12,125,13,14
+ // into a new parent category with uppercats 12,125,13,14,24
+ if (preg_match('/^'.$category['uppercats'].',/', $new_parent_uppercats))
+ {
+ array_push(
+ $page['errors'],
+ l10n('You cannot move a category in its own sub category')
+ );
+ return;
+ }
+ }
+ }
+
+ $tables =
+ array(
+ USER_ACCESS_TABLE => 'user_id',
+ GROUP_ACCESS_TABLE => 'group_id'
+ );
+
+ $query = '
+UPDATE '.CATEGORIES_TABLE.'
+ SET id_uppercat = '.$new_parent.'
+ WHERE id IN ('.implode(',', $category_ids).')
+;';
+ pwg_query($query);
+
+ update_uppercats();
+ update_global_rank();
+
+ // status and related permissions management
+ if ('NULL' == $new_parent)
+ {
+ $parent_status = 'public';
+ }
+ else
+ {
+ $query = '
+SELECT status
+ FROM '.CATEGORIES_TABLE.'
+ WHERE id = '.$new_parent.'
+;';
+ list($parent_status) = pwg_db_fetch_row(pwg_query($query));
+ }
+
+ if ('private' == $parent_status)
+ {
+ foreach ($categories as $cat_id => $category)
+ {
+ switch ($category['status'])
+ {
+ case 'public' :
+ {
+ set_cat_status(array($cat_id), 'private');
+ break;
+ }
+ case 'private' :
+ {
+ $subcats = get_subcat_ids(array($cat_id));
+
+ foreach ($tables as $table => $field)
+ {
+ $query = '
+SELECT '.$field.'
+ FROM '.$table.'
+ WHERE cat_id = '.$cat_id.'
+;';
+ $category_access = array_from_query($query, $field);
+
+ $query = '
+SELECT '.$field.'
+ FROM '.$table.'
+ WHERE cat_id = '.$new_parent.'
+;';
+ $parent_access = array_from_query($query, $field);
+
+ $to_delete = array_diff($parent_access, $category_access);
+
+ if (count($to_delete) > 0)
+ {
+ $query = '
+DELETE FROM '.$table.'
+ WHERE '.$field.' IN ('.implode(',', $to_delete).')
+ AND cat_id IN ('.implode(',', $subcats).')
+;';
+ pwg_query($query);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ array_push(
+ $page['infos'],
+ l10n_dec(
+ '%d category moved', '%d categories moved',
+ count($categories)
+ )
+ );
+}
+
+/**
+ * create a virtual category
+ *
+ * @param string category name
+ * @param int parent category id
+ * @return array with ('info' and 'id') or ('error') key
+ */
+function create_virtual_category($category_name, $parent_id=null)
+{
+ global $conf;
+
+ // is the given category name only containing blank spaces ?
+ if (preg_match('/^\s*$/', $category_name))
+ {
+ return array('error' => l10n('The name of a category should not be empty'));
+ }
+
+ $parent_id = !empty($parent_id) ? $parent_id : 'NULL';
+
+ $query = '
+SELECT MAX(rank)
+ FROM '.CATEGORIES_TABLE.'
+ WHERE id_uppercat '.(is_numeric($parent_id) ? '= '.$parent_id : 'IS NULL').'
+;';
+ list($current_rank) = pwg_db_fetch_row(pwg_query($query));
+
+ $insert = array(
+ 'name' => $category_name,
+ 'rank' => ++$current_rank,
+ 'commentable' => boolean_to_string($conf['newcat_default_commentable']),
+ 'uploadable' => 'false',
+ );
+
+ if ($parent_id != 'NULL')
+ {
+ $query = '
+SELECT id, uppercats, global_rank, visible, status
+ FROM '.CATEGORIES_TABLE.'
+ WHERE id = '.$parent_id.'
+;';
+ $parent = pwg_db_fetch_assoc(pwg_query($query));
+
+ $insert['id_uppercat'] = $parent['id'];
+ $insert['global_rank'] = $parent['global_rank'].'.'.$insert['rank'];
+
+ // at creation, must a category be visible or not ? Warning : if the
+ // parent category is invisible, the category is automatically create
+ // invisible. (invisible = locked)
+ if ('false' == $parent['visible'])
+ {
+ $insert['visible'] = 'false';
+ }
+ else
+ {
+ $insert['visible'] = boolean_to_string($conf['newcat_default_visible']);
+ }
+
+ // at creation, must a category be public or private ? Warning : if the
+ // parent category is private, the category is automatically create
+ // private.
+ if ('private' == $parent['status'])
+ {
+ $insert['status'] = 'private';
+ }
+ else
+ {
+ $insert['status'] = $conf['newcat_default_status'];
+ }
+ }
+ else
+ {
+ $insert['visible'] = boolean_to_string($conf['newcat_default_visible']);
+ $insert['status'] = $conf['newcat_default_status'];
+ $insert['global_rank'] = $insert['rank'];
+ }
+
+ // we have then to add the virtual category
+ mass_inserts(
+ CATEGORIES_TABLE,
+ array(
+ 'site_id', 'name', 'id_uppercat', 'rank', 'commentable',
+ 'uploadable', 'visible', 'status', 'global_rank',
+ ),
+ array($insert)
+ );
+
+ $inserted_id = pwg_db_insert_id(CATEGORIES_TABLE);
+
+ $query = '
+UPDATE
+ '.CATEGORIES_TABLE.'
+ SET uppercats = \''.
+ (isset($parent) ? $parent{'uppercats'}.',' : '').
+ $inserted_id.
+ '\'
+ WHERE id = '.$inserted_id.'
+;';
+ pwg_query($query);
+
+ return array(
+ 'info' => l10n('Virtual category added'),
+ 'id' => $inserted_id,
+ );
+}
+
+/**
+ * Set tags to an image. Warning: given tags are all tags associated to the
+ * image, not additionnal tags.
+ *
+ * @param array tag ids
+ * @param int image id
+ * @return void
+ */
+function set_tags($tags, $image_id)
+{
+ $query = '
+DELETE
+ FROM '.IMAGE_TAG_TABLE.'
+ WHERE image_id = '.$image_id.'
+;';
+ pwg_query($query);
+
+ if (count($tags) > 0)
+ {
+ $inserts = array();
+ foreach ($tags as $tag_id)
+ {
+ array_push(
+ $inserts,
+ array(
+ 'tag_id' => $tag_id,
+ 'image_id' => $image_id
+ )
+ );
+ }
+ mass_inserts(
+ IMAGE_TAG_TABLE,
+ array_keys($inserts[0]),
+ $inserts
+ );
+ }
+}
+
+/**
+ * Add new tags to a set of images.
+ *
+ * @param array tag ids
+ * @param array image ids
+ * @return void
+ */
+function add_tags($tags, $images)
+{
+ if (count($tags) == 0 or count($images) == 0)
+ {
+ return;
+ }
+
+ // we can't insert twice the same {image_id,tag_id} so we must first
+ // delete lines we'll insert later
+ $query = '
+DELETE
+ FROM '.IMAGE_TAG_TABLE.'
+ WHERE image_id IN ('.implode(',', $images).')
+ AND tag_id IN ('.implode(',', $tags).')
+;';
+ pwg_query($query);
+
+ $inserts = array();
+ foreach ($images as $image_id)
+ {
+ foreach ($tags as $tag_id)
+ {
+ array_push(
+ $inserts,
+ array(
+ 'image_id' => $image_id,
+ 'tag_id' => $tag_id,
+ )
+ );
+ }
+ }
+ mass_inserts(
+ IMAGE_TAG_TABLE,
+ array_keys($inserts[0]),
+ $inserts
+ );
+}
+
+function tag_id_from_tag_name($tag_name)
+{
+ global $page;
+
+ $tag_name = trim($tag_name);
+ if (isset($page['tag_id_from_tag_name_cache'][$tag_name]))
+ {
+ return $page['tag_id_from_tag_name_cache'][$tag_name];
+ }
+
+ // does the tag already exists?
+ $query = '
+SELECT id
+ FROM '.TAGS_TABLE.'
+ WHERE name = \''.$tag_name.'\'
+;';
+ $existing_tags = array_from_query($query, 'id');
+
+ if (count($existing_tags) == 0)
+ {
+ mass_inserts(
+ TAGS_TABLE,
+ array('name', 'url_name'),
+ array(
+ array(
+ 'name' => $tag_name,
+ 'url_name' => str2url($tag_name),
+ )
+ )
+ );
+
+ $page['tag_id_from_tag_name_cache'][$tag_name] = pwg_db_insert_id(TAGS_TABLE);
+ }
+ else
+ {
+ $page['tag_id_from_tag_name_cache'][$tag_name] = $existing_tags[0];
+ }
+
+ return $page['tag_id_from_tag_name_cache'][$tag_name];
+}
+
+function set_tags_of($tags_of)
+{
+ if (count($tags_of) > 0)
+ {
+ $query = '
+DELETE
+ FROM '.IMAGE_TAG_TABLE.'
+ WHERE image_id IN ('.implode(',', array_keys($tags_of)).')
+;';
+ pwg_query($query);
+
+ $inserts = array();
+
+ foreach ($tags_of as $image_id => $tag_ids)
+ {
+ foreach ($tag_ids as $tag_id)
+ {
+ array_push(
+ $inserts,
+ array(
+ 'image_id' => $image_id,
+ 'tag_id' => $tag_id,
+ )
+ );
+ }
+ }
+
+ mass_inserts(
+ IMAGE_TAG_TABLE,
+ array_keys($inserts[0]),
+ $inserts
+ );
+ }
+}
+
+/**
+ * Associate a list of images to a list of categories.
+ *
+ * The function will not duplicate links
+ *
+ * @param array images
+ * @param array categories
+ * @return void
+ */
+function associate_images_to_categories($images, $categories)
+{
+ if (count($images) == 0
+ or count($categories) == 0)
+ {
+ return false;
+ }
+
+ $query = '
+DELETE
+ FROM '.IMAGE_CATEGORY_TABLE.'
+ WHERE image_id IN ('.implode(',', $images).')
+ AND category_id IN ('.implode(',', $categories).')
+;';
+ pwg_query($query);
+
+ $inserts = array();
+ foreach ($categories as $category_id)
+ {
+ foreach ($images as $image_id)
+ {
+ array_push(
+ $inserts,
+ array(
+ 'image_id' => $image_id,
+ 'category_id' => $category_id,
+ )
+ );
+ }
+ }
+
+ mass_inserts(
+ IMAGE_CATEGORY_TABLE,
+ array_keys($inserts[0]),
+ $inserts
+ );
+
+ update_category($categories);
+}
+
+/**
+ * Associate images associated to a list of source categories to a list of
+ * destination categories.
+ *
+ * @param array sources
+ * @param array destinations
+ * @return void
+ */
+function associate_categories_to_categories($sources, $destinations)
+{
+ if (count($sources) == 0)
+ {
+ return false;
+ }
+
+ $query = '
+SELECT image_id
+ FROM '.IMAGE_CATEGORY_TABLE.'
+ WHERE category_id IN ('.implode(',', $sources).')
+;';
+ $images = array_from_query($query, 'image_id');
+
+ associate_images_to_categories($images, $destinations);
+}
+
+/**
+ * Refer main Piwigo URLs (currently PHPWG_DOMAIN domain)
+ *
+ * @param void
+ * @return array like $conf['links']
+ */
+function pwg_URL()
+{
+ $urls = array(
+ 'HOME' => 'http://'.PHPWG_DOMAIN,
+ 'WIKI' => 'http://'.PHPWG_DOMAIN.'/doc',
+ 'DEMO' => 'http://'.PHPWG_DOMAIN.'/demo',
+ 'FORUM' => 'http://'.PHPWG_DOMAIN.'/forum',
+ 'BUGS' => 'http://'.PHPWG_DOMAIN.'/bugs',
+ 'EXTENSIONS' => 'http://'.PHPWG_DOMAIN.'/ext',
+ );
+ return $urls;
+}
+
+/**
+ * Invalidates cahed data (permissions and category counts) for all users.
+ */
+function invalidate_user_cache($full = true)
+{
+ if ($full)
+ {
+ $query = '
+TRUNCATE TABLE '.USER_CACHE_CATEGORIES_TABLE.';';
+ pwg_query($query);
+ $query = '
+TRUNCATE TABLE '.USER_CACHE_TABLE.';';
+ pwg_query($query);
+ }
+ else
+ {
+ $query = '
+UPDATE '.USER_CACHE_TABLE.'
+ SET need_update = \'true\';';
+ pwg_query($query);
+ }
+ trigger_action('invalidate_user_cache', $full);
+}
+
+/**
+ * adds the caracter set to a create table sql query.
+ * all CREATE TABLE queries must call this function
+ * @param string query - the sql query
+ */
+function create_table_add_character_set($query)
+{
+ defined('DB_CHARSET') or fatal_error('create_table_add_character_set DB_CHARSET undefined');
+ if ('DB_CHARSET'!='')
+ {
+ if ( version_compare(mysql_get_server_info(), '4.1.0', '<') )
+ {
+ return $query;
+ }
+ $charset_collate = " DEFAULT CHARACTER SET ".DB_CHARSET;
+ if (DB_COLLATE!='')
+ {
+ $charset_collate .= " COLLATE ".DB_COLLATE;
+ }
+ if ( is_array($query) )
+ {
+ foreach( $query as $id=>$q)
+ {
+ $q=trim($q);
+ $q=trim($q, ';');
+ if (preg_match('/^CREATE\s+TABLE/i',$q))
+ {
+ $q.=$charset_collate;
+ }
+ $q .= ';';
+ $query[$id] = $q;
+ }
+ }
+ else
+ {
+ $query=trim($query);
+ $query=trim($query, ';');
+ if (preg_match('/^CREATE\s+TABLE/i',$query))
+ {
+ $query.=$charset_collate;
+ }
+ $query .= ';';
+ }
+ }
+ return $query;
+}
+
+/**
+ * Returns array use on template with html_options method
+ * @param Min and Max access to use
+ * @return array of user access level
+ */
+function get_user_access_level_html_options($MinLevelAccess = ACCESS_FREE, $MaxLevelAccess = ACCESS_CLOSED)
+{
+ $tpl_options = array();
+ for ($level = $MinLevelAccess; $level <= $MaxLevelAccess; $level++)
+ {
+ $tpl_options[$level] = l10n(sprintf('ACCESS_%d', $level));
+ }
+ return $tpl_options;
+}
+
+/**
+ * returns a list of templates currently available in template-extension
+ * Each .tpl file is extracted from template-extension.
+ * @return array
+ */
+function get_extents($start='')
+{
+ if ($start == '') { $start = './template-extension'; }
+ $dir = opendir($start);
+ $extents = array();
+
+ while (($file = readdir($dir)) !== false)
+ {
+ if ( $file == '.' or $file == '..' or $file == '.svn') continue;
+ $path = $start . '/' . $file;
+ if (is_dir($path))
+ {
+ $extents = array_merge($extents, get_extents($path));
+ }
+ elseif ( !is_link($path) and file_exists($path)
+ and get_extension($path) == 'tpl' )
+ {
+ $extents[] = substr($path, 21);
+ }
+ }
+ return $extents;
+}
+
+function create_tag($tag_name)
+{
+ // does the tag already exists?
+ $query = '
+SELECT id
+ FROM '.TAGS_TABLE.'
+ WHERE name = \''.$tag_name.'\'
+;';
+ $existing_tags = array_from_query($query, 'id');
+
+ if (count($existing_tags) == 0)
+ {
+ mass_inserts(
+ TAGS_TABLE,
+ array('name', 'url_name'),
+ array(
+ array(
+ 'name' => $tag_name,
+ 'url_name' => str2url($tag_name),
+ )
+ )
+ );
+
+ $inserted_id = pwg_db_insert_id(TAGS_TABLE);
+
+ return array(
+ 'info' => sprintf(
+ l10n('Tag "%s" was added'),
+ stripslashes($tag_name)
+ ),
+ 'id' => $inserted_id,
+ );
+ }
+ else
+ {
+ return array(
+ 'error' => sprintf(
+ l10n('Tag "%s" already exists'),
+ stripslashes($tag_name)
+ )
+ );
+ }
+}
+
+/**
+ * Is the category accessible to the (Admin) user ?
+ *
+ * Note : if the user is not authorized to see this category, category jump
+ * will be replaced by admin cat_modify page
+ *
+ * @param int category id to verify
+ * @return bool
+ */
+function cat_admin_access($category_id)
+{
+ global $user;
+
+ // $filter['visible_categories'] and $filter['visible_images']
+ // are not used because it's not necessary (filter <> restriction)
+ if (in_array($category_id, explode(',', $user['forbidden_categories'])))
+ {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Retrieve data from external URL
+ *
+ * @param string $src: URL
+ * @param global $dest: can be a file ressource or string
+ * @return bool
+ */
+function fetchRemote($src, &$dest, $user_agent='Piwigo', $step=0)
+{
+ // Try to retrieve data from local file?
+ if (!url_is_remote($src))
+ {
+ $content = @file_get_contents($src);
+ if ($content !== false)
+ {
+ is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // After 3 redirections, return false
+ if ($step > 3) return false;
+
+ // Initialize $dest
+ is_resource($dest) or $dest = '';
+
+ // Try curl to read remote file
+ if (function_exists('curl_init'))
+ {
+ $ch = @curl_init();
+ @curl_setopt($ch, CURLOPT_URL, $src);
+ @curl_setopt($ch, CURLOPT_HEADER, 1);
+ @curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
+ @curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ $content = @curl_exec($ch);
+ $header_length = @curl_getinfo($ch, CURLINFO_HEADER_SIZE);
+ $status = @curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ @curl_close($ch);
+ if ($content !== false and $status >= 200 and $status < 400)
+ {
+ if (preg_match('/Location:\s+?(.+)/', substr($content, 0, $header_length), $m))
+ {
+ return fetchRemote($m[1], $dest, $user_agent, $step+1);
+ }
+ $content = substr($content, $header_length);
+ is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
+ return true;
+ }
+ }
+
+ // Try file_get_contents to read remote file
+ if (ini_get('allow_url_fopen'))
+ {
+ $content = @file_get_contents($src);
+ if ($content !== false)
+ {
+ is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
+ return true;
+ }
+ }
+
+ // Try fsockopen to read remote file
+ $src = parse_url($src);
+ $host = $src['host'];
+ $path = isset($src['path']) ? $src['path'] : '/';
+ $path .= isset($src['query']) ? '?'.$src['query'] : '';
+
+ if (($s = @fsockopen($host,80,$errno,$errstr,5)) === false)
+ {
+ return false;
+ }
+
+ fwrite($s,
+ "GET ".$path." HTTP/1.0\r\n"
+ ."Host: ".$host."\r\n"
+ ."User-Agent: ".$user_agent."\r\n"
+ ."Accept: */*\r\n"
+ ."\r\n"
+ );
+
+ $i = 0;
+ $in_content = false;
+ while (!feof($s))
+ {
+ $line = fgets($s);
+
+ if (rtrim($line,"\r\n") == '' && !$in_content)
+ {
+ $in_content = true;
+ $i++;
+ continue;
+ }
+ if ($i == 0)
+ {
+ if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/',rtrim($line,"\r\n"), $m))
+ {
+ fclose($s);
+ return false;
+ }
+ $status = (integer) $m[2];
+ if ($status < 200 || $status >= 400)
+ {
+ fclose($s);
+ return false;
+ }
+ }
+ if (!$in_content)
+ {
+ if (preg_match('/Location:\s+?(.+)$/',rtrim($line,"\r\n"),$m))
+ {
+ fclose($s);
+ return fetchRemote(trim($m[1]),$dest,$user_agent,$step+1);
+ }
+ $i++;
+ continue;
+ }
+ is_resource($dest) ? @fwrite($dest, $line) : $dest .= $line;
+ $i++;
+ }
+ fclose($s);
+ return true;
+}
+
+
+/**
+ * returns the groupname corresponding to the given group identifier if
+ * exists
+ *
+ * @param int group_id
+ * @return mixed
+ */
+function get_groupname($group_id)
+{
+ $query = '
+SELECT name
+ FROM '.GROUPS_TABLE.'
+ WHERE id = '.intval($group_id).'
+;';
+ $result = pwg_query($query);
+ if (pwg_db_num_rows($result) > 0)
+ {
+ list($groupname) = pwg_db_fetch_row($result);
+ }
+ else
+ {
+ return false;
+ }
+
+ return $groupname;
+}
+
+/**
+ * returns the username corresponding to the given user identifier if exists
+ *
+ * @param int user_id
+ * @return mixed
+ */
+function get_username($user_id)
+{
+ global $conf;
+
+ $query = '
+SELECT '.$conf['user_fields']['username'].'
+ FROM '.USERS_TABLE.'
+ WHERE '.$conf['user_fields']['id'].' = '.intval($user_id).'
+;';
+ $result = pwg_query($query);
+ if (pwg_db_num_rows($result) > 0)
+ {
+ list($username) = pwg_db_fetch_row($result);
+ }
+ else
+ {
+ return false;
+ }
+
+ return stripslashes($username);
+}
+
+function get_newsletter_subscribe_base_url($language) {
+ $subscribe_domain = 'piwigo.org';
+
+ $domain_of = array(
+ 'fr_FR' => 'fr.piwigo.org',
+ 'it_IT' => 'it.piwigo.org',
+ 'de_DE' => 'de.piwigo.org',
+ 'es_ES' => 'es.piwigo.org',
+ 'zh_CN' => 'cn.piwigo.org',
+ 'pl_PL' => 'pl.piwigo.org',
+ 'hu_HU' => 'hu.piwigo.org',
+ 'ru_RU' => 'ru.piwigo.org',
+ );
+
+ if (isset($domain_of[$language])) {
+ $subscribe_domain = $domain_of[$language];
+ }
+
+ return 'http://'.$subscribe_domain.'/announcement/subscribe/';
+}
+
+/**
+ * Accordion menus need to know which section to open by default when
+ * loading the page
+ */
+function get_active_menu($menu_page)
+{
+ global $page;
+
+ if (isset($page['active_menu']))
+ {
+ return $page['active_menu'];
+ }
+
+ // specific cases
+ if ('element_set' == $menu_page)
+ {
+ if (isset($_GET['cat']) and is_numeric($_GET['cat']))
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ switch ($menu_page)
+ {
+ case 'photos_add':
+ case 'upload':
+ case 'rating':
+ case 'tags':
+ case 'picture_modify':
+ return 0;
+
+ case 'cat_list':
+ case 'cat_modify':
+ case 'cat_move':
+ case 'cat_options':
+ case 'cat_perm':
+ case 'permalinks':
+ return 1;
+
+ case 'user_list':
+ case 'user_perm':
+ case 'group_list':
+ case 'group_perm':
+ case 'notification_by_mail':
+ return 2;
+
+ case 'plugins_list':
+ case 'plugins_update':
+ case 'plugins_new':
+ case 'plugin':
+ return 3;
+
+ case 'site_manager':
+ case 'site_update':
+ case 'stats':
+ case 'history':
+ case 'maintenance':
+ case 'thumbnail':
+ case 'comments':
+ return 4;
+
+ case 'configuration':
+ case 'extend_for_templates':
+ case 'menubar':
+ case 'themes_new':
+ case 'themes_installed':
+ case 'theme':
+ case 'languages_installed':
+ case 'languages_new':
+ return 5;
+ }
+ return 0;
+}
+
+function get_fckb_taglist($query)
+{
+ $result = pwg_query($query);
+ $taglist = array();
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ array_push(
+ $taglist,
+ array(
+ 'caption' => $row['tag_name'],
+ 'value' => '~~'.$row['tag_id'].'~~',
+ )
+ );
+ }
+
+ return $taglist;
+}
+
+function get_fckb_tag_ids($raw_tags)
+{
+ // In $raw_tags we receive something like array('~~6~~', '~~59~~', 'New
+ // tag', 'Another new tag') The ~~34~~ means that it is an existing
+ // tag. I've added the surrounding ~~ to permit creation of tags like "10"
+ // or "1234" (numeric characters only)
+
+ $tag_ids = array();
+
+ foreach ($raw_tags as $raw_tag)
+ {
+ if (preg_match('/^~~(\d+)~~$/', $raw_tag, $matches))
+ {
+ array_push($tag_ids, $matches[1]);
+ }
+ else
+ {
+ // we have to create a new tag
+ array_push(
+ $tag_ids,
+ tag_id_from_tag_name($raw_tag)
+ );
+ }
+ }
+
+ return $tag_ids;
+}
+?>
Index: /tags/2.1.0/admin/include/functions_history.inc.php
===================================================================
--- /tags/2.1.0/admin/include/functions_history.inc.php (revision 6217)
+++ /tags/2.1.0/admin/include/functions_history.inc.php (revision 6217)
@@ -0,0 +1,179 @@
+add('stats', l10n('Statistics'), $link_start.'stats');
+ $tabsheet->add('history', l10n('Search'), $link_start.'history');
+ // TabSheet selection
+ $tabsheet->select($page['page']);
+ // Assign tabsheet to template
+ $tabsheet->assign();
+}
+
+function history_compare($a, $b)
+{
+ return strcmp($a['date'].$a['time'], $b['date'].$b['time']);
+}
+
+function get_history($data, $search, $types)
+{
+ if (isset($search['fields']['filename']))
+ {
+ $query = '
+SELECT
+ id
+ FROM '.IMAGES_TABLE.'
+ WHERE file LIKE \''.$search['fields']['filename'].'\'
+;';
+ $search['image_ids'] = array_from_query($query, 'id');
+ }
+
+ // echo '
'; print_r($search); echo '
';
+
+ $clauses = array();
+
+ if (isset($search['fields']['date-after']))
+ {
+ array_push(
+ $clauses,
+ "date >= '".$search['fields']['date-after']."'"
+ );
+ }
+
+ if (isset($search['fields']['date-before']))
+ {
+ array_push(
+ $clauses,
+ "date <= '".$search['fields']['date-before']."'"
+ );
+ }
+
+ if (isset($search['fields']['types']))
+ {
+ $local_clauses = array();
+
+ foreach ($types as $type) {
+ if (in_array($type, $search['fields']['types'])) {
+ $clause = 'image_type ';
+ if ($type == 'none')
+ {
+ $clause.= 'IS NULL';
+ }
+ else
+ {
+ $clause.= "= '".$type."'";
+ }
+
+ array_push($local_clauses, $clause);
+ }
+ }
+
+ if (count($local_clauses) > 0)
+ {
+ array_push(
+ $clauses,
+ implode(' OR ', $local_clauses)
+ );
+ }
+ }
+
+ if (isset($search['fields']['user'])
+ and $search['fields']['user'] != -1)
+ {
+ array_push(
+ $clauses,
+ 'user_id = '.$search['fields']['user']
+ );
+ }
+
+ if (isset($search['fields']['image_id']))
+ {
+ array_push(
+ $clauses,
+ 'image_id = '.$search['fields']['image_id']
+ );
+ }
+
+ if (isset($search['fields']['filename']))
+ {
+ if (count($search['image_ids']) == 0)
+ {
+ // a clause that is always false
+ array_push($clauses, '1 = 2 ');
+ }
+ else
+ {
+ array_push(
+ $clauses,
+ 'image_id IN ('.implode(', ', $search['image_ids']).')'
+ );
+ }
+ }
+
+ $clauses = prepend_append_array_items($clauses, '(', ')');
+
+ $where_separator =
+ implode(
+ "\n AND ",
+ $clauses
+ );
+
+ $query = '
+SELECT
+ date,
+ time,
+ user_id,
+ IP,
+ section,
+ category_id,
+ tag_ids,
+ image_id,
+ image_type
+ FROM '.HISTORY_TABLE.'
+ WHERE '.$where_separator.'
+;';
+
+ // LIMIT '.$conf['nb_logs_page'].' OFFSET '.$page['start'].'
+
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ array_push($data, $row);
+ }
+
+ return $data;
+}
+
+add_event_handler('get_history', 'get_history', EVENT_HANDLER_PRIORITY_NEUTRAL, 3);
+trigger_action('functions_history_included');
+
+?>
Index: /tags/2.1.0/admin/include/functions_install.inc.php
===================================================================
--- /tags/2.1.0/admin/include/functions_install.inc.php (revision 6217)
+++ /tags/2.1.0/admin/include/functions_install.inc.php (revision 6217)
@@ -0,0 +1,161 @@
+ $engine)
+ {
+ if (file_exists(sprintf($pattern, $engine_name)))
+ {
+ $engines[$engine_name]['label'] = $engine['engine'];
+ $engines[$engine_name]['available'] = false;
+
+ if (isset($engine['function_available'])
+ && function_exists($engine['function_available']))
+ {
+ $engines[$engine_name]['available'] = true;
+ }
+ elseif (isset($engine['class_available'])
+ && class_exists($engine['class_available']))
+ {
+ $engines[$engine_name]['available'] = true;
+ }
+ }
+ }
+
+ if ($engines['sqlite']['available'] and !$engines['pdo-sqlite']['available'])
+ {
+ unset($engines['pdo-sqlite']);
+ }
+ elseif ($engines['pdo-sqlite']['available'] and !$engines['sqlite']['available'])
+ {
+ unset($engines['sqlite']);
+ }
+ elseif (DEFAULT_DB_SQLITE=='native')
+ {
+ unset($engines['pdo-sqlite']);
+ }
+ else
+ {
+ unset($engines['sqlite']);
+ }
+
+ return $engines;
+}
+
+/**
+ * Automatically activate all core themes in the "themes" directory.
+ *
+ * @return void
+ */
+function activate_core_themes()
+{
+ include_once(PHPWG_ROOT_PATH.'admin/include/themes.class.php');
+ $themes = new themes();
+ foreach ($themes->fs_themes as $theme_id => $fs_theme)
+ {
+ if (in_array($theme_id, array('Sylvia', 'clear', 'dark')))
+ {
+ $themes->perform_action('activate', $theme_id);
+ }
+ }
+}
+
+function install_db_connect(&$infos, &$errors)
+{
+ global $pwg_db_link;
+
+ try
+ {
+ $pwg_db_link = pwg_db_connect($_POST['dbhost'], $_POST['dbuser'], $_POST['dbpasswd'], $_POST['dbname']);
+ if ($pwg_db_link)
+ {
+ pwg_db_check_version();
+ }
+ }
+ catch (Exception $e)
+ {
+ array_push( $errors, l10n($e->getMessage()));
+ }
+}
+?>
Index: /tags/2.1.0/admin/include/functions_metadata.php
===================================================================
--- /tags/2.1.0/admin/include/functions_metadata.php (revision 6217)
+++ /tags/2.1.0/admin/include/functions_metadata.php (revision 6217)
@@ -0,0 +1,305 @@
+ $value)
+ {
+ if (in_array($pwg_key, array('date_creation', 'date_available')))
+ {
+ if (preg_match('/(\d{4})(\d{2})(\d{2})/', $value, $matches))
+ {
+ $iptc[$pwg_key] = $matches[1].'-'.$matches[2].'-'.$matches[3];
+ }
+ }
+ }
+
+ if (isset($iptc['keywords']))
+ {
+ // official keywords separator is the comma
+ $iptc['keywords'] = preg_replace('/[.;]/', ',', $iptc['keywords']);
+ $iptc['keywords'] = preg_replace('/^,+|,+$/', '', $iptc['keywords']);
+
+ $iptc['keywords'] = implode(
+ ',',
+ array_unique(
+ explode(
+ ',',
+ $iptc['keywords']
+ )
+ )
+ );
+ }
+
+ foreach ($iptc as $pwg_key => $value)
+ {
+ $iptc[$pwg_key] = addslashes($iptc[$pwg_key]);
+ }
+
+ return $iptc;
+}
+
+function get_sync_exif_data($file)
+{
+ global $conf;
+
+ $exif = get_exif_data($file, $conf['use_exif_mapping']);
+
+ foreach ($exif as $pwg_key => $value)
+ {
+ if (in_array($pwg_key, array('date_creation', 'date_available')))
+ {
+ if (preg_match('/^(\d{4}).(\d{2}).(\d{2})/', $value, $matches))
+ {
+ $exif[$pwg_key] = $matches[1].'-'.$matches[2].'-'.$matches[3];
+ }
+ }
+ $exif[$pwg_key] = addslashes($exif[$pwg_key]);
+ }
+
+ return $exif;
+}
+
+function update_metadata($files)
+{
+ global $conf;
+
+ if (!defined('CURRENT_DATE'))
+ {
+ define('CURRENT_DATE', date('Y-m-d'));
+ }
+
+ $datas = array();
+ $tags_of = array();
+ $has_high_images = array();
+
+ $image_ids = array();
+ foreach ($files as $id => $file)
+ {
+ array_push($image_ids, $id);
+ }
+
+ $query = '
+SELECT id
+ FROM '.IMAGES_TABLE.'
+ WHERE has_high = \'true\'
+ AND id IN (
+'.wordwrap(implode(', ', $image_ids), 80, "\n").'
+)
+;';
+
+ $has_high_images = array_from_query($query, 'id');
+
+ foreach ($files as $id => $file)
+ {
+ $data = array();
+ $data['id'] = $id;
+ $data['filesize'] = floor(filesize($file)/1024);
+
+ if ($image_size = @getimagesize($file))
+ {
+ $data['width'] = $image_size[0];
+ $data['height'] = $image_size[1];
+ }
+
+ if (in_array($id, $has_high_images))
+ {
+ $high_file = dirname($file).'/pwg_high/'.basename($file);
+
+ $data['high_filesize'] = floor(filesize($high_file)/1024);
+ }
+
+ if ($conf['use_exif'])
+ {
+ $exif = get_sync_exif_data($file);
+ if (count($exif) == 0 and isset($data['high_filesize']))
+ {
+ $exif = get_sync_exif_data($high_file);
+ }
+ $data = array_merge($data, $exif);
+ }
+
+ if ($conf['use_iptc'])
+ {
+ $iptc = get_sync_iptc_data($file);
+ if (count($iptc) == 0 and isset($data['high_filesize']))
+ {
+ $iptc = get_sync_iptc_data($high_file);
+ }
+ $data = array_merge($data, $iptc);
+
+ if (count($iptc) > 0)
+ {
+ foreach (array_keys($iptc) as $key)
+ {
+ if ($key == 'keywords' or $key == 'tags')
+ {
+ if (!isset($tags_of[$id]))
+ {
+ $tags_of[$id] = array();
+ }
+
+ foreach (explode(',', $iptc[$key]) as $tag_name)
+ {
+ array_push(
+ $tags_of[$id],
+ tag_id_from_tag_name($tag_name)
+ );
+ }
+ }
+ }
+ }
+ }
+
+ $data['date_metadata_update'] = CURRENT_DATE;
+
+ array_push($datas, $data);
+ }
+
+ if (count($datas) > 0)
+ {
+ $update_fields =
+ array(
+ 'filesize',
+ 'width',
+ 'height',
+ 'high_filesize',
+ 'date_metadata_update'
+ );
+
+ if ($conf['use_exif'])
+ {
+ $update_fields =
+ array_merge(
+ $update_fields,
+ array_keys($conf['use_exif_mapping'])
+ );
+ }
+
+ if ($conf['use_iptc'])
+ {
+ $update_fields =
+ array_merge(
+ $update_fields,
+ array_diff(
+ array_keys($conf['use_iptc_mapping']),
+ array('tags', 'keywords')
+ )
+ );
+ }
+
+ mass_updates(
+ IMAGES_TABLE,
+ array(
+ 'primary' => array('id'),
+ 'update' => array_unique($update_fields)
+ ),
+ $datas,
+ MASS_UPDATES_SKIP_EMPTY
+ );
+ }
+
+ set_tags_of($tags_of);
+}
+
+/**
+ * returns an array associating element id (images.id) with its complete
+ * path in the filesystem
+ *
+ * @param int id_uppercat
+ * @param int site_id
+ * @param boolean recursive ?
+ * @param boolean only newly added files ?
+ * @return array
+ */
+function get_filelist($category_id = '', $site_id=1, $recursive = false,
+ $only_new = false)
+{
+ // filling $cat_ids : all categories required
+ $cat_ids = array();
+
+ $query = '
+SELECT id
+ FROM '.CATEGORIES_TABLE.'
+ WHERE site_id = '.$site_id.'
+ AND dir IS NOT NULL';
+ if (is_numeric($category_id))
+ {
+ if ($recursive)
+ {
+ $query.= '
+ AND uppercats '.DB_REGEX_OPERATOR.' \'(^|,)'.$category_id.'(,|$)\'
+';
+ }
+ else
+ {
+ $query.= '
+ AND id = '.$category_id.'
+';
+ }
+ }
+ $query.= '
+;';
+ $result = pwg_query($query);
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ array_push($cat_ids, $row['id']);
+ }
+
+ if (count($cat_ids) == 0)
+ {
+ return array();
+ }
+
+ $files = array();
+
+ $query = '
+SELECT id, path
+ FROM '.IMAGES_TABLE.'
+ WHERE storage_category_id IN ('.implode(',', $cat_ids).')';
+ if ($only_new)
+ {
+ $query.= '
+ AND date_metadata_update IS NULL
+';
+ }
+ $query.= '
+;';
+ $result = pwg_query($query);
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $files[$row['id']] = $row['path'];
+ }
+
+ return $files;
+}
+?>
Index: /tags/2.1.0/admin/include/functions_notification_by_mail.inc.php
===================================================================
--- /tags/2.1.0/admin/include/functions_notification_by_mail.inc.php (revision 6217)
+++ /tags/2.1.0/admin/include/functions_notification_by_mail.inc.php (revision 6217)
@@ -0,0 +1,526 @@
+ get_moment(),
+ 'sendmail_timeout' => (intval(ini_get('max_execution_time')) * $conf['nbm_max_treatment_timeout_percent']),
+ 'is_sendmail_timeout' => false
+ );
+
+if
+ (
+ (!isset($env_nbm['sendmail_timeout'])) or
+ (!is_numeric($env_nbm['sendmail_timeout'])) or
+ ($env_nbm['sendmail_timeout'] <= 0)
+ )
+{
+ $env_nbm['sendmail_timeout'] = $conf['nbm_treatment_timeout_default'];
+}
+
+/*
+ * Search an available check_key
+ *
+ * It's a copy of function find_available_feed_id
+ *
+ * @return string nbm identifier
+ */
+function find_available_check_key()
+{
+ while (true)
+ {
+ $key = generate_key(16);
+ $query = '
+select
+ count(*)
+from
+ '.USER_MAIL_NOTIFICATION_TABLE.'
+where
+ check_key = \''.$key.'\';';
+
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count == 0)
+ {
+ return $key;
+ }
+ }
+}
+
+/*
+ * Check sendmail timeout state
+ *
+ * @return true, if it's timeout
+ */
+function check_sendmail_timeout()
+{
+ global $env_nbm;
+
+ $env_nbm['is_sendmail_timeout'] = ((get_moment() - $env_nbm['start_time']) > $env_nbm['sendmail_timeout']);
+
+ return $env_nbm['is_sendmail_timeout'];
+}
+
+
+/*
+ * Add quote to all elements of check_key_list
+ *
+ * @return quoted check key list
+ */
+function quote_check_key_list($check_key_list = array())
+{
+ return array_map(create_function('$s', 'return \'\\\'\'.$s.\'\\\'\';'), $check_key_list);
+}
+
+/*
+ * Execute all main queries to get list of user
+ *
+ * Type are the type of list 'subscribe', 'send'
+ *
+ * return array of users
+ */
+function get_user_notifications($action, $check_key_list = array(), $enabled_filter_value = '')
+{
+ global $conf;
+
+ $data_users = array();
+
+ if (in_array($action, array('subscribe', 'send')))
+ {
+ $quoted_check_key_list = quote_check_key_list($check_key_list);
+ if (count($quoted_check_key_list) != 0 )
+ {
+ $query_and_check_key = ' and
+ check_key in ('.implode(",", $quoted_check_key_list).') ';
+ }
+ else
+ {
+ $query_and_check_key = '';
+ }
+
+ $query = '
+select
+ N.user_id,
+ N.check_key,
+ U.'.$conf['user_fields']['username'].' as username,
+ U.'.$conf['user_fields']['email'].' as mail_address,
+ N.enabled,
+ N.last_send
+from
+ '.USER_MAIL_NOTIFICATION_TABLE.' as N,
+ '.USERS_TABLE.' as U
+where
+ N.user_id = U.'.$conf['user_fields']['id'];
+
+ if ($action == 'send')
+ {
+ // No mail empty and all users enabled
+ $query .= ' and
+ N.enabled = \'true\' and
+ U.'.$conf['user_fields']['email'].' is not null';
+ }
+
+ $query .= $query_and_check_key;
+
+ if (isset($enabled_filter_value) and ($enabled_filter_value != ''))
+ {
+ $query .= ' and
+ N.enabled = \''.boolean_to_string($enabled_filter_value).'\'';
+ }
+
+ $query .= '
+order by';
+
+ if ($action == 'send')
+ {
+ $query .= '
+ last_send, username;';
+ }
+ else
+ {
+ $query .= '
+ username;';
+ }
+
+ $query .= ';';
+
+ $result = pwg_query($query);
+ if (!empty($result))
+ {
+ while ($nbm_user = pwg_db_fetch_assoc($result))
+ {
+ array_push($data_users, $nbm_user);
+ }
+ }
+ }
+ return $data_users;
+}
+
+/*
+ * Begin of use nbm environment
+ * Prepare and save current environment and initialize data in order to send mail
+ *
+ * Return none
+ */
+function begin_users_env_nbm($is_to_send_mail = false)
+{
+ global $user, $lang, $lang_info, $conf, $env_nbm;
+
+ // Save $user, $lang_info and $lang arrays (include/user.inc.php has been executed)
+ $env_nbm['save_user'] = $user;
+ // Save current language to stack, necessary because $user change during NBM
+ switch_lang_to($user['language']);
+
+ $env_nbm['is_to_send_mail'] = $is_to_send_mail;
+
+ if ($is_to_send_mail)
+ {
+ // Init mail configuration
+ $env_nbm['email_format'] = get_str_email_format($conf['nbm_send_html_mail']);
+ $env_nbm['send_as_name'] = ((isset($conf['nbm_send_mail_as']) and !empty($conf['nbm_send_mail_as'])) ? $conf['nbm_send_mail_as'] : get_mail_sender_name());
+ $env_nbm['send_as_mail_address'] = get_webmaster_mail_address();
+ $env_nbm['send_as_mail_formated'] = format_email($env_nbm['send_as_name'], $env_nbm['send_as_mail_address']);
+ // Init mail counter
+ $env_nbm['error_on_mail_count'] = 0;
+ $env_nbm['sent_mail_count'] = 0;
+ // Save sendmail message info and error in the original language
+ $env_nbm['msg_info'] = l10n('Mail sent to %s [%s].');
+ $env_nbm['msg_error'] = l10n('Error when sending email to %s [%s].');
+ }
+}
+
+/*
+ * End of use nbm environment
+ * Restore environment
+ *
+ * Return none
+ */
+function end_users_env_nbm()
+{
+ global $user, $lang, $lang_info, $env_nbm;
+
+ // Restore $user, $lang_info and $lang arrays (include/user.inc.php has been executed)
+ $user = $env_nbm['save_user'];
+ // Restore current language to stack, necessary because $user change during NBM
+ switch_lang_back();
+
+ if ($env_nbm['is_to_send_mail'])
+ {
+ unset($env_nbm['email_format']);
+ unset($env_nbm['send_as_name']);
+ unset($env_nbm['send_as_mail_address']);
+ unset($env_nbm['send_as_mail_formated']);
+ // Don t unset counter
+ //unset($env_nbm['error_on_mail_count']);
+ //unset($env_nbm['sent_mail_count']);
+ unset($env_nbm['msg_info']);
+ unset($env_nbm['msg_error']);
+ }
+
+ unset($env_nbm['save_user']);
+ unset($env_nbm['is_to_send_mail']);
+}
+
+/*
+ * Set user on nbm enviromnent
+ *
+ * Return none
+ */
+function set_user_on_env_nbm(&$nbm_user, $is_action_send)
+{
+ global $user, $lang, $lang_info, $env_nbm;
+
+ $user = build_user( $nbm_user['user_id'], true );
+
+ switch_lang_to($user['language']);
+
+ if ($is_action_send)
+ {
+ $nbm_user['theme'] = $user['theme'];
+ $env_nbm['mail_template'] = get_mail_template($env_nbm['email_format'], $nbm_user['theme']);
+ $env_nbm['mail_template']->set_filename('notification_by_mail', 'notification_by_mail.tpl');
+ }
+}
+
+/*
+ * Unset user on nbm enviromnent
+ *
+ * Return none
+ */
+function unset_user_on_env_nbm()
+{
+ global $env_nbm;
+
+ switch_lang_back();
+ unset($env_nbm['mail_template']);
+}
+
+/*
+ * Inc Counter success
+ *
+ * Return none
+ */
+function inc_mail_sent_success($nbm_user)
+{
+ global $page, $env_nbm;
+
+ $env_nbm['sent_mail_count'] += 1;
+ array_push($page['infos'], sprintf($env_nbm['msg_info'], stripslashes($nbm_user['username']), $nbm_user['mail_address']));
+}
+
+/*
+ * Inc Counter failed
+ *
+ * Return none
+ */
+function inc_mail_sent_failed($nbm_user)
+{
+ global $page, $env_nbm;
+
+ $env_nbm['error_on_mail_count'] += 1;
+ array_push($page['errors'], sprintf($env_nbm['msg_error'], stripslashes($nbm_user['username']), $nbm_user['mail_address']));
+}
+
+/*
+ * Display Counter Info
+ *
+ * Return none
+ */
+function display_counter_info()
+{
+ global $page, $env_nbm;
+
+ if ($env_nbm['error_on_mail_count'] != 0)
+ {
+ array_push($page['errors'], l10n_dec('%d mail was not sent.', '%d mails were not sent.', $env_nbm['error_on_mail_count']));
+ if ($env_nbm['sent_mail_count'] != 0)
+ array_push($page['infos'], l10n_dec('%d mail was sent.', '%d mails were sent.', $env_nbm['sent_mail_count']));
+ }
+ else
+ {
+ if ($env_nbm['sent_mail_count'] == 0)
+ array_push($page['infos'], l10n('No mail to send.'));
+ else
+ array_push($page['infos'], l10n_dec('%d mail was sent.', '%d mails were sent.', $env_nbm['sent_mail_count']));
+ }
+}
+
+function assign_vars_nbm_mail_content($nbm_user)
+{
+ global $env_nbm;
+
+ set_make_full_url();
+
+ $env_nbm['mail_template']->assign
+ (
+ array
+ (
+ 'USERNAME' => stripslashes($nbm_user['username']),
+
+ 'SEND_AS_NAME' => $env_nbm['send_as_name'],
+
+ 'UNSUBSCRIBE_LINK' => add_url_params(get_root_url().'nbm.php', array('unsubscribe' => $nbm_user['check_key'])),
+ 'SUBSCRIBE_LINK' => add_url_params(get_root_url().'nbm.php', array('subscribe' => $nbm_user['check_key'])),
+ 'CONTACT_EMAIL' => $env_nbm['send_as_mail_address']
+ )
+ );
+
+ unset_make_full_url();
+}
+
+/*
+ * Subscribe or unsubscribe notification by mail
+ *
+ * is_subscribe define if action=subscribe or unsubscribe
+ * check_key list where action will be done
+ *
+ * @return check_key list treated
+ */
+function do_subscribe_unsubscribe_notification_by_mail($is_admin_request, $is_subscribe = false, $check_key_list = array())
+{
+ global $conf, $page, $env_nbm, $conf;
+
+ $check_key_treated = array();
+ $updated_data_count = 0;
+ $error_on_updated_data_count = 0;
+
+ if ($is_subscribe)
+ {
+ $msg_info = l10n('User %s [%s] was added to the subscription list.');
+ $msg_error = l10n('User %s [%s] was not added to the subscription list.');
+ }
+ else
+ {
+ $msg_info = l10n('User %s [%s] was removed from the subscription list.');
+ $msg_error = l10n('User %s [%s] was not removed from the subscription list.');
+ }
+
+ if (count($check_key_list) != 0)
+ {
+ $updates = array();
+ $enabled_value = boolean_to_string($is_subscribe);
+ $data_users = get_user_notifications('subscribe', $check_key_list, !$is_subscribe);
+
+ // Prepare message after change language
+ $msg_break_timeout = l10n('Time to send mail is limited. Others mails are skipped.');
+
+ // Begin nbm users environment
+ begin_users_env_nbm(true);
+
+ foreach ($data_users as $nbm_user)
+ {
+ if (check_sendmail_timeout())
+ {
+ // Stop fill list on 'send', if the quota is override
+ array_push($page['errors'], $msg_break_timeout);
+ break;
+ }
+
+ // Fill return list
+ array_push($check_key_treated, $nbm_user['check_key']);
+
+ $do_update = true;
+ if ($nbm_user['mail_address'] != '')
+ {
+ // set env nbm user
+ set_user_on_env_nbm($nbm_user, true);
+
+ $subject = '['.$conf['gallery_title'].']: '.($is_subscribe ? l10n('Subscribe to notification by mail'): l10n('Unsubscribe from notification by mail'));
+
+ // Assign current var for nbm mail
+ assign_vars_nbm_mail_content($nbm_user);
+
+ $section_action_by = ($is_subscribe ? 'subscribe_by_' : 'unsubscribe_by_');
+ $section_action_by .= ($is_admin_request ? 'admin' : 'himself');
+ $env_nbm['mail_template']->assign
+ (
+ array
+ (
+ $section_action_by => true,
+ 'GOTO_GALLERY_TITLE' => $conf['gallery_title'],
+ 'GOTO_GALLERY_URL' => $conf['gallery_url'],
+ )
+ );
+
+ if (pwg_mail
+ (
+ format_email(stripslashes($nbm_user['username']), $nbm_user['mail_address']),
+ array
+ (
+ 'from' => $env_nbm['send_as_mail_formated'],
+ 'subject' => $subject,
+ 'email_format' => $env_nbm['email_format'],
+ 'content' => $env_nbm['mail_template']->parse('notification_by_mail', true),
+ 'content_format' => $env_nbm['email_format'],
+ 'theme' => $nbm_user['theme']
+ )
+ ))
+ {
+ inc_mail_sent_success($nbm_user);
+ }
+ else
+ {
+ inc_mail_sent_failed($nbm_user);
+ $do_update = false;
+ }
+
+ // unset env nbm user
+ unset_user_on_env_nbm();
+
+ }
+
+ if ($do_update)
+ {
+ array_push
+ (
+ $updates,
+ array
+ (
+ 'check_key' => $nbm_user['check_key'],
+ 'enabled' => $enabled_value
+ )
+ );
+ $updated_data_count += 1;
+ array_push($page['infos'], sprintf($msg_info, stripslashes($nbm_user['username']), $nbm_user['mail_address']));
+ }
+ else
+ {
+ $error_on_updated_data_count += 1;
+ array_push($page['errors'], sprintf($msg_error, stripslashes($nbm_user['username']), $nbm_user['mail_address']));
+ }
+
+ }
+
+ // Restore nbm environment
+ end_users_env_nbm();
+
+ display_counter_info();
+
+ mass_updates(
+ USER_MAIL_NOTIFICATION_TABLE,
+ array(
+ 'primary' => array('check_key'),
+ 'update' => array('enabled')
+ ),
+ $updates
+ );
+
+ }
+
+ array_push($page['infos'], l10n_dec('%d user was updated.', '%d users were updated.', $updated_data_count));
+ if ($error_on_updated_data_count != 0)
+ {
+ array_push($page['errors'],
+ l10n_dec('%d user was not updated.',
+ '%d users were not updated.',
+ $error_on_updated_data_count));
+ }
+
+ return $check_key_treated;
+}
+
+/*
+ * Unsubscribe notification by mail
+ *
+ * check_key list where action will be done
+ *
+ * @return check_key list treated
+ */
+function unsubscribe_notification_by_mail($is_admin_request, $check_key_list = array())
+{
+ return do_subscribe_unsubscribe_notification_by_mail($is_admin_request, false, $check_key_list);
+}
+
+/*
+ * Subscribe notification by mail
+ *
+ * check_key list where action will be done
+ *
+ * @return check_key list treated
+ */
+function subscribe_notification_by_mail($is_admin_request, $check_key_list = array())
+{
+ return do_subscribe_unsubscribe_notification_by_mail($is_admin_request, true, $check_key_list);
+}
+
+?>
Index: /tags/2.1.0/admin/include/functions_permalinks.php
===================================================================
--- /tags/2.1.0/admin/include/functions_permalinks.php (revision 6217)
+++ /tags/2.1.0/admin/include/functions_permalinks.php (revision 6217)
@@ -0,0 +1,204 @@
+
Index: /tags/2.1.0/admin/include/functions_plugins.inc.php
===================================================================
--- /tags/2.1.0/admin/include/functions_plugins.inc.php (revision 6217)
+++ /tags/2.1.0/admin/include/functions_plugins.inc.php (revision 6217)
@@ -0,0 +1,46 @@
+
Index: /tags/2.1.0/admin/include/functions_upgrade.php
===================================================================
--- /tags/2.1.0/admin/include/functions_upgrade.php (revision 6217)
+++ /tags/2.1.0/admin/include/functions_upgrade.php (revision 6217)
@@ -0,0 +1,263 @@
+'.implode(', ', $plugins).'');
+ }
+}
+
+// Check access rights
+function check_upgrade_access_rights()
+{
+ global $conf, $page, $current_release;
+
+ if (version_compare($current_release, '2.0', '>=') and isset($_COOKIE[session_name()]))
+ {
+ // Check if user is already connected as webmaster
+ session_start();
+ if (!empty($_SESSION['pwg_uid']))
+ {
+ $query = '
+SELECT status
+ FROM '.USER_INFOS_TABLE.'
+ WHERE user_id = '.$_SESSION['pwg_uid'].'
+;';
+ pwg_query($query);
+
+ $row = pwg_db_fetch_assoc(pwg_query($query));
+ if (isset($row['status']) and $row['status'] == 'webmaster')
+ {
+ define('PHPWG_IN_UPGRADE', true);
+ return;
+ }
+ }
+ }
+
+ if (!isset($_POST['username']) or !isset($_POST['password']))
+ {
+ return;
+ }
+
+ $username = $_POST['username'];
+ $password = $_POST['password'];
+
+ if(!@get_magic_quotes_gpc())
+ {
+ $username = pwg_db_real_escape_string($username);
+ }
+
+ if (version_compare($current_release, '2.0', '<'))
+ {
+ $username = utf8_decode($username);
+ $password = utf8_decode($password);
+ }
+
+ if (version_compare($current_release, '1.5', '<'))
+ {
+ $query = '
+SELECT password, status
+FROM '.USERS_TABLE.'
+WHERE username = "'.$username.'"
+;';
+ }
+ else
+ {
+ $query = '
+SELECT u.password, ui.status
+FROM '.USERS_TABLE.' AS u
+INNER JOIN '.USER_INFOS_TABLE.' AS ui
+ON u.'.$conf['user_fields']['id'].'=ui.user_id
+WHERE '.$conf['user_fields']['username'].'="'.$username.'"
+;';
+ }
+ $row = pwg_db_fetch_assoc(pwg_query($query));
+
+ if (!isset($conf['pass_convert']))
+ {
+ $conf['pass_convert'] = create_function('$s', 'return md5($s);');
+ }
+
+ if ($row['password'] != $conf['pass_convert']($password))
+ {
+ array_push($page['errors'], l10n('Invalid password!'));
+ }
+ elseif ($row['status'] != 'admin' and $row['status'] != 'webmaster')
+ {
+ array_push($page['errors'], l10n('You do not have access rights to run upgrade'));
+ }
+ else
+ {
+ define('PHPWG_IN_UPGRADE', true);
+ }
+}
+
+/**
+ * which upgrades are available ?
+ *
+ * @return array
+ */
+function get_available_upgrade_ids()
+{
+ $upgrades_path = PHPWG_ROOT_PATH.'install/db';
+
+ $available_upgrade_ids = array();
+
+ if ($contents = opendir($upgrades_path))
+ {
+ while (($node = readdir($contents)) !== false)
+ {
+ if (is_file($upgrades_path.'/'.$node)
+ and preg_match('/^(.*?)-database\.php$/', $node, $match))
+ {
+ array_push($available_upgrade_ids, $match[1]);
+ }
+ }
+ }
+ natcasesort($available_upgrade_ids);
+
+ return $available_upgrade_ids;
+}
+
+
+/**
+ * returns true if there are available upgrade files
+ */
+function check_upgrade_feed()
+{
+ // retrieve already applied upgrades
+ $query = '
+SELECT id
+ FROM '.UPGRADE_TABLE.'
+;';
+ $applied = array_from_query($query, 'id');
+
+ // retrieve existing upgrades
+ $existing = get_available_upgrade_ids();
+
+ // which upgrades need to be applied?
+ return (count(array_diff($existing, $applied)) > 0);
+}
+
+function upgrade_db_connect()
+{
+ global $conf;
+
+ try
+ {
+ $pwg_db_link = pwg_db_connect($conf['db_host'], $conf['db_user'], $conf['db_password'], $conf['db_base']);
+ if ($pwg_db_link)
+ {
+ pwg_db_check_version();
+ }
+ }
+ catch (Exception $e)
+ {
+ my_error(l10n($e->getMessage()), true);
+ }
+}
+?>
Index: /tags/2.1.0/admin/include/functions_upload.inc.php
===================================================================
--- /tags/2.1.0/admin/include/functions_upload.inc.php (revision 6217)
+++ /tags/2.1.0/admin/include/functions_upload.inc.php (revision 6217)
@@ -0,0 +1,276 @@
+ isset($original_filename) ? $original_filename : basename($file_path),
+ 'date_available' => $dbnow,
+ 'tn_ext' => 'jpg',
+ 'path' => preg_replace('#^'.preg_quote(PHPWG_ROOT_PATH).'#', '', $file_path),
+ 'filesize' => $file_infos['filesize'],
+ 'width' => $file_infos['width'],
+ 'height' => $file_infos['height'],
+ 'md5sum' => $md5sum,
+ );
+
+ if (isset($high_infos))
+ {
+ $insert['has_high'] = 'true';
+ $insert['high_filesize'] = $high_infos['filesize'];
+ }
+
+ if (isset($level))
+ {
+ $insert['level'] = $level;
+ }
+
+ mass_inserts(
+ IMAGES_TABLE,
+ array_keys($insert),
+ array($insert)
+ );
+
+ $image_id = mysql_insert_id();
+
+ if (isset($categories) and count($categories) > 0)
+ {
+ associate_images_to_categories(
+ array($image_id),
+ $categories
+ );
+ }
+
+ // update metadata from the uploaded file (exif/iptc)
+ update_metadata(array($image_id=>$file_path));
+
+ invalidate_user_cache();
+
+ return $image_id;
+}
+
+function prepare_directory($directory)
+{
+ if (!is_dir($directory)) {
+ umask(0000);
+ $recursive = true;
+ if (!@mkdir($directory, 0777, $recursive))
+ {
+ die('[prepare_directory] cannot create directory "'.$directory.'"');
+ }
+ }
+
+ if (!is_writable($directory))
+ {
+ // last chance to make the directory writable
+ @chmod($directory, 0777);
+
+ if (!is_writable($directory))
+ {
+ die('[prepare_directory] directory "'.$directory.'" has no write access');
+ }
+ }
+
+ secure_directory($directory);
+}
+
+function need_resize($image_filepath, $max_width, $max_height)
+{
+ list($width, $height) = getimagesize($image_filepath);
+
+ if ($width > $max_width or $height > $max_height)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+function pwg_image_resize($result, $source_filepath, $destination_filepath, $max_width, $max_height, $quality)
+{
+ if ($result !== false)
+ {
+ //someone hooked us - so we skip
+ return $result;
+ }
+
+ if (!function_exists('gd_info'))
+ {
+ return false;
+ }
+
+ // extension of the picture filename
+ $extension = strtolower(get_extension($source_filepath));
+
+ $source_image = null;
+ if (in_array($extension, array('jpg', 'jpeg')))
+ {
+ $source_image = @imagecreatefromjpeg($source_filepath);
+ }
+ else if ($extension == 'png')
+ {
+ $source_image = @imagecreatefrompng($source_filepath);
+ }
+ else
+ {
+ die('unsupported file extension');
+ }
+
+ // width/height
+ $source_width = imagesx($source_image);
+ $source_height = imagesy($source_image);
+
+ $ratio_width = $source_width / $max_width;
+ $ratio_height = $source_height / $max_height;
+
+ // maximal size exceeded ?
+ if ($ratio_width > 1 or $ratio_height > 1)
+ {
+ if ($ratio_width < $ratio_height)
+ {
+ $destination_width = ceil($source_width / $ratio_height);
+ $destination_height = $max_height;
+ }
+ else
+ {
+ $destination_width = $max_width;
+ $destination_height = ceil($source_height / $ratio_width);
+ }
+ }
+ else
+ {
+ // the image doesn't need any resize! We just copy it to the destination
+ copy($source_filepath, $destination_filepath);
+ return true;
+ }
+
+ $destination_image = imagecreatetruecolor($destination_width, $destination_height);
+
+ imagecopyresampled(
+ $destination_image,
+ $source_image,
+ 0,
+ 0,
+ 0,
+ 0,
+ $destination_width,
+ $destination_height,
+ $source_width,
+ $source_height
+ );
+
+ imagejpeg($destination_image, $destination_filepath, $quality);
+ // freeing memory ressources
+ imagedestroy($source_image);
+ imagedestroy($destination_image);
+
+ // everything should be OK if we are here!
+ return true;
+}
+
+function pwg_image_infos($path)
+{
+ list($width, $height) = getimagesize($path);
+ $filesize = floor(filesize($path)/1024);
+
+ return array(
+ 'width' => $width,
+ 'height' => $height,
+ 'filesize' => $filesize,
+ );
+}
+
+function is_valid_image_extension($extension)
+{
+ return in_array(strtolower($extension), array('jpg', 'jpeg', 'png'));
+}
+?>
Index: /tags/2.1.0/admin/include/index.php
===================================================================
--- /tags/2.1.0/admin/include/index.php (revision 6217)
+++ /tags/2.1.0/admin/include/index.php (revision 6217)
@@ -0,0 +1,30 @@
+
Index: /tags/2.1.0/admin/include/languages.class.php
===================================================================
--- /tags/2.1.0/admin/include/languages.class.php (revision 6217)
+++ /tags/2.1.0/admin/include/languages.class.php (revision 6217)
@@ -0,0 +1,403 @@
+fs_languages = $this->get_fs_languages($target_charset);
+ }
+
+ /**
+ * Set tabsheet for languages pages.
+ * @param string selected page.
+ */
+ function set_tabsheet($selected)
+ {
+ include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
+
+ $link = get_root_url().'admin.php?page=';
+
+ $tabsheet = new tabsheet();
+ $tabsheet->add('languages_installed', l10n('Installed Languages'), $link.'languages_installed');
+ $tabsheet->add('languages_new', l10n('Add New Language'), $link.'languages_new');
+ $tabsheet->select($selected);
+ $tabsheet->assign();
+ }
+
+ /**
+ * Perform requested actions
+ * @param string - action
+ * @param string - language id
+ * @param array - errors
+ */
+ function perform_action($action, $language_id)
+ {
+ global $conf;
+
+ if (isset($this->db_languages[$language_id]))
+ {
+ $crt_db_language = $this->db_languages[$language_id];
+ }
+
+ $errors = array();
+
+ switch ($action)
+ {
+ case 'activate':
+ if (isset($crt_db_language))
+ {
+ array_push($errors, 'CANNOT ACTIVATE - LANGUAGE IS ALREADY ACTIVATED');
+ break;
+ }
+
+ $query = '
+INSERT INTO '.LANGUAGES_TABLE.'
+ (id, name)
+ VALUES(\''.$language_id.'\', \''.$this->fs_languages[$language_id].'\')
+;';
+ pwg_query($query);
+ break;
+
+ case 'deactivate':
+ if (!isset($crt_db_language))
+ {
+ array_push($errors, 'CANNOT DEACTIVATE - LANGUAGE IS ALREADY DEACTIVATED');
+ break;
+ }
+
+ if ($language_id == get_default_language())
+ {
+ array_push($errors, 'CANNOT DEACTIVATE - LANGUAGE IS DEFAULT LANGUAGE');
+ break;
+ }
+
+ $query = "
+DELETE
+ FROM ".LANGUAGES_TABLE."
+ WHERE id= '".$language_id."'
+;";
+ pwg_query($query);
+ break;
+
+ case 'delete':
+ if (!empty($crt_db_language))
+ {
+ array_push($errors, 'CANNOT DELETE - LANGUAGE IS ACTIVATED');
+ break;
+ }
+ if (!isset($this->fs_languages[$language_id]))
+ {
+ array_push($errors, 'CANNOT DELETE - LANGUAGE DOES NOT EXIST');
+ break;
+ }
+
+ // Set default language to user who are using this language
+ $query = '
+UPDATE '.USER_INFOS_TABLE.'
+ SET language = "'.get_default_language().'"
+ WHERE language = "'.$language_id.'"
+;';
+ pwg_query($query);
+
+ if (!$this->deltree(PHPWG_ROOT_PATH.'language/'.$language_id))
+ {
+ $this->send_to_trash(PHPWG_ROOT_PATH.'language/'.$language_id);
+ }
+ break;
+
+ case 'set_default':
+ $query = '
+UPDATE '.USER_INFOS_TABLE.'
+ SET language = "'.$language_id.'"
+ WHERE user_id = '.$conf['default_user_id'].'
+;';
+ pwg_query($query);
+ break;
+ }
+ return $errors;
+ }
+
+ /**
+ * Get languages defined in the language directory
+ */
+ function get_fs_languages($target_charset = null)
+ {
+ if ( empty($target_charset) )
+ {
+ $target_charset = get_pwg_charset();
+ }
+ $target_charset = strtolower($target_charset);
+
+ $dir = opendir(PHPWG_ROOT_PATH.'language');
+
+ while ($file = readdir($dir))
+ {
+ $path = PHPWG_ROOT_PATH.'language/'.$file;
+ if (!is_link($path) and is_dir($path) and file_exists($path.'/iso.txt'))
+ {
+ list($language_name) = @file($path.'/iso.txt');
+
+ $languages[$file] = convert_charset($language_name, $target_charset);
+ }
+ }
+ closedir($dir);
+ @asort($languages);
+
+ return $languages;
+ }
+
+ function get_db_languages()
+ {
+ $query = '
+ SELECT id, name
+ FROM '.LANGUAGES_TABLE.'
+ ORDER BY name ASC
+ ;';
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $this->db_languages[ $row['id'] ] = $row['name'];
+ }
+ }
+
+ /**
+ * Retrieve PEM server datas to $server_languages
+ */
+ function get_server_languages()
+ {
+ global $user;
+
+ $pem_category_id = 8;
+
+ // Retrieve PEM versions
+ $version = PHPWG_VERSION;
+ $versions_to_check = array();
+ $url = PEM_URL . '/api/get_version_list.php?category_id='.$pem_category_id.'&format=php';
+ if (fetchRemote($url, $result) 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;
+ }
+
+ // Retrieve PEM languages infos
+ $url = PEM_URL . '/api/get_revision_list.php?category_id='.$pem_category_id.'&format=php&last_revision_only=true';
+ $url .= '&version=' . implode(',', $versions_to_check);
+ $url .= '&lang='.$user['language'];
+
+ if (fetchRemote($url, $result))
+ {
+ $pem_languages = @unserialize($result);
+ if (!is_array($pem_languages))
+ {
+ return false;
+ }
+ foreach ($pem_languages as $language)
+ {
+ if (preg_match('/^.*? \[[A-Z]{2}\]$/', $language['extension_name'])
+ and !in_array($language['extension_name'], $this->fs_languages))
+ {
+ $this->server_languages[] = $language;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Extract language files from archive
+ *
+ * @param string - install or upgrade
+ * @param string - remote revision identifier (numeric)
+ * @param string - language id or extension id
+ */
+ function extract_language_files($action, $revision, $dest='')
+ {
+ if ($archive = tempnam( PHPWG_ROOT_PATH.'language', 'zip'))
+ {
+ $url = PEM_URL . '/download.php?rid=' . $revision;
+ $url .= '&origin=piwigo_' . $action;
+
+ if ($handle = @fopen($archive, 'wb') and fetchRemote($url, $handle))
+ {
+ fclose($handle);
+ include(PHPWG_ROOT_PATH.'admin/include/pclzip.lib.php');
+ $zip = new PclZip($archive);
+ if ($list = $zip->listContent())
+ {
+ foreach ($list as $file)
+ {
+ // we search iso.txt in archive
+ if (basename($file['filename']) == 'iso.txt'
+ and (!isset($main_filepath)
+ or strlen($file['filename']) < strlen($main_filepath)))
+ {
+ $main_filepath = $file['filename'];
+ }
+ }
+ if (isset($main_filepath))
+ {
+ $root = basename(dirname($main_filepath)); // iso.txt path in archive
+ if (preg_match('/^[a-z]{2}_[A-Z]{2}$/', $root))
+ {
+ if ($action == 'install')
+ {
+ $dest = $root;
+ }
+ $extract_path = PHPWG_ROOT_PATH.'language/'.$dest;
+ if (
+ $result = $zip->extract(
+ PCLZIP_OPT_PATH, $extract_path,
+ PCLZIP_OPT_REMOVE_PATH, $root,
+ PCLZIP_OPT_REPLACE_NEWER
+ )
+ )
+ {
+ foreach ($result as $file)
+ {
+ if ($file['stored_filename'] == $main_filepath)
+ {
+ $status = $file['status'];
+ break;
+ }
+ }
+ if ($status == 'ok')
+ {
+ $this->fs_languages = $this->get_fs_languages();
+ $this->perform_action('activate', $dest);
+ }
+ if (file_exists($extract_path.'/obsolete.list')
+ and $old_files = file($extract_path.'/obsolete.list', FILE_IGNORE_NEW_LINES)
+ and !empty($old_files))
+ {
+ array_push($old_files, 'obsolete.list');
+ foreach($old_files as $old_file)
+ {
+ $path = $extract_path.'/'.$old_file;
+ if (is_file($path))
+ {
+ @unlink($path);
+ }
+ elseif (is_dir($path))
+ {
+ if (!$this->deltree($path))
+ {
+ $this->send_to_trash($path);
+ }
+ }
+ }
+ }
+ }
+ else $status = 'extract_error';
+ }
+ else $status = 'archive_error';
+ }
+ else $status = 'archive_error';
+ }
+ else $status = 'archive_error';
+ }
+ else $status = 'dl_archive_error';
+ }
+ else $status = 'temp_path_error';
+
+ @unlink($archive);
+ return $status;
+ }
+
+ /**
+ * delete $path directory
+ * @param string - path
+ */
+ function deltree($path)
+ {
+ if (is_dir($path))
+ {
+ $fh = opendir($path);
+ while ($file = readdir($fh))
+ {
+ if ($file != '.' and $file != '..')
+ {
+ $pathfile = $path . '/' . $file;
+ if (is_dir($pathfile))
+ {
+ $this->deltree($pathfile);
+ }
+ else
+ {
+ @unlink($pathfile);
+ }
+ }
+ }
+ closedir($fh);
+ return @rmdir($path);
+ }
+ }
+
+ /**
+ * send $path to trash directory
+ * @param string - path
+ */
+ function send_to_trash($path)
+ {
+ $trash_path = PHPWG_ROOT_PATH . 'language/trash';
+ if (!is_dir($trash_path))
+ {
+ @mkdir($trash_path);
+ $file = @fopen($trash_path . '/.htaccess', 'w');
+ @fwrite($file, 'deny from all');
+ @fclose($file);
+ }
+ while ($r = $trash_path . '/' . md5(uniqid(rand(), true)))
+ {
+ if (!is_dir($r))
+ {
+ @rename($path, $r);
+ break;
+ }
+ }
+ }
+}
+?>
Index: /tags/2.1.0/admin/include/pclzip.lib.php
===================================================================
--- /tags/2.1.0/admin/include/pclzip.lib.php (revision 6217)
+++ /tags/2.1.0/admin/include/pclzip.lib.php (revision 6217)
@@ -0,0 +1,5694 @@
+zipname = $p_zipname;
+ $this->zip_fd = 0;
+ $this->magic_quotes_status = -1;
+
+ // ----- Return
+ return;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // create($p_filelist, $p_add_dir="", $p_remove_dir="")
+ // create($p_filelist, $p_option, $p_option_value, ...)
+ // Description :
+ // This method supports two different synopsis. The first one is historical.
+ // This method creates a Zip Archive. The Zip file is created in the
+ // filesystem. The files and directories indicated in $p_filelist
+ // are added in the archive. See the parameters description for the
+ // supported format of $p_filelist.
+ // When a directory is in the list, the directory and its content is added
+ // in the archive.
+ // In this synopsis, the function takes an optional variable list of
+ // options. See bellow the supported options.
+ // Parameters :
+ // $p_filelist : An array containing file or directory names, or
+ // a string containing one filename or one directory name, or
+ // a string containing a list of filenames and/or directory
+ // names separated by spaces.
+ // $p_add_dir : A path to add before the real path of the archived file,
+ // in order to have it memorized in the archive.
+ // $p_remove_dir : A path to remove from the real path of the file to archive,
+ // in order to have a shorter path memorized in the archive.
+ // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
+ // is removed first, before $p_add_dir is added.
+ // Options :
+ // PCLZIP_OPT_ADD_PATH :
+ // PCLZIP_OPT_REMOVE_PATH :
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
+ // PCLZIP_OPT_COMMENT :
+ // PCLZIP_CB_PRE_ADD :
+ // PCLZIP_CB_POST_ADD :
+ // Return Values :
+ // 0 on failure,
+ // The list of the added files, with a status of the add action.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ function create($p_filelist)
+ {
+ $v_result=1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Set default values
+ $v_options = array();
+ $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Look for arguments
+ if ($v_size > 1) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Remove from the options list the first argument
+ array_shift($v_arg_list);
+ $v_size--;
+
+ // ----- Look for first arg
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+ array (PCLZIP_OPT_REMOVE_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+ PCLZIP_OPT_ADD_PATH => 'optional',
+ PCLZIP_CB_PRE_ADD => 'optional',
+ PCLZIP_CB_POST_ADD => 'optional',
+ PCLZIP_OPT_NO_COMPRESSION => 'optional',
+ PCLZIP_OPT_COMMENT => 'optional',
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+ //, PCLZIP_OPT_CRYPT => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Look for 2 args
+ // Here we need to support the first historic synopsis of the
+ // method.
+ else {
+
+ // ----- Get the first argument
+ $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];
+
+ // ----- Look for the optional second argument
+ if ($v_size == 2) {
+ $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
+ }
+ else if ($v_size > 2) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
+ "Invalid number / type of arguments");
+ return 0;
+ }
+ }
+ }
+
+ // ----- Look for default option values
+ $this->privOptionDefaultThreshold($v_options);
+
+ // ----- Init
+ $v_string_list = array();
+ $v_att_list = array();
+ $v_filedescr_list = array();
+ $p_result_list = array();
+
+ // ----- Look if the $p_filelist is really an array
+ if (is_array($p_filelist)) {
+
+ // ----- Look if the first element is also an array
+ // This will mean that this is a file description entry
+ if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
+ $v_att_list = $p_filelist;
+ }
+
+ // ----- The list is a list of string names
+ else {
+ $v_string_list = $p_filelist;
+ }
+ }
+
+ // ----- Look if the $p_filelist is a string
+ else if (is_string($p_filelist)) {
+ // ----- Create a list from the string
+ $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
+ }
+
+ // ----- Invalid variable type for $p_filelist
+ else {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist");
+ return 0;
+ }
+
+ // ----- Reformat the string list
+ if (sizeof($v_string_list) != 0) {
+ foreach ($v_string_list as $v_string) {
+ if ($v_string != '') {
+ $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
+ }
+ else {
+ }
+ }
+ }
+
+ // ----- For each file in the list check the attributes
+ $v_supported_attributes
+ = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
+ ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
+ ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
+ ,PCLZIP_ATT_FILE_MTIME => 'optional'
+ ,PCLZIP_ATT_FILE_CONTENT => 'optional'
+ ,PCLZIP_ATT_FILE_COMMENT => 'optional'
+ );
+ foreach ($v_att_list as $v_entry) {
+ $v_result = $this->privFileDescrParseAtt($v_entry,
+ $v_filedescr_list[],
+ $v_options,
+ $v_supported_attributes);
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Expand the filelist (expand directories)
+ $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Call the create fct
+ $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Return
+ return $p_result_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // add($p_filelist, $p_add_dir="", $p_remove_dir="")
+ // add($p_filelist, $p_option, $p_option_value, ...)
+ // Description :
+ // This method supports two synopsis. The first one is historical.
+ // This methods add the list of files in an existing archive.
+ // If a file with the same name already exists, it is added at the end of the
+ // archive, the first one is still present.
+ // If the archive does not exist, it is created.
+ // Parameters :
+ // $p_filelist : An array containing file or directory names, or
+ // a string containing one filename or one directory name, or
+ // a string containing a list of filenames and/or directory
+ // names separated by spaces.
+ // $p_add_dir : A path to add before the real path of the archived file,
+ // in order to have it memorized in the archive.
+ // $p_remove_dir : A path to remove from the real path of the file to archive,
+ // in order to have a shorter path memorized in the archive.
+ // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
+ // is removed first, before $p_add_dir is added.
+ // Options :
+ // PCLZIP_OPT_ADD_PATH :
+ // PCLZIP_OPT_REMOVE_PATH :
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
+ // PCLZIP_OPT_COMMENT :
+ // PCLZIP_OPT_ADD_COMMENT :
+ // PCLZIP_OPT_PREPEND_COMMENT :
+ // PCLZIP_CB_PRE_ADD :
+ // PCLZIP_CB_POST_ADD :
+ // Return Values :
+ // 0 on failure,
+ // The list of the added files, with a status of the add action.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ function add($p_filelist)
+ {
+ $v_result=1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Set default values
+ $v_options = array();
+ $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Look for arguments
+ if ($v_size > 1) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Remove form the options list the first argument
+ array_shift($v_arg_list);
+ $v_size--;
+
+ // ----- Look for first arg
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+ array (PCLZIP_OPT_REMOVE_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+ PCLZIP_OPT_ADD_PATH => 'optional',
+ PCLZIP_CB_PRE_ADD => 'optional',
+ PCLZIP_CB_POST_ADD => 'optional',
+ PCLZIP_OPT_NO_COMPRESSION => 'optional',
+ PCLZIP_OPT_COMMENT => 'optional',
+ PCLZIP_OPT_ADD_COMMENT => 'optional',
+ PCLZIP_OPT_PREPEND_COMMENT => 'optional',
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+ //, PCLZIP_OPT_CRYPT => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Look for 2 args
+ // Here we need to support the first historic synopsis of the
+ // method.
+ else {
+
+ // ----- Get the first argument
+ $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];
+
+ // ----- Look for the optional second argument
+ if ($v_size == 2) {
+ $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
+ }
+ else if ($v_size > 2) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+ // ----- Return
+ return 0;
+ }
+ }
+ }
+
+ // ----- Look for default option values
+ $this->privOptionDefaultThreshold($v_options);
+
+ // ----- Init
+ $v_string_list = array();
+ $v_att_list = array();
+ $v_filedescr_list = array();
+ $p_result_list = array();
+
+ // ----- Look if the $p_filelist is really an array
+ if (is_array($p_filelist)) {
+
+ // ----- Look if the first element is also an array
+ // This will mean that this is a file description entry
+ if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
+ $v_att_list = $p_filelist;
+ }
+
+ // ----- The list is a list of string names
+ else {
+ $v_string_list = $p_filelist;
+ }
+ }
+
+ // ----- Look if the $p_filelist is a string
+ else if (is_string($p_filelist)) {
+ // ----- Create a list from the string
+ $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
+ }
+
+ // ----- Invalid variable type for $p_filelist
+ else {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist");
+ return 0;
+ }
+
+ // ----- Reformat the string list
+ if (sizeof($v_string_list) != 0) {
+ foreach ($v_string_list as $v_string) {
+ $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
+ }
+ }
+
+ // ----- For each file in the list check the attributes
+ $v_supported_attributes
+ = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
+ ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
+ ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
+ ,PCLZIP_ATT_FILE_MTIME => 'optional'
+ ,PCLZIP_ATT_FILE_CONTENT => 'optional'
+ ,PCLZIP_ATT_FILE_COMMENT => 'optional'
+ );
+ foreach ($v_att_list as $v_entry) {
+ $v_result = $this->privFileDescrParseAtt($v_entry,
+ $v_filedescr_list[],
+ $v_options,
+ $v_supported_attributes);
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Expand the filelist (expand directories)
+ $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Call the create fct
+ $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Return
+ return $p_result_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : listContent()
+ // Description :
+ // This public method, gives the list of the files and directories, with their
+ // properties.
+ // The properties of each entries in the list are (used also in other functions) :
+ // filename : Name of the file. For a create or add action it is the filename
+ // given by the user. For an extract function it is the filename
+ // of the extracted file.
+ // stored_filename : Name of the file / directory stored in the archive.
+ // size : Size of the stored file.
+ // compressed_size : Size of the file's data compressed in the archive
+ // (without the headers overhead)
+ // mtime : Last known modification date of the file (UNIX timestamp)
+ // comment : Comment associated with the file
+ // folder : true | false
+ // index : index of the file in the archive
+ // status : status of the action (depending of the action) :
+ // Values are :
+ // ok : OK !
+ // filtered : the file / dir is not extracted (filtered by user)
+ // already_a_directory : the file can not be extracted because a
+ // directory with the same name already exists
+ // write_protected : the file can not be extracted because a file
+ // with the same name already exists and is
+ // write protected
+ // newer_exist : the file was not extracted because a newer file exists
+ // path_creation_fail : the file is not extracted because the folder
+ // does not exist and can not be created
+ // write_error : the file was not extracted because there was a
+ // error while writing the file
+ // read_error : the file was not extracted because there was a error
+ // while reading the file
+ // invalid_header : the file was not extracted because of an archive
+ // format error (bad file header)
+ // Note that each time a method can continue operating when there
+ // is an action error on a file, the error is only logged in the file status.
+ // Return Values :
+ // 0 on an unrecoverable failure,
+ // The list of the files in the archive.
+ // --------------------------------------------------------------------------------
+ function listContent()
+ {
+ $v_result=1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return(0);
+ }
+
+ // ----- Call the extracting fct
+ $p_list = array();
+ if (($v_result = $this->privList($p_list)) != 1)
+ {
+ unset($p_list);
+ return(0);
+ }
+
+ // ----- Return
+ return $p_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // extract($p_path="./", $p_remove_path="")
+ // extract([$p_option, $p_option_value, ...])
+ // Description :
+ // This method supports two synopsis. The first one is historical.
+ // This method extract all the files / directories from the archive to the
+ // folder indicated in $p_path.
+ // If you want to ignore the 'root' part of path of the memorized files
+ // you can indicate this in the optional $p_remove_path parameter.
+ // By default, if a newer file with the same name already exists, the
+ // file is not extracted.
+ //
+ // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions
+ // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append
+ // at the end of the path value of PCLZIP_OPT_PATH.
+ // Parameters :
+ // $p_path : Path where the files and directories are to be extracted
+ // $p_remove_path : First part ('root' part) of the memorized path
+ // (if any similar) to remove while extracting.
+ // Options :
+ // PCLZIP_OPT_PATH :
+ // PCLZIP_OPT_ADD_PATH :
+ // PCLZIP_OPT_REMOVE_PATH :
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
+ // PCLZIP_CB_PRE_EXTRACT :
+ // PCLZIP_CB_POST_EXTRACT :
+ // Return Values :
+ // 0 or a negative value on failure,
+ // The list of the extracted files, with a status of the action.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ function extract()
+ {
+ $v_result=1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return(0);
+ }
+
+ // ----- Set default values
+ $v_options = array();
+// $v_path = "./";
+ $v_path = '';
+ $v_remove_path = "";
+ $v_remove_all_path = false;
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Default values for option
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
+
+ // ----- Look for arguments
+ if ($v_size > 0) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Look for first arg
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+ array (PCLZIP_OPT_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+ PCLZIP_OPT_ADD_PATH => 'optional',
+ PCLZIP_CB_PRE_EXTRACT => 'optional',
+ PCLZIP_CB_POST_EXTRACT => 'optional',
+ PCLZIP_OPT_SET_CHMOD => 'optional',
+ PCLZIP_OPT_BY_NAME => 'optional',
+ PCLZIP_OPT_BY_EREG => 'optional',
+ PCLZIP_OPT_BY_PREG => 'optional',
+ PCLZIP_OPT_BY_INDEX => 'optional',
+ PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
+ PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',
+ PCLZIP_OPT_REPLACE_NEWER => 'optional'
+ ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
+ ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Set the arguments
+ if (isset($v_options[PCLZIP_OPT_PATH])) {
+ $v_path = $v_options[PCLZIP_OPT_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
+ $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
+ $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
+ // ----- Check for '/' in last path char
+ if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
+ $v_path .= '/';
+ }
+ $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
+ }
+ }
+
+ // ----- Look for 2 args
+ // Here we need to support the first historic synopsis of the
+ // method.
+ else {
+
+ // ----- Get the first argument
+ $v_path = $v_arg_list[0];
+
+ // ----- Look for the optional second argument
+ if ($v_size == 2) {
+ $v_remove_path = $v_arg_list[1];
+ }
+ else if ($v_size > 2) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+ // ----- Return
+ return 0;
+ }
+ }
+ }
+
+ // ----- Look for default option values
+ $this->privOptionDefaultThreshold($v_options);
+
+ // ----- Trace
+
+ // ----- Call the extracting fct
+ $p_list = array();
+ $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path,
+ $v_remove_all_path, $v_options);
+ if ($v_result < 1) {
+ unset($p_list);
+ return(0);
+ }
+
+ // ----- Return
+ return $p_list;
+ }
+ // --------------------------------------------------------------------------------
+
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // extractByIndex($p_index, $p_path="./", $p_remove_path="")
+ // extractByIndex($p_index, [$p_option, $p_option_value, ...])
+ // Description :
+ // This method supports two synopsis. The first one is historical.
+ // This method is doing a partial extract of the archive.
+ // The extracted files or folders are identified by their index in the
+ // archive (from 0 to n).
+ // Note that if the index identify a folder, only the folder entry is
+ // extracted, not all the files included in the archive.
+ // Parameters :
+ // $p_index : A single index (integer) or a string of indexes of files to
+ // extract. The form of the string is "0,4-6,8-12" with only numbers
+ // and '-' for range or ',' to separate ranges. No spaces or ';'
+ // are allowed.
+ // $p_path : Path where the files and directories are to be extracted
+ // $p_remove_path : First part ('root' part) of the memorized path
+ // (if any similar) to remove while extracting.
+ // Options :
+ // PCLZIP_OPT_PATH :
+ // PCLZIP_OPT_ADD_PATH :
+ // PCLZIP_OPT_REMOVE_PATH :
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
+ // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and
+ // not as files.
+ // The resulting content is in a new field 'content' in the file
+ // structure.
+ // This option must be used alone (any other options are ignored).
+ // PCLZIP_CB_PRE_EXTRACT :
+ // PCLZIP_CB_POST_EXTRACT :
+ // Return Values :
+ // 0 on failure,
+ // The list of the extracted files, with a status of the action.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ //function extractByIndex($p_index, options...)
+ function extractByIndex($p_index)
+ {
+ $v_result=1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return(0);
+ }
+
+ // ----- Set default values
+ $v_options = array();
+// $v_path = "./";
+ $v_path = '';
+ $v_remove_path = "";
+ $v_remove_all_path = false;
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Default values for option
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
+
+ // ----- Look for arguments
+ if ($v_size > 1) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Remove form the options list the first argument
+ array_shift($v_arg_list);
+ $v_size--;
+
+ // ----- Look for first arg
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+ array (PCLZIP_OPT_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+ PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
+ PCLZIP_OPT_ADD_PATH => 'optional',
+ PCLZIP_CB_PRE_EXTRACT => 'optional',
+ PCLZIP_CB_POST_EXTRACT => 'optional',
+ PCLZIP_OPT_SET_CHMOD => 'optional',
+ PCLZIP_OPT_REPLACE_NEWER => 'optional'
+ ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
+ ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Set the arguments
+ if (isset($v_options[PCLZIP_OPT_PATH])) {
+ $v_path = $v_options[PCLZIP_OPT_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
+ $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
+ $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
+ // ----- Check for '/' in last path char
+ if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
+ $v_path .= '/';
+ }
+ $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
+ }
+ if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
+ }
+ else {
+ }
+ }
+
+ // ----- Look for 2 args
+ // Here we need to support the first historic synopsis of the
+ // method.
+ else {
+
+ // ----- Get the first argument
+ $v_path = $v_arg_list[0];
+
+ // ----- Look for the optional second argument
+ if ($v_size == 2) {
+ $v_remove_path = $v_arg_list[1];
+ }
+ else if ($v_size > 2) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+ // ----- Return
+ return 0;
+ }
+ }
+ }
+
+ // ----- Trace
+
+ // ----- Trick
+ // Here I want to reuse extractByRule(), so I need to parse the $p_index
+ // with privParseOptions()
+ $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index);
+ $v_options_trick = array();
+ $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick,
+ array (PCLZIP_OPT_BY_INDEX => 'optional' ));
+ if ($v_result != 1) {
+ return 0;
+ }
+ $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];
+
+ // ----- Look for default option values
+ $this->privOptionDefaultThreshold($v_options);
+
+ // ----- Call the extracting fct
+ if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
+ return(0);
+ }
+
+ // ----- Return
+ return $p_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // delete([$p_option, $p_option_value, ...])
+ // Description :
+ // This method removes files from the archive.
+ // If no parameters are given, then all the archive is emptied.
+ // Parameters :
+ // None or optional arguments.
+ // Options :
+ // PCLZIP_OPT_BY_INDEX :
+ // PCLZIP_OPT_BY_NAME :
+ // PCLZIP_OPT_BY_EREG :
+ // PCLZIP_OPT_BY_PREG :
+ // Return Values :
+ // 0 on failure,
+ // The list of the files which are still present in the archive.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ function delete()
+ {
+ $v_result=1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return(0);
+ }
+
+ // ----- Set default values
+ $v_options = array();
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Look for arguments
+ if ($v_size > 0) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+ array (PCLZIP_OPT_BY_NAME => 'optional',
+ PCLZIP_OPT_BY_EREG => 'optional',
+ PCLZIP_OPT_BY_PREG => 'optional',
+ PCLZIP_OPT_BY_INDEX => 'optional' ));
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Call the delete fct
+ $v_list = array();
+ if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {
+ $this->privSwapBackMagicQuotes();
+ unset($v_list);
+ return(0);
+ }
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : deleteByIndex()
+ // Description :
+ // ***** Deprecated *****
+ // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered.
+ // --------------------------------------------------------------------------------
+ function deleteByIndex($p_index)
+ {
+
+ $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);
+
+ // ----- Return
+ return $p_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : properties()
+ // Description :
+ // This method gives the properties of the archive.
+ // The properties are :
+ // nb : Number of files in the archive
+ // comment : Comment associated with the archive file
+ // status : not_exist, ok
+ // Parameters :
+ // None
+ // Return Values :
+ // 0 on failure,
+ // An array with the archive properties.
+ // --------------------------------------------------------------------------------
+ function properties()
+ {
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ $this->privSwapBackMagicQuotes();
+ return(0);
+ }
+
+ // ----- Default properties
+ $v_prop = array();
+ $v_prop['comment'] = '';
+ $v_prop['nb'] = 0;
+ $v_prop['status'] = 'not_exist';
+
+ // ----- Look if file exists
+ if (@is_file($this->zipname))
+ {
+ // ----- Open the zip file
+ if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
+ {
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
+
+ // ----- Return
+ return 0;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+ {
+ $this->privSwapBackMagicQuotes();
+ return 0;
+ }
+
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ // ----- Set the user attributes
+ $v_prop['comment'] = $v_central_dir['comment'];
+ $v_prop['nb'] = $v_central_dir['entries'];
+ $v_prop['status'] = 'ok';
+ }
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_prop;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : duplicate()
+ // Description :
+ // This method creates an archive by copying the content of an other one. If
+ // the archive already exist, it is replaced by the new one without any warning.
+ // Parameters :
+ // $p_archive : The filename of a valid archive, or
+ // a valid PclZip object.
+ // Return Values :
+ // 1 on success.
+ // 0 or a negative value on error (error code).
+ // --------------------------------------------------------------------------------
+ function duplicate($p_archive)
+ {
+ $v_result = 1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Look if the $p_archive is a PclZip object
+ if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip'))
+ {
+
+ // ----- Duplicate the archive
+ $v_result = $this->privDuplicate($p_archive->zipname);
+ }
+
+ // ----- Look if the $p_archive is a string (so a filename)
+ else if (is_string($p_archive))
+ {
+
+ // ----- Check that $p_archive is a valid zip file
+ // TBC : Should also check the archive format
+ if (!is_file($p_archive)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'");
+ $v_result = PCLZIP_ERR_MISSING_FILE;
+ }
+ else {
+ // ----- Duplicate the archive
+ $v_result = $this->privDuplicate($p_archive);
+ }
+ }
+
+ // ----- Invalid variable
+ else
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
+ $v_result = PCLZIP_ERR_INVALID_PARAMETER;
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : merge()
+ // Description :
+ // This method merge the $p_archive_to_add archive at the end of the current
+ // one ($this).
+ // If the archive ($this) does not exist, the merge becomes a duplicate.
+ // If the $p_archive_to_add archive does not exist, the merge is a success.
+ // Parameters :
+ // $p_archive_to_add : It can be directly the filename of a valid zip archive,
+ // or a PclZip object archive.
+ // Return Values :
+ // 1 on success,
+ // 0 or negative values on error (see below).
+ // --------------------------------------------------------------------------------
+ function merge($p_archive_to_add)
+ {
+ $v_result = 1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return(0);
+ }
+
+ // ----- Look if the $p_archive_to_add is a PclZip object
+ if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip'))
+ {
+
+ // ----- Merge the archive
+ $v_result = $this->privMerge($p_archive_to_add);
+ }
+
+ // ----- Look if the $p_archive_to_add is a string (so a filename)
+ else if (is_string($p_archive_to_add))
+ {
+
+ // ----- Create a temporary archive
+ $v_object_archive = new PclZip($p_archive_to_add);
+
+ // ----- Merge the archive
+ $v_result = $this->privMerge($v_object_archive);
+ }
+
+ // ----- Invalid variable
+ else
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
+ $v_result = PCLZIP_ERR_INVALID_PARAMETER;
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+
+
+ // --------------------------------------------------------------------------------
+ // Function : errorCode()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function errorCode()
+ {
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
+ return(PclErrorCode());
+ }
+ else {
+ return($this->error_code);
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : errorName()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function errorName($p_with_code=false)
+ {
+ $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',
+ PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
+ PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',
+ PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',
+ PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',
+ PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',
+ PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',
+ PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
+ PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',
+ PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',
+ PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',
+ PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',
+ PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',
+ PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',
+ PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
+ PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
+ PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
+ PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
+ PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION'
+ ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE'
+ ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION'
+ );
+
+ if (isset($v_name[$this->error_code])) {
+ $v_value = $v_name[$this->error_code];
+ }
+ else {
+ $v_value = 'NoName';
+ }
+
+ if ($p_with_code) {
+ return($v_value.' ('.$this->error_code.')');
+ }
+ else {
+ return($v_value);
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : errorInfo()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function errorInfo($p_full=false)
+ {
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
+ return(PclErrorString());
+ }
+ else {
+ if ($p_full) {
+ return($this->errorName(true)." : ".$this->error_string);
+ }
+ else {
+ return($this->error_string." [code ".$this->error_code."]");
+ }
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+
+// --------------------------------------------------------------------------------
+// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
+// ***** *****
+// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY *****
+// --------------------------------------------------------------------------------
+
+
+
+ // --------------------------------------------------------------------------------
+ // Function : privCheckFormat()
+ // Description :
+ // This method check that the archive exists and is a valid zip archive.
+ // Several level of check exists. (futur)
+ // Parameters :
+ // $p_level : Level of check. Default 0.
+ // 0 : Check the first bytes (magic codes) (default value))
+ // 1 : 0 + Check the central directory (futur)
+ // 2 : 1 + Check each file header (futur)
+ // Return Values :
+ // true on success,
+ // false on error, the error code is set.
+ // --------------------------------------------------------------------------------
+ function privCheckFormat($p_level=0)
+ {
+ $v_result = true;
+
+ // ----- Reset the file system cache
+ clearstatcache();
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Look if the file exits
+ if (!is_file($this->zipname)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'");
+ return(false);
+ }
+
+ // ----- Check that the file is readeable
+ if (!is_readable($this->zipname)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'");
+ return(false);
+ }
+
+ // ----- Check the magic code
+ // TBC
+
+ // ----- Check the central header
+ // TBC
+
+ // ----- Check each file header
+ // TBC
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privParseOptions()
+ // Description :
+ // This internal methods reads the variable list of arguments ($p_options_list,
+ // $p_size) and generate an array with the options and values ($v_result_list).
+ // $v_requested_options contains the options that can be present and those that
+ // must be present.
+ // $v_requested_options is an array, with the option value as key, and 'optional',
+ // or 'mandatory' as value.
+ // Parameters :
+ // See above.
+ // Return Values :
+ // 1 on success.
+ // 0 on failure.
+ // --------------------------------------------------------------------------------
+ function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false)
+ {
+ $v_result=1;
+
+ // ----- Read the options
+ $i=0;
+ while ($i<$p_size) {
+
+ // ----- Check if the option is supported
+ if (!isset($v_requested_options[$p_options_list[$i]])) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for next option
+ switch ($p_options_list[$i]) {
+ // ----- Look for options that request a path value
+ case PCLZIP_OPT_PATH :
+ case PCLZIP_OPT_REMOVE_PATH :
+ case PCLZIP_OPT_ADD_PATH :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
+ $i++;
+ break;
+
+ case PCLZIP_OPT_TEMP_FILE_THRESHOLD :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+ return PclZip::errorCode();
+ }
+
+ // ----- Check for incompatible options
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
+ return PclZip::errorCode();
+ }
+
+ // ----- Check the value
+ $v_value = $p_options_list[$i+1];
+ if ((!is_integer($v_value)) || ($v_value<0)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value (and convert it in bytes)
+ $v_result_list[$p_options_list[$i]] = $v_value*1048576;
+ $i++;
+ break;
+
+ case PCLZIP_OPT_TEMP_FILE_ON :
+ // ----- Check for incompatible options
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
+ return PclZip::errorCode();
+ }
+
+ $v_result_list[$p_options_list[$i]] = true;
+ break;
+
+ case PCLZIP_OPT_TEMP_FILE_OFF :
+ // ----- Check for incompatible options
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");
+ return PclZip::errorCode();
+ }
+ // ----- Check for incompatible options
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");
+ return PclZip::errorCode();
+ }
+
+ $v_result_list[$p_options_list[$i]] = true;
+ break;
+
+ case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ if ( is_string($p_options_list[$i+1])
+ && ($p_options_list[$i+1] != '')) {
+ $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
+ $i++;
+ }
+ else {
+ }
+ break;
+
+ // ----- Look for options that request an array of string for value
+ case PCLZIP_OPT_BY_NAME :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ if (is_string($p_options_list[$i+1])) {
+ $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1];
+ }
+ else if (is_array($p_options_list[$i+1])) {
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
+ }
+ else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ $i++;
+ break;
+
+ // ----- Look for options that request an EREG or PREG expression
+ case PCLZIP_OPT_BY_EREG :
+ // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG
+ // to PCLZIP_OPT_BY_PREG
+ $p_options_list[$i] = PCLZIP_OPT_BY_PREG;
+ case PCLZIP_OPT_BY_PREG :
+ //case PCLZIP_OPT_CRYPT :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ if (is_string($p_options_list[$i+1])) {
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
+ }
+ else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ $i++;
+ break;
+
+ // ----- Look for options that takes a string
+ case PCLZIP_OPT_COMMENT :
+ case PCLZIP_OPT_ADD_COMMENT :
+ case PCLZIP_OPT_PREPEND_COMMENT :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
+ "Missing parameter value for option '"
+ .PclZipUtilOptionText($p_options_list[$i])
+ ."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ if (is_string($p_options_list[$i+1])) {
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
+ }
+ else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
+ "Wrong parameter value for option '"
+ .PclZipUtilOptionText($p_options_list[$i])
+ ."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ $i++;
+ break;
+
+ // ----- Look for options that request an array of index
+ case PCLZIP_OPT_BY_INDEX :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ $v_work_list = array();
+ if (is_string($p_options_list[$i+1])) {
+
+ // ----- Remove spaces
+ $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', '');
+
+ // ----- Parse items
+ $v_work_list = explode(",", $p_options_list[$i+1]);
+ }
+ else if (is_integer($p_options_list[$i+1])) {
+ $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1];
+ }
+ else if (is_array($p_options_list[$i+1])) {
+ $v_work_list = $p_options_list[$i+1];
+ }
+ else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Reduce the index list
+ // each index item in the list must be a couple with a start and
+ // an end value : [0,3], [5-5], [8-10], ...
+ // ----- Check the format of each item
+ $v_sort_flag=false;
+ $v_sort_value=0;
+ for ($j=0; $j= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
+ $i++;
+ break;
+
+ // ----- Look for options that request a call-back
+ case PCLZIP_CB_PRE_EXTRACT :
+ case PCLZIP_CB_POST_EXTRACT :
+ case PCLZIP_CB_PRE_ADD :
+ case PCLZIP_CB_POST_ADD :
+ /* for futur use
+ case PCLZIP_CB_PRE_DELETE :
+ case PCLZIP_CB_POST_DELETE :
+ case PCLZIP_CB_PRE_LIST :
+ case PCLZIP_CB_POST_LIST :
+ */
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ $v_function_name = $p_options_list[$i+1];
+
+ // ----- Check that the value is a valid existing function
+ if (!function_exists($v_function_name)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Set the attribute
+ $v_result_list[$p_options_list[$i]] = $v_function_name;
+ $i++;
+ break;
+
+ default :
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
+ "Unknown parameter '"
+ .$p_options_list[$i]."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Next options
+ $i++;
+ }
+
+ // ----- Look for mandatory options
+ if ($v_requested_options !== false) {
+ for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
+ // ----- Look for mandatory option
+ if ($v_requested_options[$key] == 'mandatory') {
+ // ----- Look if present
+ if (!isset($v_result_list[$key])) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ }
+ }
+ }
+
+ // ----- Look for default values
+ if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
+
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privOptionDefaultThreshold()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privOptionDefaultThreshold(&$p_options)
+ {
+ $v_result=1;
+
+ if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
+ || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) {
+ return $v_result;
+ }
+
+ // ----- Get 'memory_limit' configuration value
+ $v_memory_limit = ini_get('memory_limit');
+ $v_memory_limit = trim($v_memory_limit);
+ $last = strtolower(substr($v_memory_limit, -1));
+
+ if($last == 'g')
+ //$v_memory_limit = $v_memory_limit*1024*1024*1024;
+ $v_memory_limit = $v_memory_limit*1073741824;
+ if($last == 'm')
+ //$v_memory_limit = $v_memory_limit*1024*1024;
+ $v_memory_limit = $v_memory_limit*1048576;
+ if($last == 'k')
+ $v_memory_limit = $v_memory_limit*1024;
+
+ $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO);
+
+
+ // ----- Sanity check : No threshold if value lower than 1M
+ if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {
+ unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privFileDescrParseAtt()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // 1 on success.
+ // 0 on failure.
+ // --------------------------------------------------------------------------------
+ function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false)
+ {
+ $v_result=1;
+
+ // ----- For each file in the list check the attributes
+ foreach ($p_file_list as $v_key => $v_value) {
+
+ // ----- Check if the option is supported
+ if (!isset($v_requested_options[$v_key])) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for attribute
+ switch ($v_key) {
+ case PCLZIP_ATT_FILE_NAME :
+ if (!is_string($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);
+
+ if ($p_filedescr['filename'] == '') {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+
+ break;
+
+ case PCLZIP_ATT_FILE_NEW_SHORT_NAME :
+ if (!is_string($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);
+
+ if ($p_filedescr['new_short_name'] == '') {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+ break;
+
+ case PCLZIP_ATT_FILE_NEW_FULL_NAME :
+ if (!is_string($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);
+
+ if ($p_filedescr['new_full_name'] == '') {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+ break;
+
+ // ----- Look for options that takes a string
+ case PCLZIP_ATT_FILE_COMMENT :
+ if (!is_string($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['comment'] = $v_value;
+ break;
+
+ case PCLZIP_ATT_FILE_MTIME :
+ if (!is_integer($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['mtime'] = $v_value;
+ break;
+
+ case PCLZIP_ATT_FILE_CONTENT :
+ $p_filedescr['content'] = $v_value;
+ break;
+
+ default :
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
+ "Unknown parameter '".$v_key."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for mandatory options
+ if ($v_requested_options !== false) {
+ for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
+ // ----- Look for mandatory option
+ if ($v_requested_options[$key] == 'mandatory') {
+ // ----- Look if present
+ if (!isset($p_file_list[$key])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
+ return PclZip::errorCode();
+ }
+ }
+ }
+ }
+
+ // end foreach
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privFileDescrExpand()
+ // Description :
+ // This method look for each item of the list to see if its a file, a folder
+ // or a string to be added as file. For any other type of files (link, other)
+ // just ignore the item.
+ // Then prepare the information that will be stored for that file.
+ // When its a folder, expand the folder with all the files that are in that
+ // folder (recursively).
+ // Parameters :
+ // Return Values :
+ // 1 on success.
+ // 0 on failure.
+ // --------------------------------------------------------------------------------
+ function privFileDescrExpand(&$p_filedescr_list, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Create a result list
+ $v_result_list = array();
+
+ // ----- Look each entry
+ for ($i=0; $iprivCalculateStoredFilename($v_descr, $p_options);
+
+ // ----- Add the descriptor in result list
+ $v_result_list[sizeof($v_result_list)] = $v_descr;
+
+ // ----- Look for folder
+ if ($v_descr['type'] == 'folder') {
+ // ----- List of items in folder
+ $v_dirlist_descr = array();
+ $v_dirlist_nb = 0;
+ if ($v_folder_handler = @opendir($v_descr['filename'])) {
+ while (($v_item_handler = @readdir($v_folder_handler)) !== false) {
+
+ // ----- Skip '.' and '..'
+ if (($v_item_handler == '.') || ($v_item_handler == '..')) {
+ continue;
+ }
+
+ // ----- Compose the full filename
+ $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler;
+
+ // ----- Look for different stored filename
+ // Because the name of the folder was changed, the name of the
+ // files/sub-folders also change
+ if (($v_descr['stored_filename'] != $v_descr['filename'])
+ && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {
+ if ($v_descr['stored_filename'] != '') {
+ $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler;
+ }
+ else {
+ $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;
+ }
+ }
+
+ $v_dirlist_nb++;
+ }
+
+ @closedir($v_folder_handler);
+ }
+ else {
+ // TBC : unable to open folder in read mode
+ }
+
+ // ----- Expand each element of the list
+ if ($v_dirlist_nb != 0) {
+ // ----- Expand
+ if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) {
+ return $v_result;
+ }
+
+ // ----- Concat the resulting list
+ $v_result_list = array_merge($v_result_list, $v_dirlist_descr);
+ }
+ else {
+ }
+
+ // ----- Free local array
+ unset($v_dirlist_descr);
+ }
+ }
+
+ // ----- Get the result list
+ $p_filedescr_list = $v_result_list;
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCreate()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privCreate($p_filedescr_list, &$p_result_list, &$p_options)
+ {
+ $v_result=1;
+ $v_list_detail = array();
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Open the file in write mode
+ if (($v_result = $this->privOpenFd('wb')) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Add the list of files
+ $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);
+
+ // ----- Close
+ $this->privCloseFd();
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAdd()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privAdd($p_filedescr_list, &$p_result_list, &$p_options)
+ {
+ $v_result=1;
+ $v_list_detail = array();
+
+ // ----- Look if the archive exists or is empty
+ if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0))
+ {
+
+ // ----- Do a create
+ $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);
+
+ // ----- Return
+ return $v_result;
+ }
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Open the zip file
+ if (($v_result=$this->privOpenFd('rb')) != 1)
+ {
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+ {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+ return $v_result;
+ }
+
+ // ----- Go to beginning of File
+ @rewind($this->zip_fd);
+
+ // ----- Creates a temporay file
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
+
+ // ----- Open the temporary file in write mode
+ if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
+ {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Copy the files from the archive to the temporary file
+ // TBC : Here I should better append the file and go back to erase the central dir
+ $v_size = $v_central_dir['offset'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = fread($this->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Swap the file descriptor
+ // Here is a trick : I swap the temporary fd with the zip fd, in order to use
+ // the following methods on the temporary fil and not the real archive
+ $v_swap = $this->zip_fd;
+ $this->zip_fd = $v_zip_temp_fd;
+ $v_zip_temp_fd = $v_swap;
+
+ // ----- Add the files
+ $v_header_list = array();
+ if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
+ {
+ fclose($v_zip_temp_fd);
+ $this->privCloseFd();
+ @unlink($v_zip_temp_name);
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Store the offset of the central dir
+ $v_offset = @ftell($this->zip_fd);
+
+ // ----- Copy the block of file headers from the old archive
+ $v_size = $v_central_dir['size'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($v_zip_temp_fd, $v_read_size);
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Create the Central Dir files header
+ for ($i=0, $v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) {
+ fclose($v_zip_temp_fd);
+ $this->privCloseFd();
+ @unlink($v_zip_temp_name);
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+ $v_count++;
+ }
+
+ // ----- Transform the header to a 'usable' info
+ $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
+ }
+
+ // ----- Zip file comment
+ $v_comment = $v_central_dir['comment'];
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
+ }
+ if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {
+ $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT];
+ }
+ if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {
+ $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment;
+ }
+
+ // ----- Calculate the size of the central header
+ $v_size = @ftell($this->zip_fd)-$v_offset;
+
+ // ----- Create the central dir footer
+ if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1)
+ {
+ // ----- Reset the file list
+ unset($v_header_list);
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Swap back the file descriptor
+ $v_swap = $this->zip_fd;
+ $this->zip_fd = $v_zip_temp_fd;
+ $v_zip_temp_fd = $v_swap;
+
+ // ----- Close
+ $this->privCloseFd();
+
+ // ----- Close the temporary file
+ @fclose($v_zip_temp_fd);
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Delete the zip file
+ // TBC : I should test the result ...
+ @unlink($this->zipname);
+
+ // ----- Rename the temporary file
+ // TBC : I should test the result ...
+ //@rename($v_zip_temp_name, $this->zipname);
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privOpenFd()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function privOpenFd($p_mode)
+ {
+ $v_result=1;
+
+ // ----- Look if already open
+ if ($this->zip_fd != 0)
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Open the zip file
+ if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0)
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCloseFd()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function privCloseFd()
+ {
+ $v_result=1;
+
+ if ($this->zip_fd != 0)
+ @fclose($this->zip_fd);
+ $this->zip_fd = 0;
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAddList()
+ // Description :
+ // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
+ // different from the real path of the file. This is usefull if you want to have PclTar
+ // running in any directory, and memorize relative path from an other directory.
+ // Parameters :
+ // $p_list : An array containing the file or directory names to add in the tar
+ // $p_result_list : list of added files with their properties (specially the status field)
+ // $p_add_dir : Path to add in the filename path archived
+ // $p_remove_dir : Path to remove in the filename path archived
+ // Return Values :
+ // --------------------------------------------------------------------------------
+// function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)
+ function privAddList($p_filedescr_list, &$p_result_list, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Add the files
+ $v_header_list = array();
+ if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Store the offset of the central dir
+ $v_offset = @ftell($this->zip_fd);
+
+ // ----- Create the Central Dir files header
+ for ($i=0,$v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) {
+ // ----- Return
+ return $v_result;
+ }
+ $v_count++;
+ }
+
+ // ----- Transform the header to a 'usable' info
+ $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
+ }
+
+ // ----- Zip file comment
+ $v_comment = '';
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
+ }
+
+ // ----- Calculate the size of the central header
+ $v_size = @ftell($this->zip_fd)-$v_offset;
+
+ // ----- Create the central dir footer
+ if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1)
+ {
+ // ----- Reset the file list
+ unset($v_header_list);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAddFileList()
+ // Description :
+ // Parameters :
+ // $p_filedescr_list : An array containing the file description
+ // or directory names to add in the zip
+ // $p_result_list : list of added files with their properties (specially the status field)
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options)
+ {
+ $v_result=1;
+ $v_header = array();
+
+ // ----- Recuperate the current number of elt in list
+ $v_nb = sizeof($p_result_list);
+
+ // ----- Loop on the files
+ for ($j=0; ($jprivAddFile($p_filedescr_list[$j], $v_header,
+ $p_options);
+ if ($v_result != 1) {
+ return $v_result;
+ }
+
+ // ----- Store the file infos
+ $p_result_list[$v_nb++] = $v_header;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAddFile()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privAddFile($p_filedescr, &$p_header, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Working variable
+ $p_filename = $p_filedescr['filename'];
+
+ // TBC : Already done in the fileAtt check ... ?
+ if ($p_filename == "") {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for a stored different filename
+ /* TBC : Removed
+ if (isset($p_filedescr['stored_filename'])) {
+ $v_stored_filename = $p_filedescr['stored_filename'];
+ }
+ else {
+ $v_stored_filename = $p_filedescr['stored_filename'];
+ }
+ */
+
+ // ----- Set the file properties
+ clearstatcache();
+ $p_header['version'] = 20;
+ $p_header['version_extracted'] = 10;
+ $p_header['flag'] = 0;
+ $p_header['compression'] = 0;
+ $p_header['crc'] = 0;
+ $p_header['compressed_size'] = 0;
+ $p_header['filename_len'] = strlen($p_filename);
+ $p_header['extra_len'] = 0;
+ $p_header['disk'] = 0;
+ $p_header['internal'] = 0;
+ $p_header['offset'] = 0;
+ $p_header['filename'] = $p_filename;
+// TBC : Removed $p_header['stored_filename'] = $v_stored_filename;
+ $p_header['stored_filename'] = $p_filedescr['stored_filename'];
+ $p_header['extra'] = '';
+ $p_header['status'] = 'ok';
+ $p_header['index'] = -1;
+
+ // ----- Look for regular file
+ if ($p_filedescr['type']=='file') {
+ $p_header['external'] = 0x00000000;
+ $p_header['size'] = filesize($p_filename);
+ }
+
+ // ----- Look for regular folder
+ else if ($p_filedescr['type']=='folder') {
+ $p_header['external'] = 0x00000010;
+ $p_header['mtime'] = filemtime($p_filename);
+ $p_header['size'] = filesize($p_filename);
+ }
+
+ // ----- Look for virtual file
+ else if ($p_filedescr['type'] == 'virtual_file') {
+ $p_header['external'] = 0x00000000;
+ $p_header['size'] = strlen($p_filedescr['content']);
+ }
+
+
+ // ----- Look for filetime
+ if (isset($p_filedescr['mtime'])) {
+ $p_header['mtime'] = $p_filedescr['mtime'];
+ }
+ else if ($p_filedescr['type'] == 'virtual_file') {
+ $p_header['mtime'] = time();
+ }
+ else {
+ $p_header['mtime'] = filemtime($p_filename);
+ }
+
+ // ------ Look for file comment
+ if (isset($p_filedescr['comment'])) {
+ $p_header['comment_len'] = strlen($p_filedescr['comment']);
+ $p_header['comment'] = $p_filedescr['comment'];
+ }
+ else {
+ $p_header['comment_len'] = 0;
+ $p_header['comment'] = '';
+ }
+
+ // ----- Look for pre-add callback
+ if (isset($p_options[PCLZIP_CB_PRE_ADD])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_header, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Change the file status
+ $p_header['status'] = "skipped";
+ $v_result = 1;
+ }
+
+ // ----- Update the informations
+ // Only some fields can be modified
+ if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
+ $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);
+ }
+ }
+
+ // ----- Look for empty stored filename
+ if ($p_header['stored_filename'] == "") {
+ $p_header['status'] = "filtered";
+ }
+
+ // ----- Check the path length
+ if (strlen($p_header['stored_filename']) > 0xFF) {
+ $p_header['status'] = 'filename_too_long';
+ }
+
+ // ----- Look if no error, or file not skipped
+ if ($p_header['status'] == 'ok') {
+
+ // ----- Look for a file
+ if ($p_filedescr['type'] == 'file') {
+ // ----- Look for using temporary file to zip
+ if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
+ && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
+ || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
+ && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) {
+ $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);
+ if ($v_result < PCLZIP_ERR_NO_ERROR) {
+ return $v_result;
+ }
+ }
+
+ // ----- Use "in memory" zip algo
+ else {
+
+ // ----- Open the source file
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file content
+ $v_content = @fread($v_file, $p_header['size']);
+
+ // ----- Close the file
+ @fclose($v_file);
+
+ // ----- Calculate the CRC
+ $p_header['crc'] = @crc32($v_content);
+
+ // ----- Look for no compression
+ if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
+ // ----- Set header parameters
+ $p_header['compressed_size'] = $p_header['size'];
+ $p_header['compression'] = 0;
+ }
+
+ // ----- Look for normal compression
+ else {
+ // ----- Compress the content
+ $v_content = @gzdeflate($v_content);
+
+ // ----- Set header parameters
+ $p_header['compressed_size'] = strlen($v_content);
+ $p_header['compression'] = 8;
+ }
+
+ // ----- Call the header generation
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+ @fclose($v_file);
+ return $v_result;
+ }
+
+ // ----- Write the compressed (or not) content
+ @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
+
+ }
+
+ }
+
+ // ----- Look for a virtual file (a file from string)
+ else if ($p_filedescr['type'] == 'virtual_file') {
+
+ $v_content = $p_filedescr['content'];
+
+ // ----- Calculate the CRC
+ $p_header['crc'] = @crc32($v_content);
+
+ // ----- Look for no compression
+ if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
+ // ----- Set header parameters
+ $p_header['compressed_size'] = $p_header['size'];
+ $p_header['compression'] = 0;
+ }
+
+ // ----- Look for normal compression
+ else {
+ // ----- Compress the content
+ $v_content = @gzdeflate($v_content);
+
+ // ----- Set header parameters
+ $p_header['compressed_size'] = strlen($v_content);
+ $p_header['compression'] = 8;
+ }
+
+ // ----- Call the header generation
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+ @fclose($v_file);
+ return $v_result;
+ }
+
+ // ----- Write the compressed (or not) content
+ @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
+ }
+
+ // ----- Look for a directory
+ else if ($p_filedescr['type'] == 'folder') {
+ // ----- Look for directory last '/'
+ if (@substr($p_header['stored_filename'], -1) != '/') {
+ $p_header['stored_filename'] .= '/';
+ }
+
+ // ----- Set the file properties
+ $p_header['size'] = 0;
+ //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked
+ $p_header['external'] = 0x00000010; // Value for a folder : to be checked
+
+ // ----- Call the header generation
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1)
+ {
+ return $v_result;
+ }
+ }
+ }
+
+ // ----- Look for post-add callback
+ if (isset($p_options[PCLZIP_CB_POST_ADD])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_header, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+// eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Ignored
+ $v_result = 1;
+ }
+
+ // ----- Update the informations
+ // Nothing can be modified
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAddFileUsingTempFile()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options)
+ {
+ $v_result=PCLZIP_ERR_NO_ERROR;
+
+ // ----- Working variable
+ $p_filename = $p_filedescr['filename'];
+
+
+ // ----- Open the source file
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
+ return PclZip::errorCode();
+ }
+
+ // ----- Creates a compressed temporary file
+ $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
+ if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) {
+ fclose($v_file);
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ $v_size = filesize($p_filename);
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($v_file, $v_read_size);
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @gzputs($v_file_compressed, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Close the file
+ @fclose($v_file);
+ @gzclose($v_file_compressed);
+
+ // ----- Check the minimum file size
+ if (filesize($v_gzip_temp_name) < 18) {
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes');
+ return PclZip::errorCode();
+ }
+
+ // ----- Extract the compressed attributes
+ if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the gzip file header
+ $v_binary_data = @fread($v_file_compressed, 10);
+ $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);
+
+ // ----- Check some parameters
+ $v_data_header['os'] = bin2hex($v_data_header['os']);
+
+ // ----- Read the gzip file footer
+ @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8);
+ $v_binary_data = @fread($v_file_compressed, 8);
+ $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);
+
+ // ----- Set the attributes
+ $p_header['compression'] = ord($v_data_header['cm']);
+ //$p_header['mtime'] = $v_data_header['mtime'];
+ $p_header['crc'] = $v_data_footer['crc'];
+ $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18;
+
+ // ----- Close the file
+ @fclose($v_file_compressed);
+
+ // ----- Call the header generation
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+ return $v_result;
+ }
+
+ // ----- Add the compressed data
+ if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0)
+ {
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ fseek($v_file_compressed, 10);
+ $v_size = $p_header['compressed_size'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($v_file_compressed, $v_read_size);
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Close the file
+ @fclose($v_file_compressed);
+
+ // ----- Unlink the temporary file
+ @unlink($v_gzip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCalculateStoredFilename()
+ // Description :
+ // Based on file descriptor properties and global options, this method
+ // calculate the filename that will be stored in the archive.
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privCalculateStoredFilename(&$p_filedescr, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Working variables
+ $p_filename = $p_filedescr['filename'];
+ if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {
+ $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];
+ }
+ else {
+ $p_add_dir = '';
+ }
+ if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {
+ $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];
+ }
+ else {
+ $p_remove_dir = '';
+ }
+ if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
+ $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];
+ }
+ else {
+ $p_remove_all_dir = 0;
+ }
+
+
+ // ----- Look for full name change
+ if (isset($p_filedescr['new_full_name'])) {
+ // ----- Remove drive letter if any
+ $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);
+ }
+
+ // ----- Look for path and/or short name change
+ else {
+
+ // ----- Look for short name change
+ // Its when we cahnge just the filename but not the path
+ if (isset($p_filedescr['new_short_name'])) {
+ $v_path_info = pathinfo($p_filename);
+ $v_dir = '';
+ if ($v_path_info['dirname'] != '') {
+ $v_dir = $v_path_info['dirname'].'/';
+ }
+ $v_stored_filename = $v_dir.$p_filedescr['new_short_name'];
+ }
+ else {
+ // ----- Calculate the stored filename
+ $v_stored_filename = $p_filename;
+ }
+
+ // ----- Look for all path to remove
+ if ($p_remove_all_dir) {
+ $v_stored_filename = basename($p_filename);
+ }
+ // ----- Look for partial path remove
+ else if ($p_remove_dir != "") {
+ if (substr($p_remove_dir, -1) != '/')
+ $p_remove_dir .= "/";
+
+ if ( (substr($p_filename, 0, 2) == "./")
+ || (substr($p_remove_dir, 0, 2) == "./")) {
+
+ if ( (substr($p_filename, 0, 2) == "./")
+ && (substr($p_remove_dir, 0, 2) != "./")) {
+ $p_remove_dir = "./".$p_remove_dir;
+ }
+ if ( (substr($p_filename, 0, 2) != "./")
+ && (substr($p_remove_dir, 0, 2) == "./")) {
+ $p_remove_dir = substr($p_remove_dir, 2);
+ }
+ }
+
+ $v_compare = PclZipUtilPathInclusion($p_remove_dir,
+ $v_stored_filename);
+ if ($v_compare > 0) {
+ if ($v_compare == 2) {
+ $v_stored_filename = "";
+ }
+ else {
+ $v_stored_filename = substr($v_stored_filename,
+ strlen($p_remove_dir));
+ }
+ }
+ }
+
+ // ----- Remove drive letter if any
+ $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);
+
+ // ----- Look for path to add
+ if ($p_add_dir != "") {
+ if (substr($p_add_dir, -1) == "/")
+ $v_stored_filename = $p_add_dir.$v_stored_filename;
+ else
+ $v_stored_filename = $p_add_dir."/".$v_stored_filename;
+ }
+ }
+
+ // ----- Filename (reduce the path of stored name)
+ $v_stored_filename = PclZipUtilPathReduction($v_stored_filename);
+ $p_filedescr['stored_filename'] = $v_stored_filename;
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privWriteFileHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privWriteFileHeader(&$p_header)
+ {
+ $v_result=1;
+
+ // ----- Store the offset position of the file
+ $p_header['offset'] = ftell($this->zip_fd);
+
+ // ----- Transform UNIX mtime to DOS format mdate/mtime
+ $v_date = getdate($p_header['mtime']);
+ $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
+ $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
+
+ // ----- Packed data
+ $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50,
+ $p_header['version_extracted'], $p_header['flag'],
+ $p_header['compression'], $v_mtime, $v_mdate,
+ $p_header['crc'], $p_header['compressed_size'],
+ $p_header['size'],
+ strlen($p_header['stored_filename']),
+ $p_header['extra_len']);
+
+ // ----- Write the first 148 bytes of the header in the archive
+ fputs($this->zip_fd, $v_binary_data, 30);
+
+ // ----- Write the variable fields
+ if (strlen($p_header['stored_filename']) != 0)
+ {
+ fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
+ }
+ if ($p_header['extra_len'] != 0)
+ {
+ fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privWriteCentralFileHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privWriteCentralFileHeader(&$p_header)
+ {
+ $v_result=1;
+
+ // TBC
+ //for(reset($p_header); $key = key($p_header); next($p_header)) {
+ //}
+
+ // ----- Transform UNIX mtime to DOS format mdate/mtime
+ $v_date = getdate($p_header['mtime']);
+ $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
+ $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
+
+
+ // ----- Packed data
+ $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50,
+ $p_header['version'], $p_header['version_extracted'],
+ $p_header['flag'], $p_header['compression'],
+ $v_mtime, $v_mdate, $p_header['crc'],
+ $p_header['compressed_size'], $p_header['size'],
+ strlen($p_header['stored_filename']),
+ $p_header['extra_len'], $p_header['comment_len'],
+ $p_header['disk'], $p_header['internal'],
+ $p_header['external'], $p_header['offset']);
+
+ // ----- Write the 42 bytes of the header in the zip file
+ fputs($this->zip_fd, $v_binary_data, 46);
+
+ // ----- Write the variable fields
+ if (strlen($p_header['stored_filename']) != 0)
+ {
+ fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
+ }
+ if ($p_header['extra_len'] != 0)
+ {
+ fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
+ }
+ if ($p_header['comment_len'] != 0)
+ {
+ fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privWriteCentralHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)
+ {
+ $v_result=1;
+
+ // ----- Packed data
+ $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries,
+ $p_nb_entries, $p_size,
+ $p_offset, strlen($p_comment));
+
+ // ----- Write the 22 bytes of the header in the zip file
+ fputs($this->zip_fd, $v_binary_data, 22);
+
+ // ----- Write the variable fields
+ if (strlen($p_comment) != 0)
+ {
+ fputs($this->zip_fd, $p_comment, strlen($p_comment));
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privList()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privList(&$p_list)
+ {
+ $v_result=1;
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Open the zip file
+ if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
+ {
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+ {
+ $this->privSwapBackMagicQuotes();
+ return $v_result;
+ }
+
+ // ----- Go to beginning of Central Dir
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_central_dir['offset']))
+ {
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read each entry
+ for ($i=0; $i<$v_central_dir['entries']; $i++)
+ {
+ // ----- Read the file header
+ if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1)
+ {
+ $this->privSwapBackMagicQuotes();
+ return $v_result;
+ }
+ $v_header['index'] = $i;
+
+ // ----- Get the only interesting attributes
+ $this->privConvertHeader2FileInfo($v_header, $p_list[$i]);
+ unset($v_header);
+ }
+
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privConvertHeader2FileInfo()
+ // Description :
+ // This function takes the file informations from the central directory
+ // entries and extract the interesting parameters that will be given back.
+ // The resulting file infos are set in the array $p_info
+ // $p_info['filename'] : Filename with full path. Given by user (add),
+ // extracted in the filesystem (extract).
+ // $p_info['stored_filename'] : Stored filename in the archive.
+ // $p_info['size'] = Size of the file.
+ // $p_info['compressed_size'] = Compressed size of the file.
+ // $p_info['mtime'] = Last modification date of the file.
+ // $p_info['comment'] = Comment associated with the file.
+ // $p_info['folder'] = true/false : indicates if the entry is a folder or not.
+ // $p_info['status'] = status of the action on the file.
+ // $p_info['crc'] = CRC of the file content.
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privConvertHeader2FileInfo($p_header, &$p_info)
+ {
+ $v_result=1;
+
+ // ----- Get the interesting attributes
+ $v_temp_path = PclZipUtilPathReduction($p_header['filename']);
+ $p_info['filename'] = $v_temp_path;
+ $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']);
+ $p_info['stored_filename'] = $v_temp_path;
+ $p_info['size'] = $p_header['size'];
+ $p_info['compressed_size'] = $p_header['compressed_size'];
+ $p_info['mtime'] = $p_header['mtime'];
+ $p_info['comment'] = $p_header['comment'];
+ $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010);
+ $p_info['index'] = $p_header['index'];
+ $p_info['status'] = $p_header['status'];
+ $p_info['crc'] = $p_header['crc'];
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractByRule()
+ // Description :
+ // Extract a file or directory depending of rules (by index, by name, ...)
+ // Parameters :
+ // $p_file_list : An array where will be placed the properties of each
+ // extracted file
+ // $p_path : Path to add while writing the extracted files
+ // $p_remove_path : Path to remove (from the file memorized path) while writing the
+ // extracted files. If the path does not match the file path,
+ // the file is extracted with its memorized path.
+ // $p_remove_path does not apply to 'list' mode.
+ // $p_path and $p_remove_path are commulative.
+ // Return Values :
+ // 1 on success,0 or less on error (see error code list)
+ // --------------------------------------------------------------------------------
+ function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Check the path
+ if ( ($p_path == "")
+ || ( (substr($p_path, 0, 1) != "/")
+ && (substr($p_path, 0, 3) != "../")
+ && (substr($p_path,1,2)!=":/")))
+ $p_path = "./".$p_path;
+
+ // ----- Reduce the path last (and duplicated) '/'
+ if (($p_path != "./") && ($p_path != "/"))
+ {
+ // ----- Look for the path end '/'
+ while (substr($p_path, -1) == "/")
+ {
+ $p_path = substr($p_path, 0, strlen($p_path)-1);
+ }
+ }
+
+ // ----- Look for path to remove format (should end by /)
+ if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/'))
+ {
+ $p_remove_path .= '/';
+ }
+ $p_remove_path_size = strlen($p_remove_path);
+
+ // ----- Open the zip file
+ if (($v_result = $this->privOpenFd('rb')) != 1)
+ {
+ $this->privSwapBackMagicQuotes();
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Start at beginning of Central Dir
+ $v_pos_entry = $v_central_dir['offset'];
+
+ // ----- Read each entry
+ $j_start = 0;
+ for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++)
+ {
+
+ // ----- Read next Central dir entry
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_pos_entry))
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file header
+ $v_header = array();
+ if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1)
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Store the index
+ $v_header['index'] = $i;
+
+ // ----- Store the file position
+ $v_pos_entry = ftell($this->zip_fd);
+
+ // ----- Look for the specific extract rules
+ $v_extract = false;
+
+ // ----- Look for extract by name rule
+ if ( (isset($p_options[PCLZIP_OPT_BY_NAME]))
+ && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
+
+ // ----- Look if the filename is in the list
+ for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
+ && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
+ $v_extract = true;
+ }
+ }
+ // ----- Look for a filename
+ elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
+ $v_extract = true;
+ }
+ }
+ }
+
+ // ----- Look for extract by ereg rule
+ // ereg() is deprecated with PHP 5.3
+ /*
+ else if ( (isset($p_options[PCLZIP_OPT_BY_EREG]))
+ && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
+
+ if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) {
+ $v_extract = true;
+ }
+ }
+ */
+
+ // ----- Look for extract by preg rule
+ else if ( (isset($p_options[PCLZIP_OPT_BY_PREG]))
+ && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
+
+ if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) {
+ $v_extract = true;
+ }
+ }
+
+ // ----- Look for extract by index rule
+ else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX]))
+ && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
+
+ // ----- Look if the index is in the list
+ for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
+ $v_extract = true;
+ }
+ if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
+ $j_start = $j+1;
+ }
+
+ if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
+ break;
+ }
+ }
+ }
+
+ // ----- Look for no rule, which means extract all the archive
+ else {
+ $v_extract = true;
+ }
+
+ // ----- Check compression method
+ if ( ($v_extract)
+ && ( ($v_header['compression'] != 8)
+ && ($v_header['compression'] != 0))) {
+ $v_header['status'] = 'unsupported_compression';
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+ $this->privSwapBackMagicQuotes();
+
+ PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION,
+ "Filename '".$v_header['stored_filename']."' is "
+ ."compressed by an unsupported compression "
+ ."method (".$v_header['compression'].") ");
+
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Check encrypted files
+ if (($v_extract) && (($v_header['flag'] & 1) == 1)) {
+ $v_header['status'] = 'unsupported_encryption';
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+ $this->privSwapBackMagicQuotes();
+
+ PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION,
+ "Unsupported encryption for "
+ ." filename '".$v_header['stored_filename']
+ ."'");
+
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Look for real extraction
+ if (($v_extract) && ($v_header['status'] != 'ok')) {
+ $v_result = $this->privConvertHeader2FileInfo($v_header,
+ $p_file_list[$v_nb_extracted++]);
+ if ($v_result != 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+ return $v_result;
+ }
+
+ $v_extract = false;
+ }
+
+ // ----- Look for real extraction
+ if ($v_extract)
+ {
+
+ // ----- Go to the file position
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_header['offset']))
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for extraction as string
+ if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {
+
+ $v_string = '';
+
+ // ----- Extracting the file
+ $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);
+ if ($v_result1 < 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+ return $v_result1;
+ }
+
+ // ----- Get the only interesting attributes
+ if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1)
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Set the file content
+ $p_file_list[$v_nb_extracted]['content'] = $v_string;
+
+ // ----- Next extracted file
+ $v_nb_extracted++;
+
+ // ----- Look for user callback abort
+ if ($v_result1 == 2) {
+ break;
+ }
+ }
+ // ----- Look for extraction in standard output
+ elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT]))
+ && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) {
+ // ----- Extracting the file in standard output
+ $v_result1 = $this->privExtractFileInOutput($v_header, $p_options);
+ if ($v_result1 < 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+ return $v_result1;
+ }
+
+ // ----- Get the only interesting attributes
+ if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+ return $v_result;
+ }
+
+ // ----- Look for user callback abort
+ if ($v_result1 == 2) {
+ break;
+ }
+ }
+ // ----- Look for normal extraction
+ else {
+ // ----- Extracting the file
+ $v_result1 = $this->privExtractFile($v_header,
+ $p_path, $p_remove_path,
+ $p_remove_all_path,
+ $p_options);
+ if ($v_result1 < 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+ return $v_result1;
+ }
+
+ // ----- Get the only interesting attributes
+ if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1)
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Look for user callback abort
+ if ($v_result1 == 2) {
+ break;
+ }
+ }
+ }
+ }
+
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractFile()
+ // Description :
+ // Parameters :
+ // Return Values :
+ //
+ // 1 : ... ?
+ // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback
+ // --------------------------------------------------------------------------------
+ function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Read the file header
+ if (($v_result = $this->privReadFileHeader($v_header)) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+
+ // ----- Check that the file header is coherent with $p_entry info
+ if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
+ // TBC
+ }
+
+ // ----- Look for all path to remove
+ if ($p_remove_all_path == true) {
+ // ----- Look for folder entry that not need to be extracted
+ if (($p_entry['external']&0x00000010)==0x00000010) {
+
+ $p_entry['status'] = "filtered";
+
+ return $v_result;
+ }
+
+ // ----- Get the basename of the path
+ $p_entry['filename'] = basename($p_entry['filename']);
+ }
+
+ // ----- Look for path to remove
+ else if ($p_remove_path != "")
+ {
+ if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2)
+ {
+
+ // ----- Change the file status
+ $p_entry['status'] = "filtered";
+
+ // ----- Return
+ return $v_result;
+ }
+
+ $p_remove_path_size = strlen($p_remove_path);
+ if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path)
+ {
+
+ // ----- Remove the path
+ $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
+
+ }
+ }
+
+ // ----- Add the path
+ if ($p_path != '') {
+ $p_entry['filename'] = $p_path."/".$p_entry['filename'];
+ }
+
+ // ----- Check a base_dir_restriction
+ if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {
+ $v_inclusion
+ = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION],
+ $p_entry['filename']);
+ if ($v_inclusion == 0) {
+
+ PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION,
+ "Filename '".$p_entry['filename']."' is "
+ ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION");
+
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Look for pre-extract callback
+ if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Change the file status
+ $p_entry['status'] = "skipped";
+ $v_result = 1;
+ }
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ // ----- This status is internal and will be changed in 'skipped'
+ $p_entry['status'] = "aborted";
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+
+ // ----- Update the informations
+ // Only some fields can be modified
+ $p_entry['filename'] = $v_local_header['filename'];
+ }
+
+
+ // ----- Look if extraction should be done
+ if ($p_entry['status'] == 'ok') {
+
+ // ----- Look for specific actions while the file exist
+ if (file_exists($p_entry['filename']))
+ {
+
+ // ----- Look if file is a directory
+ if (is_dir($p_entry['filename']))
+ {
+
+ // ----- Change the file status
+ $p_entry['status'] = "already_a_directory";
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ // For historical reason first PclZip implementation does not stop
+ // when this kind of error occurs.
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+ PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY,
+ "Filename '".$p_entry['filename']."' is "
+ ."already used by an existing directory");
+
+ return PclZip::errorCode();
+ }
+ }
+ // ----- Look if file is write protected
+ else if (!is_writeable($p_entry['filename']))
+ {
+
+ // ----- Change the file status
+ $p_entry['status'] = "write_protected";
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ // For historical reason first PclZip implementation does not stop
+ // when this kind of error occurs.
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
+ "Filename '".$p_entry['filename']."' exists "
+ ."and is write protected");
+
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Look if the extracted file is older
+ else if (filemtime($p_entry['filename']) > $p_entry['mtime'])
+ {
+ // ----- Change the file status
+ if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER]))
+ && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) {
+ }
+ else {
+ $p_entry['status'] = "newer_exist";
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ // For historical reason first PclZip implementation does not stop
+ // when this kind of error occurs.
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
+ "Newer version of '".$p_entry['filename']."' exists "
+ ."and option PCLZIP_OPT_REPLACE_NEWER is not selected");
+
+ return PclZip::errorCode();
+ }
+ }
+ }
+ else {
+ }
+ }
+
+ // ----- Check the directory availability and create it if necessary
+ else {
+ if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/'))
+ $v_dir_to_check = $p_entry['filename'];
+ else if (!strstr($p_entry['filename'], "/"))
+ $v_dir_to_check = "";
+ else
+ $v_dir_to_check = dirname($p_entry['filename']);
+
+ if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) {
+
+ // ----- Change the file status
+ $p_entry['status'] = "path_creation_fail";
+
+ // ----- Return
+ //return $v_result;
+ $v_result = 1;
+ }
+ }
+ }
+
+ // ----- Look if extraction should be done
+ if ($p_entry['status'] == 'ok') {
+
+ // ----- Do the extraction (if not a folder)
+ if (!(($p_entry['external']&0x00000010)==0x00000010))
+ {
+ // ----- Look for not compressed file
+ if ($p_entry['compression'] == 0) {
+
+ // ----- Opening destination file
+ if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0)
+ {
+
+ // ----- Change the file status
+ $p_entry['status'] = "write_error";
+
+ // ----- Return
+ return $v_result;
+ }
+
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ $v_size = $p_entry['compressed_size'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($this->zip_fd, $v_read_size);
+ /* Try to speed up the code
+ $v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @fwrite($v_dest_file, $v_binary_data, $v_read_size);
+ */
+ @fwrite($v_dest_file, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Closing the destination file
+ fclose($v_dest_file);
+
+ // ----- Change the file mtime
+ touch($p_entry['filename'], $p_entry['mtime']);
+
+
+ }
+ else {
+ // ----- TBC
+ // Need to be finished
+ if (($p_entry['flag'] & 1) == 1) {
+ PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.');
+ return PclZip::errorCode();
+ }
+
+
+ // ----- Look for using temporary file to unzip
+ if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
+ && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
+ || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
+ && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) {
+ $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);
+ if ($v_result < PCLZIP_ERR_NO_ERROR) {
+ return $v_result;
+ }
+ }
+
+ // ----- Look for extract in memory
+ else {
+
+
+ // ----- Read the compressed file in a buffer (one shot)
+ $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+ // ----- Decompress the file
+ $v_file_content = @gzinflate($v_buffer);
+ unset($v_buffer);
+ if ($v_file_content === FALSE) {
+
+ // ----- Change the file status
+ // TBC
+ $p_entry['status'] = "error";
+
+ return $v_result;
+ }
+
+ // ----- Opening destination file
+ if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
+
+ // ----- Change the file status
+ $p_entry['status'] = "write_error";
+
+ return $v_result;
+ }
+
+ // ----- Write the uncompressed data
+ @fwrite($v_dest_file, $v_file_content, $p_entry['size']);
+ unset($v_file_content);
+
+ // ----- Closing the destination file
+ @fclose($v_dest_file);
+
+ }
+
+ // ----- Change the file mtime
+ @touch($p_entry['filename'], $p_entry['mtime']);
+ }
+
+ // ----- Look for chmod option
+ if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {
+
+ // ----- Change the mode of the file
+ @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);
+ }
+
+ }
+ }
+
+ // ----- Change abort status
+ if ($p_entry['status'] == "aborted") {
+ $p_entry['status'] = "skipped";
+ }
+
+ // ----- Look for post-extract callback
+ elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractFileUsingTempFile()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privExtractFileUsingTempFile(&$p_entry, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Creates a temporary file
+ $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
+ if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) {
+ fclose($v_file);
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
+ return PclZip::errorCode();
+ }
+
+
+ // ----- Write gz file format header
+ $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3));
+ @fwrite($v_dest_file, $v_binary_data, 10);
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ $v_size = $p_entry['compressed_size'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($this->zip_fd, $v_read_size);
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @fwrite($v_dest_file, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Write gz file format footer
+ $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);
+ @fwrite($v_dest_file, $v_binary_data, 8);
+
+ // ----- Close the temporary file
+ @fclose($v_dest_file);
+
+ // ----- Opening destination file
+ if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
+ $p_entry['status'] = "write_error";
+ return $v_result;
+ }
+
+ // ----- Open the temporary gz file
+ if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) {
+ @fclose($v_dest_file);
+ $p_entry['status'] = "read_error";
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
+ return PclZip::errorCode();
+ }
+
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ $v_size = $p_entry['size'];
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @gzread($v_src_file, $v_read_size);
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @fwrite($v_dest_file, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+ @fclose($v_dest_file);
+ @gzclose($v_src_file);
+
+ // ----- Delete the temporary file
+ @unlink($v_gzip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractFileInOutput()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privExtractFileInOutput(&$p_entry, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Read the file header
+ if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
+ return $v_result;
+ }
+
+
+ // ----- Check that the file header is coherent with $p_entry info
+ if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
+ // TBC
+ }
+
+ // ----- Look for pre-extract callback
+ if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Change the file status
+ $p_entry['status'] = "skipped";
+ $v_result = 1;
+ }
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ // ----- This status is internal and will be changed in 'skipped'
+ $p_entry['status'] = "aborted";
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+
+ // ----- Update the informations
+ // Only some fields can be modified
+ $p_entry['filename'] = $v_local_header['filename'];
+ }
+
+ // ----- Trace
+
+ // ----- Look if extraction should be done
+ if ($p_entry['status'] == 'ok') {
+
+ // ----- Do the extraction (if not a folder)
+ if (!(($p_entry['external']&0x00000010)==0x00000010)) {
+ // ----- Look for not compressed file
+ if ($p_entry['compressed_size'] == $p_entry['size']) {
+
+ // ----- Read the file in a buffer (one shot)
+ $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+ // ----- Send the file to the output
+ echo $v_buffer;
+ unset($v_buffer);
+ }
+ else {
+
+ // ----- Read the compressed file in a buffer (one shot)
+ $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+ // ----- Decompress the file
+ $v_file_content = gzinflate($v_buffer);
+ unset($v_buffer);
+
+ // ----- Send the file to the output
+ echo $v_file_content;
+ unset($v_file_content);
+ }
+ }
+ }
+
+ // ----- Change abort status
+ if ($p_entry['status'] == "aborted") {
+ $p_entry['status'] = "skipped";
+ }
+
+ // ----- Look for post-extract callback
+ elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+ }
+
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractFileAsString()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privExtractFileAsString(&$p_entry, &$p_string, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Read the file header
+ $v_header = array();
+ if (($v_result = $this->privReadFileHeader($v_header)) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+
+ // ----- Check that the file header is coherent with $p_entry info
+ if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
+ // TBC
+ }
+
+ // ----- Look for pre-extract callback
+ if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Change the file status
+ $p_entry['status'] = "skipped";
+ $v_result = 1;
+ }
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ // ----- This status is internal and will be changed in 'skipped'
+ $p_entry['status'] = "aborted";
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+
+ // ----- Update the informations
+ // Only some fields can be modified
+ $p_entry['filename'] = $v_local_header['filename'];
+ }
+
+
+ // ----- Look if extraction should be done
+ if ($p_entry['status'] == 'ok') {
+
+ // ----- Do the extraction (if not a folder)
+ if (!(($p_entry['external']&0x00000010)==0x00000010)) {
+ // ----- Look for not compressed file
+ // if ($p_entry['compressed_size'] == $p_entry['size'])
+ if ($p_entry['compression'] == 0) {
+
+ // ----- Reading the file
+ $p_string = @fread($this->zip_fd, $p_entry['compressed_size']);
+ }
+ else {
+
+ // ----- Reading the file
+ $v_data = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+ // ----- Decompress the file
+ if (($p_string = @gzinflate($v_data)) === FALSE) {
+ // TBC
+ }
+ }
+
+ // ----- Trace
+ }
+ else {
+ // TBC : error : can not extract a folder in a string
+ }
+
+ }
+
+ // ----- Change abort status
+ if ($p_entry['status'] == "aborted") {
+ $p_entry['status'] = "skipped";
+ }
+
+ // ----- Look for post-extract callback
+ elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Swap the content to header
+ $v_local_header['content'] = $p_string;
+ $p_string = '';
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
+
+ // ----- Swap back the content to header
+ $p_string = $v_local_header['content'];
+ unset($v_local_header['content']);
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privReadFileHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privReadFileHeader(&$p_header)
+ {
+ $v_result=1;
+
+ // ----- Read the 4 bytes signature
+ $v_binary_data = @fread($this->zip_fd, 4);
+ $v_data = unpack('Vid', $v_binary_data);
+
+ // ----- Check signature
+ if ($v_data['id'] != 0x04034b50)
+ {
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the first 42 bytes of the header
+ $v_binary_data = fread($this->zip_fd, 26);
+
+ // ----- Look for invalid block size
+ if (strlen($v_binary_data) != 26)
+ {
+ $p_header['filename'] = "";
+ $p_header['status'] = "invalid_header";
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Extract the values
+ $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);
+
+ // ----- Get filename
+ $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']);
+
+ // ----- Get extra_fields
+ if ($v_data['extra_len'] != 0) {
+ $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']);
+ }
+ else {
+ $p_header['extra'] = '';
+ }
+
+ // ----- Extract properties
+ $p_header['version_extracted'] = $v_data['version'];
+ $p_header['compression'] = $v_data['compression'];
+ $p_header['size'] = $v_data['size'];
+ $p_header['compressed_size'] = $v_data['compressed_size'];
+ $p_header['crc'] = $v_data['crc'];
+ $p_header['flag'] = $v_data['flag'];
+ $p_header['filename_len'] = $v_data['filename_len'];
+
+ // ----- Recuperate date in UNIX format
+ $p_header['mdate'] = $v_data['mdate'];
+ $p_header['mtime'] = $v_data['mtime'];
+ if ($p_header['mdate'] && $p_header['mtime'])
+ {
+ // ----- Extract time
+ $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
+ $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
+ $v_seconde = ($p_header['mtime'] & 0x001F)*2;
+
+ // ----- Extract date
+ $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
+ $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
+ $v_day = $p_header['mdate'] & 0x001F;
+
+ // ----- Get UNIX date format
+ $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
+
+ }
+ else
+ {
+ $p_header['mtime'] = time();
+ }
+
+ // TBC
+ //for(reset($v_data); $key = key($v_data); next($v_data)) {
+ //}
+
+ // ----- Set the stored filename
+ $p_header['stored_filename'] = $p_header['filename'];
+
+ // ----- Set the status field
+ $p_header['status'] = "ok";
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privReadCentralFileHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privReadCentralFileHeader(&$p_header)
+ {
+ $v_result=1;
+
+ // ----- Read the 4 bytes signature
+ $v_binary_data = @fread($this->zip_fd, 4);
+ $v_data = unpack('Vid', $v_binary_data);
+
+ // ----- Check signature
+ if ($v_data['id'] != 0x02014b50)
+ {
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the first 42 bytes of the header
+ $v_binary_data = fread($this->zip_fd, 42);
+
+ // ----- Look for invalid block size
+ if (strlen($v_binary_data) != 42)
+ {
+ $p_header['filename'] = "";
+ $p_header['status'] = "invalid_header";
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Extract the values
+ $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data);
+
+ // ----- Get filename
+ if ($p_header['filename_len'] != 0)
+ $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']);
+ else
+ $p_header['filename'] = '';
+
+ // ----- Get extra
+ if ($p_header['extra_len'] != 0)
+ $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']);
+ else
+ $p_header['extra'] = '';
+
+ // ----- Get comment
+ if ($p_header['comment_len'] != 0)
+ $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']);
+ else
+ $p_header['comment'] = '';
+
+ // ----- Extract properties
+
+ // ----- Recuperate date in UNIX format
+ //if ($p_header['mdate'] && $p_header['mtime'])
+ // TBC : bug : this was ignoring time with 0/0/0
+ if (1)
+ {
+ // ----- Extract time
+ $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
+ $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
+ $v_seconde = ($p_header['mtime'] & 0x001F)*2;
+
+ // ----- Extract date
+ $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
+ $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
+ $v_day = $p_header['mdate'] & 0x001F;
+
+ // ----- Get UNIX date format
+ $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
+
+ }
+ else
+ {
+ $p_header['mtime'] = time();
+ }
+
+ // ----- Set the stored filename
+ $p_header['stored_filename'] = $p_header['filename'];
+
+ // ----- Set default status to ok
+ $p_header['status'] = 'ok';
+
+ // ----- Look if it is a directory
+ if (substr($p_header['filename'], -1) == '/') {
+ //$p_header['external'] = 0x41FF0010;
+ $p_header['external'] = 0x00000010;
+ }
+
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCheckFileHeaders()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // 1 on success,
+ // 0 on error;
+ // --------------------------------------------------------------------------------
+ function privCheckFileHeaders(&$p_local_header, &$p_central_header)
+ {
+ $v_result=1;
+
+ // ----- Check the static values
+ // TBC
+ if ($p_local_header['filename'] != $p_central_header['filename']) {
+ }
+ if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) {
+ }
+ if ($p_local_header['flag'] != $p_central_header['flag']) {
+ }
+ if ($p_local_header['compression'] != $p_central_header['compression']) {
+ }
+ if ($p_local_header['mtime'] != $p_central_header['mtime']) {
+ }
+ if ($p_local_header['filename_len'] != $p_central_header['filename_len']) {
+ }
+
+ // ----- Look for flag bit 3
+ if (($p_local_header['flag'] & 8) == 8) {
+ $p_local_header['size'] = $p_central_header['size'];
+ $p_local_header['compressed_size'] = $p_central_header['compressed_size'];
+ $p_local_header['crc'] = $p_central_header['crc'];
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privReadEndCentralDir()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privReadEndCentralDir(&$p_central_dir)
+ {
+ $v_result=1;
+
+ // ----- Go to the end of the zip file
+ $v_size = filesize($this->zipname);
+ @fseek($this->zip_fd, $v_size);
+ if (@ftell($this->zip_fd) != $v_size)
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\'');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- First try : look if this is an archive with no commentaries (most of the time)
+ // in this case the end of central dir is at 22 bytes of the file end
+ $v_found = 0;
+ if ($v_size > 26) {
+ @fseek($this->zip_fd, $v_size-22);
+ if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22))
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read for bytes
+ $v_binary_data = @fread($this->zip_fd, 4);
+ $v_data = @unpack('Vid', $v_binary_data);
+
+ // ----- Check signature
+ if ($v_data['id'] == 0x06054b50) {
+ $v_found = 1;
+ }
+
+ $v_pos = ftell($this->zip_fd);
+ }
+
+ // ----- Go back to the maximum possible size of the Central Dir End Record
+ if (!$v_found) {
+ $v_maximum_size = 65557; // 0xFFFF + 22;
+ if ($v_maximum_size > $v_size)
+ $v_maximum_size = $v_size;
+ @fseek($this->zip_fd, $v_size-$v_maximum_size);
+ if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size))
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read byte per byte in order to find the signature
+ $v_pos = ftell($this->zip_fd);
+ $v_bytes = 0x00000000;
+ while ($v_pos < $v_size)
+ {
+ // ----- Read a byte
+ $v_byte = @fread($this->zip_fd, 1);
+
+ // ----- Add the byte
+ //$v_bytes = ($v_bytes << 8) | Ord($v_byte);
+ // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number
+ // Otherwise on systems where we have 64bit integers the check below for the magic number will fail.
+ $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte);
+
+ // ----- Compare the bytes
+ if ($v_bytes == 0x504b0506)
+ {
+ $v_pos++;
+ break;
+ }
+
+ $v_pos++;
+ }
+
+ // ----- Look if not found end of central dir
+ if ($v_pos == $v_size)
+ {
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Read the first 18 bytes of the header
+ $v_binary_data = fread($this->zip_fd, 18);
+
+ // ----- Look for invalid block size
+ if (strlen($v_binary_data) != 18)
+ {
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data));
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Extract the values
+ $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);
+
+ // ----- Check the global size
+ if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {
+
+ // ----- Removed in release 2.2 see readme file
+ // The check of the file size is a little too strict.
+ // Some bugs where found when a zip is encrypted/decrypted with 'crypt'.
+ // While decrypted, zip has training 0 bytes
+ if (0) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT,
+ 'The central dir is not at the end of the archive.'
+ .' Some trailing bytes exists after the archive.');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Get comment
+ if ($v_data['comment_size'] != 0) {
+ $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']);
+ }
+ else
+ $p_central_dir['comment'] = '';
+
+ $p_central_dir['entries'] = $v_data['entries'];
+ $p_central_dir['disk_entries'] = $v_data['disk_entries'];
+ $p_central_dir['offset'] = $v_data['offset'];
+ $p_central_dir['size'] = $v_data['size'];
+ $p_central_dir['disk'] = $v_data['disk'];
+ $p_central_dir['disk_start'] = $v_data['disk_start'];
+
+ // TBC
+ //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) {
+ //}
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privDeleteByRule()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privDeleteByRule(&$p_result_list, &$p_options)
+ {
+ $v_result=1;
+ $v_list_detail = array();
+
+ // ----- Open the zip file
+ if (($v_result=$this->privOpenFd('rb')) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+ {
+ $this->privCloseFd();
+ return $v_result;
+ }
+
+ // ----- Go to beginning of File
+ @rewind($this->zip_fd);
+
+ // ----- Scan all the files
+ // ----- Start at beginning of Central Dir
+ $v_pos_entry = $v_central_dir['offset'];
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_pos_entry))
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read each entry
+ $v_header_list = array();
+ $j_start = 0;
+ for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++)
+ {
+
+ // ----- Read the file header
+ $v_header_list[$v_nb_extracted] = array();
+ if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1)
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ return $v_result;
+ }
+
+
+ // ----- Store the index
+ $v_header_list[$v_nb_extracted]['index'] = $i;
+
+ // ----- Look for the specific extract rules
+ $v_found = false;
+
+ // ----- Look for extract by name rule
+ if ( (isset($p_options[PCLZIP_OPT_BY_NAME]))
+ && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
+
+ // ----- Look if the filename is in the list
+ for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
+ && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
+ $v_found = true;
+ }
+ elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */
+ && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
+ $v_found = true;
+ }
+ }
+ // ----- Look for a filename
+ elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
+ $v_found = true;
+ }
+ }
+ }
+
+ // ----- Look for extract by ereg rule
+ // ereg() is deprecated with PHP 5.3
+ /*
+ else if ( (isset($p_options[PCLZIP_OPT_BY_EREG]))
+ && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
+
+ if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
+ $v_found = true;
+ }
+ }
+ */
+
+ // ----- Look for extract by preg rule
+ else if ( (isset($p_options[PCLZIP_OPT_BY_PREG]))
+ && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
+
+ if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
+ $v_found = true;
+ }
+ }
+
+ // ----- Look for extract by index rule
+ else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX]))
+ && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
+
+ // ----- Look if the index is in the list
+ for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
+ $v_found = true;
+ }
+ if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
+ $j_start = $j+1;
+ }
+
+ if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
+ break;
+ }
+ }
+ }
+ else {
+ $v_found = true;
+ }
+
+ // ----- Look for deletion
+ if ($v_found)
+ {
+ unset($v_header_list[$v_nb_extracted]);
+ }
+ else
+ {
+ $v_nb_extracted++;
+ }
+ }
+
+ // ----- Look if something need to be deleted
+ if ($v_nb_extracted > 0) {
+
+ // ----- Creates a temporay file
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
+
+ // ----- Creates a temporary zip archive
+ $v_temp_zip = new PclZip($v_zip_temp_name);
+
+ // ----- Open the temporary zip file in write mode
+ if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) {
+ $this->privCloseFd();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Look which file need to be kept
+ for ($i=0; $izip_fd);
+ if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $v_temp_zip->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file header
+ $v_local_header = array();
+ if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $v_temp_zip->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Check that local file header is same as central file header
+ if ($this->privCheckFileHeaders($v_local_header,
+ $v_header_list[$i]) != 1) {
+ // TBC
+ }
+ unset($v_local_header);
+
+ // ----- Write the file header
+ if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $v_temp_zip->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read/write the data block
+ if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $v_temp_zip->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+ }
+
+ // ----- Store the offset of the central dir
+ $v_offset = @ftell($v_temp_zip->zip_fd);
+
+ // ----- Re-Create the Central Dir files header
+ for ($i=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) {
+ $v_temp_zip->privCloseFd();
+ $this->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Transform the header to a 'usable' info
+ $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
+ }
+
+
+ // ----- Zip file comment
+ $v_comment = '';
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
+ }
+
+ // ----- Calculate the size of the central header
+ $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset;
+
+ // ----- Create the central dir footer
+ if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) {
+ // ----- Reset the file list
+ unset($v_header_list);
+ $v_temp_zip->privCloseFd();
+ $this->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Close
+ $v_temp_zip->privCloseFd();
+ $this->privCloseFd();
+
+ // ----- Delete the zip file
+ // TBC : I should test the result ...
+ @unlink($this->zipname);
+
+ // ----- Rename the temporary file
+ // TBC : I should test the result ...
+ //@rename($v_zip_temp_name, $this->zipname);
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
+
+ // ----- Destroy the temporary archive
+ unset($v_temp_zip);
+ }
+
+ // ----- Remove every files : reset the file
+ else if ($v_central_dir['entries'] != 0) {
+ $this->privCloseFd();
+
+ if (($v_result = $this->privOpenFd('wb')) != 1) {
+ return $v_result;
+ }
+
+ if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) {
+ return $v_result;
+ }
+
+ $this->privCloseFd();
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privDirCheck()
+ // Description :
+ // Check if a directory exists, if not it creates it and all the parents directory
+ // which may be useful.
+ // Parameters :
+ // $p_dir : Directory path to check.
+ // Return Values :
+ // 1 : OK
+ // -1 : Unable to create directory
+ // --------------------------------------------------------------------------------
+ function privDirCheck($p_dir, $p_is_dir=false)
+ {
+ $v_result = 1;
+
+
+ // ----- Remove the final '/'
+ if (($p_is_dir) && (substr($p_dir, -1)=='/'))
+ {
+ $p_dir = substr($p_dir, 0, strlen($p_dir)-1);
+ }
+
+ // ----- Check the directory availability
+ if ((is_dir($p_dir)) || ($p_dir == ""))
+ {
+ return 1;
+ }
+
+ // ----- Extract parent directory
+ $p_parent_dir = dirname($p_dir);
+
+ // ----- Just a check
+ if ($p_parent_dir != $p_dir)
+ {
+ // ----- Look for parent directory
+ if ($p_parent_dir != "")
+ {
+ if (($v_result = $this->privDirCheck($p_parent_dir)) != 1)
+ {
+ return $v_result;
+ }
+ }
+ }
+
+ // ----- Create the directory
+ if (!@mkdir($p_dir, 0777))
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privMerge()
+ // Description :
+ // If $p_archive_to_add does not exist, the function exit with a success result.
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privMerge(&$p_archive_to_add)
+ {
+ $v_result=1;
+
+ // ----- Look if the archive_to_add exists
+ if (!is_file($p_archive_to_add->zipname))
+ {
+
+ // ----- Nothing to merge, so merge is a success
+ $v_result = 1;
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Look if the archive exists
+ if (!is_file($this->zipname))
+ {
+
+ // ----- Do a duplicate
+ $v_result = $this->privDuplicate($p_archive_to_add->zipname);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Open the zip file
+ if (($v_result=$this->privOpenFd('rb')) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+ {
+ $this->privCloseFd();
+ return $v_result;
+ }
+
+ // ----- Go to beginning of File
+ @rewind($this->zip_fd);
+
+ // ----- Open the archive_to_add file
+ if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1)
+ {
+ $this->privCloseFd();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir_to_add = array();
+ if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1)
+ {
+ $this->privCloseFd();
+ $p_archive_to_add->privCloseFd();
+
+ return $v_result;
+ }
+
+ // ----- Go to beginning of File
+ @rewind($p_archive_to_add->zip_fd);
+
+ // ----- Creates a temporay file
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
+
+ // ----- Open the temporary file in write mode
+ if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
+ {
+ $this->privCloseFd();
+ $p_archive_to_add->privCloseFd();
+
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Copy the files from the archive to the temporary file
+ // TBC : Here I should better append the file and go back to erase the central dir
+ $v_size = $v_central_dir['offset'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = fread($this->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Copy the files from the archive_to_add into the temporary file
+ $v_size = $v_central_dir_to_add['offset'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Store the offset of the central dir
+ $v_offset = @ftell($v_zip_temp_fd);
+
+ // ----- Copy the block of file headers from the old archive
+ $v_size = $v_central_dir['size'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($this->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Copy the block of file headers from the archive_to_add
+ $v_size = $v_central_dir_to_add['size'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Merge the file comments
+ $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment'];
+
+ // ----- Calculate the size of the (new) central header
+ $v_size = @ftell($v_zip_temp_fd)-$v_offset;
+
+ // ----- Swap the file descriptor
+ // Here is a trick : I swap the temporary fd with the zip fd, in order to use
+ // the following methods on the temporary fil and not the real archive fd
+ $v_swap = $this->zip_fd;
+ $this->zip_fd = $v_zip_temp_fd;
+ $v_zip_temp_fd = $v_swap;
+
+ // ----- Create the central dir footer
+ if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1)
+ {
+ $this->privCloseFd();
+ $p_archive_to_add->privCloseFd();
+ @fclose($v_zip_temp_fd);
+ $this->zip_fd = null;
+
+ // ----- Reset the file list
+ unset($v_header_list);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Swap back the file descriptor
+ $v_swap = $this->zip_fd;
+ $this->zip_fd = $v_zip_temp_fd;
+ $v_zip_temp_fd = $v_swap;
+
+ // ----- Close
+ $this->privCloseFd();
+ $p_archive_to_add->privCloseFd();
+
+ // ----- Close the temporary file
+ @fclose($v_zip_temp_fd);
+
+ // ----- Delete the zip file
+ // TBC : I should test the result ...
+ @unlink($this->zipname);
+
+ // ----- Rename the temporary file
+ // TBC : I should test the result ...
+ //@rename($v_zip_temp_name, $this->zipname);
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privDuplicate()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privDuplicate($p_archive_filename)
+ {
+ $v_result=1;
+
+ // ----- Look if the $p_archive_filename exists
+ if (!is_file($p_archive_filename))
+ {
+
+ // ----- Nothing to duplicate, so duplicate is a success.
+ $v_result = 1;
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Open the zip file
+ if (($v_result=$this->privOpenFd('wb')) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Open the temporary file in write mode
+ if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0)
+ {
+ $this->privCloseFd();
+
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Copy the files from the archive to the temporary file
+ // TBC : Here I should better append the file and go back to erase the central dir
+ $v_size = filesize($p_archive_filename);
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = fread($v_zip_temp_fd, $v_read_size);
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Close
+ $this->privCloseFd();
+
+ // ----- Close the temporary file
+ @fclose($v_zip_temp_fd);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privErrorLog()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function privErrorLog($p_error_code=0, $p_error_string='')
+ {
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
+ PclError($p_error_code, $p_error_string);
+ }
+ else {
+ $this->error_code = $p_error_code;
+ $this->error_string = $p_error_string;
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privErrorReset()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function privErrorReset()
+ {
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
+ PclErrorReset();
+ }
+ else {
+ $this->error_code = 0;
+ $this->error_string = '';
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privDisableMagicQuotes()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privDisableMagicQuotes()
+ {
+ $v_result=1;
+
+ // ----- Look if function exists
+ if ( (!function_exists("get_magic_quotes_runtime"))
+ || (!function_exists("set_magic_quotes_runtime"))) {
+ return $v_result;
+ }
+
+ // ----- Look if already done
+ if ($this->magic_quotes_status != -1) {
+ return $v_result;
+ }
+
+ // ----- Get and memorize the magic_quote value
+ $this->magic_quotes_status = @get_magic_quotes_runtime();
+
+ // ----- Disable magic_quotes
+ if ($this->magic_quotes_status == 1) {
+ @set_magic_quotes_runtime(0);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privSwapBackMagicQuotes()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privSwapBackMagicQuotes()
+ {
+ $v_result=1;
+
+ // ----- Look if function exists
+ if ( (!function_exists("get_magic_quotes_runtime"))
+ || (!function_exists("set_magic_quotes_runtime"))) {
+ return $v_result;
+ }
+
+ // ----- Look if something to do
+ if ($this->magic_quotes_status != -1) {
+ return $v_result;
+ }
+
+ // ----- Swap back magic_quotes
+ if ($this->magic_quotes_status == 1) {
+ @set_magic_quotes_runtime($this->magic_quotes_status);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ }
+ // End of class
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZipUtilPathReduction()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function PclZipUtilPathReduction($p_dir)
+ {
+ $v_result = "";
+
+ // ----- Look for not empty path
+ if ($p_dir != "") {
+ // ----- Explode path by directory names
+ $v_list = explode("/", $p_dir);
+
+ // ----- Study directories from last to first
+ $v_skip = 0;
+ for ($i=sizeof($v_list)-1; $i>=0; $i--) {
+ // ----- Look for current path
+ if ($v_list[$i] == ".") {
+ // ----- Ignore this directory
+ // Should be the first $i=0, but no check is done
+ }
+ else if ($v_list[$i] == "..") {
+ $v_skip++;
+ }
+ else if ($v_list[$i] == "") {
+ // ----- First '/' i.e. root slash
+ if ($i == 0) {
+ $v_result = "/".$v_result;
+ if ($v_skip > 0) {
+ // ----- It is an invalid path, so the path is not modified
+ // TBC
+ $v_result = $p_dir;
+ $v_skip = 0;
+ }
+ }
+ // ----- Last '/' i.e. indicates a directory
+ else if ($i == (sizeof($v_list)-1)) {
+ $v_result = $v_list[$i];
+ }
+ // ----- Double '/' inside the path
+ else {
+ // ----- Ignore only the double '//' in path,
+ // but not the first and last '/'
+ }
+ }
+ else {
+ // ----- Look for item to skip
+ if ($v_skip > 0) {
+ $v_skip--;
+ }
+ else {
+ $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:"");
+ }
+ }
+ }
+
+ // ----- Look for skip
+ if ($v_skip > 0) {
+ while ($v_skip > 0) {
+ $v_result = '../'.$v_result;
+ $v_skip--;
+ }
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZipUtilPathInclusion()
+ // Description :
+ // This function indicates if the path $p_path is under the $p_dir tree. Or,
+ // said in an other way, if the file or sub-dir $p_path is inside the dir
+ // $p_dir.
+ // The function indicates also if the path is exactly the same as the dir.
+ // This function supports path with duplicated '/' like '//', but does not
+ // support '.' or '..' statements.
+ // Parameters :
+ // Return Values :
+ // 0 if $p_path is not inside directory $p_dir
+ // 1 if $p_path is inside directory $p_dir
+ // 2 if $p_path is exactly the same as $p_dir
+ // --------------------------------------------------------------------------------
+ function PclZipUtilPathInclusion($p_dir, $p_path)
+ {
+ $v_result = 1;
+
+ // ----- Look for path beginning by ./
+ if ( ($p_dir == '.')
+ || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) {
+ $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1);
+ }
+ if ( ($p_path == '.')
+ || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) {
+ $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1);
+ }
+
+ // ----- Explode dir and path by directory separator
+ $v_list_dir = explode("/", $p_dir);
+ $v_list_dir_size = sizeof($v_list_dir);
+ $v_list_path = explode("/", $p_path);
+ $v_list_path_size = sizeof($v_list_path);
+
+ // ----- Study directories paths
+ $i = 0;
+ $j = 0;
+ while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) {
+
+ // ----- Look for empty dir (path reduction)
+ if ($v_list_dir[$i] == '') {
+ $i++;
+ continue;
+ }
+ if ($v_list_path[$j] == '') {
+ $j++;
+ continue;
+ }
+
+ // ----- Compare the items
+ if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) {
+ $v_result = 0;
+ }
+
+ // ----- Next items
+ $i++;
+ $j++;
+ }
+
+ // ----- Look if everything seems to be the same
+ if ($v_result) {
+ // ----- Skip all the empty items
+ while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++;
+ while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++;
+
+ if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {
+ // ----- There are exactly the same
+ $v_result = 2;
+ }
+ else if ($i < $v_list_dir_size) {
+ // ----- The path is shorter than the dir
+ $v_result = 0;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZipUtilCopyBlock()
+ // Description :
+ // Parameters :
+ // $p_mode : read/write compression mode
+ // 0 : src & dest normal
+ // 1 : src gzip, dest normal
+ // 2 : src normal, dest gzip
+ // 3 : src & dest gzip
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0)
+ {
+ $v_result = 1;
+
+ if ($p_mode==0)
+ {
+ while ($p_size != 0)
+ {
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($p_src, $v_read_size);
+ @fwrite($p_dest, $v_buffer, $v_read_size);
+ $p_size -= $v_read_size;
+ }
+ }
+ else if ($p_mode==1)
+ {
+ while ($p_size != 0)
+ {
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @gzread($p_src, $v_read_size);
+ @fwrite($p_dest, $v_buffer, $v_read_size);
+ $p_size -= $v_read_size;
+ }
+ }
+ else if ($p_mode==2)
+ {
+ while ($p_size != 0)
+ {
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($p_src, $v_read_size);
+ @gzwrite($p_dest, $v_buffer, $v_read_size);
+ $p_size -= $v_read_size;
+ }
+ }
+ else if ($p_mode==3)
+ {
+ while ($p_size != 0)
+ {
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @gzread($p_src, $v_read_size);
+ @gzwrite($p_dest, $v_buffer, $v_read_size);
+ $p_size -= $v_read_size;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZipUtilRename()
+ // Description :
+ // This function tries to do a simple rename() function. If it fails, it
+ // tries to copy the $p_src file in a new $p_dest file and then unlink the
+ // first one.
+ // Parameters :
+ // $p_src : Old filename
+ // $p_dest : New filename
+ // Return Values :
+ // 1 on success, 0 on failure.
+ // --------------------------------------------------------------------------------
+ function PclZipUtilRename($p_src, $p_dest)
+ {
+ $v_result = 1;
+
+ // ----- Try to rename the files
+ if (!@rename($p_src, $p_dest)) {
+
+ // ----- Try to copy & unlink the src
+ if (!@copy($p_src, $p_dest)) {
+ $v_result = 0;
+ }
+ else if (!@unlink($p_src)) {
+ $v_result = 0;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZipUtilOptionText()
+ // Description :
+ // Translate option value in text. Mainly for debug purpose.
+ // Parameters :
+ // $p_option : the option value.
+ // Return Values :
+ // The option text value.
+ // --------------------------------------------------------------------------------
+ function PclZipUtilOptionText($p_option)
+ {
+
+ $v_list = get_defined_constants();
+ for (reset($v_list); $v_key = key($v_list); next($v_list)) {
+ $v_prefix = substr($v_key, 0, 10);
+ if (( ($v_prefix == 'PCLZIP_OPT')
+ || ($v_prefix == 'PCLZIP_CB_')
+ || ($v_prefix == 'PCLZIP_ATT'))
+ && ($v_list[$v_key] == $p_option)) {
+ return $v_key;
+ }
+ }
+
+ $v_result = 'Unknown';
+
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZipUtilTranslateWinPath()
+ // Description :
+ // Translate windows path by replacing '\' by '/' and optionally removing
+ // drive letter.
+ // Parameters :
+ // $p_path : path to translate.
+ // $p_remove_disk_letter : true | false
+ // Return Values :
+ // The path translated.
+ // --------------------------------------------------------------------------------
+ function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true)
+ {
+ if (stristr(php_uname(), 'windows')) {
+ // ----- Look for potential disk letter
+ if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) {
+ $p_path = substr($p_path, $v_position+1);
+ }
+ // ----- Change potential windows directory separator
+ if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
+ $p_path = strtr($p_path, '\\', '/');
+ }
+ }
+ return $p_path;
+ }
+ // --------------------------------------------------------------------------------
+
+
+?>
Index: /tags/2.1.0/admin/include/plugins.class.php
===================================================================
--- /tags/2.1.0/admin/include/plugins.class.php (revision 6217)
+++ /tags/2.1.0/admin/include/plugins.class.php (revision 6217)
@@ -0,0 +1,589 @@
+get_fs_plugins();
+
+ foreach (get_db_plugins() as $db_plugin)
+ {
+ $this->db_plugins_by_id[$db_plugin['id']] = $db_plugin;
+ }
+ }
+
+ /**
+ * Set tabsheet for plugins pages.
+ * @param string selected page.
+ */
+ function set_tabsheet($selected)
+ {
+ include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
+
+ $link = get_root_url().'admin.php?page=';
+
+ $tabsheet = new tabsheet();
+ $tabsheet->add('plugins_list', l10n('Plugin list'), $link.'plugins_list');
+ $tabsheet->add('plugins_update', l10n('Check for updates'), $link.'plugins_update');
+ $tabsheet->add('plugins_new', l10n('Other plugins'), $link.'plugins_new');
+ $tabsheet->select($selected);
+ $tabsheet->assign();
+ }
+
+ /**
+ * Perform requested actions
+ * @param string - action
+ * @param string - plugin id
+ * @param array - errors
+ */
+ function perform_action($action, $plugin_id)
+ {
+ if (isset($this->db_plugins_by_id[$plugin_id]))
+ {
+ $crt_db_plugin = $this->db_plugins_by_id[$plugin_id];
+ }
+ $file_to_include = PHPWG_PLUGINS_PATH . $plugin_id . '/maintain.inc.php';
+
+ $errors = array();
+
+ switch ($action)
+ {
+ case 'install':
+ if (!empty($crt_db_plugin))
+ {
+ array_push($errors, 'CANNOT INSTALL - ALREADY INSTALLED');
+ break;
+ }
+ if (!isset($this->fs_plugins[$plugin_id]))
+ {
+ array_push($errors, 'CANNOT INSTALL - NO SUCH PLUGIN');
+ break;
+ }
+ if (file_exists($file_to_include))
+ {
+ include_once($file_to_include);
+ if (function_exists('plugin_install'))
+ {
+ plugin_install($plugin_id, $this->fs_plugins[$plugin_id]['version'], $errors);
+ }
+ }
+ if (empty($errors))
+ {
+ $query = '
+INSERT INTO ' . PLUGINS_TABLE . ' (id,version) VALUES (\''
+. $plugin_id . '\',\'' . $this->fs_plugins[$plugin_id]['version'] . '\'
+)';
+ pwg_query($query);
+ }
+ break;
+
+ case 'activate':
+ if (!isset($crt_db_plugin))
+ {
+ array_push($errors, 'CANNOT ACTIVATE - NOT INSTALLED');
+ break;
+ }
+ if ($crt_db_plugin['state'] != 'inactive')
+ {
+ array_push($errors, 'invalid current state ' . $crt_db_plugin['state']);
+ break;
+ }
+ if (file_exists($file_to_include))
+ {
+ include_once($file_to_include);
+ if (function_exists('plugin_activate'))
+ {
+ plugin_activate($plugin_id, $crt_db_plugin['version'], $errors);
+ }
+ }
+ if (empty($errors))
+ {
+ $query = '
+UPDATE ' . PLUGINS_TABLE . '
+SET state=\'active\', version=\''.$this->fs_plugins[$plugin_id]['version'].'\'
+WHERE id=\'' . $plugin_id . '\'';
+ pwg_query($query);
+ }
+ break;
+
+ case 'deactivate':
+ if (!isset($crt_db_plugin))
+ {
+ die ('CANNOT DEACTIVATE - NOT INSTALLED');
+ }
+ if ($crt_db_plugin['state'] != 'active')
+ {
+ die('invalid current state ' . $crt_db_plugin['state']);
+ }
+ $query = '
+UPDATE ' . PLUGINS_TABLE . ' SET state=\'inactive\' WHERE id=\'' . $plugin_id . '\'';
+ pwg_query($query);
+ if (file_exists($file_to_include))
+ {
+ include_once($file_to_include);
+ if (function_exists('plugin_deactivate'))
+ {
+ plugin_deactivate($plugin_id);
+ }
+ }
+ break;
+
+ case 'uninstall':
+ if (!isset($crt_db_plugin))
+ {
+ die ('CANNOT UNINSTALL - NOT INSTALLED');
+ }
+ $query = '
+DELETE FROM ' . PLUGINS_TABLE . ' WHERE id=\'' . $plugin_id . '\'';
+ pwg_query($query);
+ if (file_exists($file_to_include))
+ {
+ include_once($file_to_include);
+ if (function_exists('plugin_uninstall'))
+ {
+ plugin_uninstall($plugin_id);
+ }
+ }
+ break;
+
+ case 'delete':
+ if (!empty($crt_db_plugin))
+ {
+ array_push($errors, 'CANNOT DELETE - PLUGIN IS INSTALLED');
+ break;
+ }
+ if (!isset($this->fs_plugins[$plugin_id]))
+ {
+ array_push($errors, 'CANNOT DELETE - NO SUCH PLUGIN');
+ break;
+ }
+ if (!$this->deltree(PHPWG_PLUGINS_PATH . $plugin_id))
+ {
+ $this->send_to_trash(PHPWG_PLUGINS_PATH . $plugin_id);
+ }
+ break;
+ }
+ return $errors;
+ }
+
+ /**
+ * Get plugins defined in the plugin directory
+ */
+ function get_fs_plugins()
+ {
+ $dir = opendir(PHPWG_PLUGINS_PATH);
+ while ($file = readdir($dir))
+ {
+ if ($file!='.' and $file!='..')
+ {
+ $path = PHPWG_PLUGINS_PATH.$file;
+ if (is_dir($path) and !is_link($path)
+ and preg_match('/^[a-zA-Z0-9-_]+$/', $file )
+ and file_exists($path.'/main.inc.php')
+ )
+ {
+ $plugin = array(
+ 'name'=>$file,
+ 'version'=>'0',
+ 'uri'=>'',
+ 'description'=>'',
+ 'author'=>'',
+ );
+ $plg_data = implode( '', file($path.'/main.inc.php') );
+
+ if ( preg_match("|Plugin Name: (.*)|", $plg_data, $val) )
+ {
+ $plugin['name'] = trim( $val[1] );
+ }
+ if (preg_match("|Version: (.*)|", $plg_data, $val))
+ {
+ $plugin['version'] = trim($val[1]);
+ }
+ if ( preg_match("|Plugin URI: (.*)|", $plg_data, $val) )
+ {
+ $plugin['uri'] = trim($val[1]);
+ }
+ if ($desc = load_language('description.txt', $path.'/', array('return' => true)))
+ {
+ $plugin['description'] = trim($desc);
+ }
+ elseif ( preg_match("|Description: (.*)|", $plg_data, $val) )
+ {
+ $plugin['description'] = trim($val[1]);
+ }
+ if ( preg_match("|Author: (.*)|", $plg_data, $val) )
+ {
+ $plugin['author'] = trim($val[1]);
+ }
+ if ( preg_match("|Author URI: (.*)|", $plg_data, $val) )
+ {
+ $plugin['author uri'] = trim($val[1]);
+ }
+ if (!empty($plugin['uri']) and strpos($plugin['uri'] , 'extension_view.php?eid='))
+ {
+ list( , $extension) = explode('extension_view.php?eid=', $plugin['uri']);
+ if (is_numeric($extension)) $plugin['extension'] = $extension;
+ }
+ // IMPORTANT SECURITY !
+ $plugin = array_map('htmlspecialchars', $plugin);
+ $this->fs_plugins[$file] = $plugin;
+ }
+ }
+ }
+ closedir($dir);
+ }
+
+ /**
+ * Sort fs_plugins
+ */
+ function sort_fs_plugins($order='name')
+ {
+ switch ($order)
+ {
+ case 'name':
+ uasort($this->fs_plugins, 'name_compare');
+ break;
+ case 'status':
+ $this->sort_plugins_by_state();
+ break;
+ case 'author':
+ uasort($this->fs_plugins, array($this, 'plugin_author_compare'));
+ break;
+ case 'id':
+ uksort($this->fs_plugins, 'strcasecmp');
+ break;
+ }
+ }
+
+ /**
+ * Retrieve PEM server datas to $server_plugins
+ */
+ function get_server_plugins($new=false)
+ {
+ global $user;
+
+ // Retrieve PEM versions
+ $version = PHPWG_VERSION;
+ $versions_to_check = array();
+ $url = PEM_URL . '/api/get_version_list.php?category_id=12&format=php';
+ if (fetchRemote($url, $result) 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;
+ }
+
+ // Plugins to check
+ $plugins_to_check = array();
+ foreach($this->fs_plugins as $fs_plugin)
+ {
+ if (isset($fs_plugin['extension']))
+ {
+ $plugins_to_check[] = $fs_plugin['extension'];
+ }
+ }
+
+ // Retrieve PEM plugins infos
+ $url = PEM_URL . '/api/get_revision_list.php?category_id=12&format=php&last_revision_only=true';
+ $url .= '&version=' . implode(',', $versions_to_check);
+ $url .= '&lang=' . substr($user['language'], 0, 2);
+ $url .= '&get_nb_downloads=true';
+
+ if (!empty($plugins_to_check))
+ {
+ $url .= $new ? '&extension_exclude=' : '&extension_include=';
+ $url .= implode(',', $plugins_to_check);
+ }
+ if (fetchRemote($url, $result))
+ {
+ $pem_plugins = @unserialize($result);
+ if (!is_array($pem_plugins))
+ {
+ return false;
+ }
+ foreach ($pem_plugins as $plugin)
+ {
+ $this->server_plugins[$plugin['extension_id']] = $plugin;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sort $server_plugins
+ */
+ function sort_server_plugins($order='date')
+ {
+ switch ($order)
+ {
+ case 'date':
+ krsort($this->server_plugins);
+ break;
+ case 'revision':
+ usort($this->server_plugins, array($this, 'extension_revision_compare'));
+ break;
+ case 'name':
+ uasort($this->server_plugins, array($this, 'extension_name_compare'));
+ break;
+ case 'author':
+ uasort($this->server_plugins, array($this, 'extension_author_compare'));
+ break;
+ case 'downloads':
+ usort($this->server_plugins, array($this, 'extension_downloads_compare'));
+ break;
+ }
+ }
+
+ /**
+ * Extract plugin files from archive
+ * @param string - install or upgrade
+ * @param string - archive URL
+ * @param string - plugin id or extension id
+ */
+ function extract_plugin_files($action, $revision, $dest)
+ {
+ if ($archive = tempnam( PHPWG_PLUGINS_PATH, 'zip'))
+ {
+ $url = PEM_URL . '/download.php?rid=' . $revision;
+ $url .= '&origin=piwigo_' . $action;
+
+ if ($handle = @fopen($archive, 'wb') and fetchRemote($url, $handle))
+ {
+ fclose($handle);
+ include(PHPWG_ROOT_PATH.'admin/include/pclzip.lib.php');
+ $zip = new PclZip($archive);
+ if ($list = $zip->listContent())
+ {
+ foreach ($list as $file)
+ {
+ // we search main.inc.php in archive
+ if (basename($file['filename']) == 'main.inc.php'
+ and (!isset($main_filepath)
+ or strlen($file['filename']) < strlen($main_filepath)))
+ {
+ $main_filepath = $file['filename'];
+ }
+ }
+ if (isset($main_filepath))
+ {
+ $root = dirname($main_filepath); // main.inc.php path in archive
+ if ($action == 'upgrade')
+ {
+ $extract_path = PHPWG_PLUGINS_PATH . $dest;
+ }
+ else
+ {
+ $extract_path = PHPWG_PLUGINS_PATH
+ . ($root == '.' ? 'extension_' . $dest : basename($root));
+ }
+ if($result = $zip->extract(PCLZIP_OPT_PATH, $extract_path,
+ PCLZIP_OPT_REMOVE_PATH, $root,
+ PCLZIP_OPT_REPLACE_NEWER))
+ {
+ foreach ($result as $file)
+ {
+ if ($file['stored_filename'] == $main_filepath)
+ {
+ $status = $file['status'];
+ break;
+ }
+ }
+ if (file_exists($extract_path.'/obsolete.list')
+ and $old_files = file($extract_path.'/obsolete.list', FILE_IGNORE_NEW_LINES)
+ and !empty($old_files))
+ {
+ array_push($old_files, 'obsolete.list');
+ foreach($old_files as $old_file)
+ {
+ $path = $extract_path.'/'.$old_file;
+ if (is_file($path))
+ {
+ @unlink($path);
+ }
+ elseif (is_dir($path))
+ {
+ if (!$this->deltree($path))
+ {
+ $this->send_to_trash($path);
+ }
+ }
+ }
+ }
+ }
+ else $status = 'extract_error';
+ }
+ else $status = 'archive_error';
+ }
+ else $status = 'archive_error';
+ }
+ else $status = 'dl_archive_error';
+ }
+ else $status = 'temp_path_error';
+
+ @unlink($archive);
+ return $status;
+ }
+
+ /**
+ * delete $path directory
+ * @param string - path
+ */
+ function deltree($path)
+ {
+ if (is_dir($path))
+ {
+ $fh = opendir($path);
+ while ($file = readdir($fh))
+ {
+ if ($file != '.' and $file != '..')
+ {
+ $pathfile = $path . '/' . $file;
+ if (is_dir($pathfile))
+ {
+ $this->deltree($pathfile);
+ }
+ else
+ {
+ @unlink($pathfile);
+ }
+ }
+ }
+ closedir($fh);
+ return @rmdir($path);
+ }
+ }
+
+ /**
+ * send $path to trash directory
+ * @param string - path
+ */
+ function send_to_trash($path)
+ {
+ $trash_path = PHPWG_PLUGINS_PATH . 'trash';
+ if (!is_dir($trash_path))
+ {
+ @mkdir($trash_path);
+ $file = @fopen($trash_path . '/.htaccess', 'w');
+ @fwrite($file, 'deny from all');
+ @fclose($file);
+ }
+ while ($r = $trash_path . '/' . md5(uniqid(rand(), true)))
+ {
+ if (!is_dir($r))
+ {
+ @rename($path, $r);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Sort functions
+ */
+ function plugin_version_compare($a, $b)
+ {
+ $pattern = array('/([a-z])/ei', '/\.+/', '/\.\Z|\A\./');
+ $replacement = array( "'.'.intval('\\1', 36).'.'", '.', '');
+
+ $array = preg_replace($pattern, $replacement, array($a, $b));
+
+ return version_compare($array[0], $array[1], '>=');
+ }
+
+ function extension_revision_compare($a, $b)
+ {
+ if ($a['revision_date'] < $b['revision_date']) return 1;
+ else return -1;
+ }
+
+ function extension_name_compare($a, $b)
+ {
+ return strcmp(strtolower($a['extension_name']), strtolower($b['extension_name']));
+ }
+
+ function extension_author_compare($a, $b)
+ {
+ $r = strcasecmp($a['author_name'], $b['author_name']);
+ if ($r == 0) return $this->extension_name_compare($a, $b);
+ else return $r;
+ }
+
+ function plugin_author_compare($a, $b)
+ {
+ $r = strcasecmp($a['author'], $b['author']);
+ if ($r == 0) return name_compare($a, $b);
+ else return $r;
+ }
+
+ function extension_downloads_compare($a, $b)
+ {
+ if ($a['extension_nb_downloads'] < $b['extension_nb_downloads']) return 1;
+ else return -1;
+ }
+
+ function sort_plugins_by_state()
+ {
+ uasort($this->fs_plugins, 'name_compare');
+
+ $active_plugins = array();
+ $inactive_plugins = array();
+ $not_installed = array();
+
+ foreach($this->fs_plugins as $plugin_id => $plugin)
+ {
+ if (isset($this->db_plugins_by_id[$plugin_id]))
+ {
+ $this->db_plugins_by_id[$plugin_id]['state'] == 'active' ?
+ $active_plugins[$plugin_id] = $plugin : $inactive_plugins[$plugin_id] = $plugin;
+ }
+ else
+ {
+ $not_installed[$plugin_id] = $plugin;
+ }
+ }
+ $this->fs_plugins = $active_plugins + $inactive_plugins + $not_installed;
+ }
+}
+?>
Index: /tags/2.1.0/admin/include/tabsheet.class.php
===================================================================
--- /tags/2.1.0/admin/include/tabsheet.class.php (revision 6217)
+++ /tags/2.1.0/admin/include/tabsheet.class.php (revision 6217)
@@ -0,0 +1,146 @@
+sheets = array();
+ $this->name = $name;
+ $this->titlename = $titlename;
+ $this->selected = "";
+ }
+
+ /*
+ add a tab
+ */
+ function add($name, $caption, $url, $selected = false)
+ {
+ if (!isset($this->sheets[$name]))
+ {
+ $this->sheets[$name] = array('caption' => $caption,
+ 'url' => $url);
+ if($selected)
+ {
+ $this->selected=$name;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ remove a tab
+ */
+ function delete($name)
+ {
+ if (isset($this->sheets[$name]))
+ {
+ array_splice($this->sheets, $name, 1);
+
+ if ($this->selected == $name)
+ {
+ $this->selected = "";
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ select a tab to be active
+ */
+ function select($name)
+ {
+ $this->selected = $name;
+ }
+
+ /*
+ set $titlename value
+ */
+ function set_titlename($titlename)
+ {
+ $this->titlename = $titlename;
+ return $this->titlename;
+ }
+
+ /*
+ returns $titlename value
+ */
+ function get_titlename()
+ {
+ return $this->titlename;
+ }
+
+ /*
+ returns properties of selected tab
+ */
+ function get_selected()
+ {
+ if (!empty($this->selected))
+ {
+ return $this->sheets[$this->selected];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /*
+ * Build TabSheet and assign this content to current page
+ *
+ * Fill $this->$name {default value = TABSHEET} with HTML code for tabsheet
+ * Fill $this->titlename {default value = TABSHEET_TITLE} with formated caption of the selected tab
+ */
+ function assign()
+ {
+ global $template;
+
+ $template->set_filename('tabsheet', 'tabsheet.tpl');
+ $template->assign('tabsheet', $this->sheets);
+ $template->assign('tabsheet_selected', $this->selected);
+
+ $selected_tab = $this->get_selected();
+
+ if (isset($selected_tab))
+ {
+ $template->assign(
+ array($this->titlename => '['.$selected_tab['caption'].']'));
+ }
+
+ $template->assign_var_from_handle($this->name, 'tabsheet');
+ $template->clear_assign('tabsheet');
+ }
+}
+
+?>
Index: /tags/2.1.0/admin/include/themes.class.php
===================================================================
--- /tags/2.1.0/admin/include/themes.class.php (revision 6217)
+++ /tags/2.1.0/admin/include/themes.class.php (revision 6217)
@@ -0,0 +1,787 @@
+get_fs_themes();
+
+ foreach ($this->get_db_themes() as $db_theme)
+ {
+ $this->db_themes_by_id[$db_theme['id']] = $db_theme;
+ }
+ }
+
+ /**
+ * Set tabsheet for themes pages.
+ * @param string selected page.
+ */
+ function set_tabsheet($selected)
+ {
+ include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
+
+ $link = get_root_url().'admin.php?page=';
+
+ $tabsheet = new tabsheet();
+ $tabsheet->add('themes_installed', l10n('Installed Themes'), $link.'themes_installed');
+ $tabsheet->add('themes_new', l10n('Add New Theme'), $link.'themes_new');
+ $tabsheet->select($selected);
+ $tabsheet->assign();
+ }
+
+ /**
+ * Perform requested actions
+ * @param string - action
+ * @param string - theme id
+ * @param array - errors
+ */
+ function perform_action($action, $theme_id)
+ {
+ if (isset($this->db_themes_by_id[$theme_id]))
+ {
+ $crt_db_theme = $this->db_themes_by_id[$theme_id];
+ }
+
+ $file_to_include = PHPWG_THEMES_PATH.'/'.$theme_id.'/admin/maintain.inc.php';
+
+ $errors = array();
+
+ switch ($action)
+ {
+ case 'activate':
+ if (isset($crt_db_theme))
+ {
+ // the theme is already active
+ break;
+ }
+
+ if ('default' == $theme_id)
+ {
+ // you can't activate the "default" theme
+ break;
+ }
+
+ $missing_parent = $this->missing_parent_theme($theme_id);
+ if (isset($missing_parent))
+ {
+ array_push(
+ $errors,
+ sprintf(
+ l10n('Impossible to activate this theme, the parent theme is missing: %s'),
+ $missing_parent
+ )
+ );
+
+ break;
+ }
+
+ if (file_exists($file_to_include))
+ {
+ include($file_to_include);
+ if (function_exists('theme_activate'))
+ {
+ theme_activate($theme_id, $this->fs_themes[$theme_id]['version'], $errors);
+ }
+ }
+
+ if (empty($errors))
+ {
+ $query = '
+INSERT INTO '.THEMES_TABLE.'
+ (id, version, name)
+ VALUES(\''.$theme_id.'\',
+ \''.$this->fs_themes[$theme_id]['version'].'\',
+ \''.$this->fs_themes[$theme_id]['name'].'\')
+;';
+ pwg_query($query);
+ }
+ break;
+
+ case 'deactivate':
+ if (!isset($crt_db_theme))
+ {
+ // the theme is already inactive
+ break;
+ }
+
+ // you can't deactivate the last theme
+ if (count($this->db_themes_by_id) <= 1)
+ {
+ array_push(
+ $errors,
+ l10n('Impossible to deactivate this theme, you need at least one theme.')
+ );
+ break;
+ }
+
+ if ($theme_id == get_default_theme())
+ {
+ // find a random theme to replace
+ $new_theme = null;
+
+ $query = '
+SELECT
+ id
+ FROM '.THEMES_TABLE.'
+ WHERE id != "'.$theme_id.'"
+;';
+ $result = pwg_query($query);
+ if (pwg_db_num_rows($result) == 0)
+ {
+ $new_theme = 'default';
+ }
+ else
+ {
+ list($new_theme) = pwg_db_fetch_row($result);
+ }
+
+ $this->set_default_theme($new_theme);
+ }
+
+ if (file_exists($file_to_include))
+ {
+ include($file_to_include);
+ if (function_exists('theme_deactivate'))
+ {
+ theme_deactivate($theme_id);
+ }
+ }
+
+ $query = "
+DELETE
+ FROM ".THEMES_TABLE."
+ WHERE id= '".$theme_id."'
+;";
+ pwg_query($query);
+ break;
+
+ case 'delete':
+ if (!empty($crt_db_theme))
+ {
+ array_push($errors, 'CANNOT DELETE - THEME IS INSTALLED');
+ break;
+ }
+ if (!isset($this->fs_themes[$theme_id]))
+ {
+ // nothing to do here
+ break;
+ }
+
+ $children = $this->get_children_themes($theme_id);
+ if (count($children) > 0)
+ {
+ array_push(
+ $errors,
+ sprintf(
+ l10n('Impossible to delete this theme. Other themes depends on it: %s'),
+ implode(', ', $children)
+ )
+ );
+ break;
+ }
+
+ if (!$this->deltree(PHPWG_THEMES_PATH.$theme_id))
+ {
+ $this->send_to_trash(PHPWG_THEMES_PATH.$theme_id);
+ }
+ break;
+
+ case 'set_default':
+ // first we need to know which users are using the current default theme
+ $this->set_default_theme($theme_id);
+ break;
+ }
+ return $errors;
+ }
+
+ function missing_parent_theme($theme_id)
+ {
+ if (!isset($this->fs_themes[$theme_id]['parent']))
+ {
+ return null;
+ }
+
+ $parent = $this->fs_themes[$theme_id]['parent'];
+
+ if ('default' == $parent)
+ {
+ return null;
+ }
+
+ if (!isset($this->fs_themes[$parent]))
+ {
+ return $parent;
+ }
+
+ return $this->missing_parent_theme($parent);
+ }
+
+ function get_children_themes($theme_id)
+ {
+ $children = array();
+
+ foreach ($this->fs_themes as $test_child)
+ {
+ if (isset($test_child['parent']) and $test_child['parent'] == $theme_id)
+ {
+ array_push($children, $test_child['name']);
+ }
+ }
+
+ return $children;
+ }
+
+ function set_default_theme($theme_id)
+ {
+ global $conf;
+
+ // first we need to know which users are using the current default theme
+ $default_theme = get_default_theme();
+
+ $query = '
+SELECT
+ user_id
+ FROM '.USER_INFOS_TABLE.'
+ WHERE theme = "'.$default_theme.'"
+;';
+ $user_ids = array_unique(
+ array_merge(
+ array_from_query($query, 'user_id'),
+ array($conf['guest_id'], $conf['default_user_id'])
+ )
+ );
+
+ // $user_ids can't be empty, at least the default user has the default
+ // theme
+
+ $query = '
+UPDATE '.USER_INFOS_TABLE.'
+ SET theme = "'.$theme_id.'"
+ WHERE user_id IN ('.implode(',', $user_ids).')
+;';
+ pwg_query($query);
+ }
+
+ function get_db_themes($id='')
+ {
+ $query = '
+SELECT
+ *
+ FROM '.THEMES_TABLE;
+
+ $clauses = array();
+ if (!empty($id))
+ {
+ $clauses[] = "id = '".$id."'";
+ }
+ if (count($clauses) > 0)
+ {
+ $query .= '
+ WHERE '. implode(' AND ', $clauses);
+ }
+
+ $result = pwg_query($query);
+ $themes = array();
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ array_push($themes, $row);
+ }
+ return $themes;
+ }
+
+
+ /**
+ * Get themes defined in the theme directory
+ */
+ function get_fs_themes()
+ {
+ $dir = opendir(PHPWG_THEMES_PATH);
+
+ while ($file = readdir($dir))
+ {
+ if ($file!='.' and $file!='..')
+ {
+ $path = PHPWG_THEMES_PATH.$file;
+ if (is_dir($path)
+ and preg_match('/^[a-zA-Z0-9-_]+$/', $file)
+ and file_exists($path.'/themeconf.inc.php')
+ )
+ {
+ $theme = array(
+ 'id' => $file,
+ 'name' => $file,
+ 'version' => '0',
+ 'uri' => '',
+ 'description' => '',
+ 'author' => '',
+ );
+ $theme_data = implode( '', file($path.'/themeconf.inc.php') );
+
+ if ( preg_match("|Theme Name: (.*)|", $theme_data, $val) )
+ {
+ $theme['name'] = trim( $val[1] );
+ }
+ if (preg_match("|Version: (.*)|", $theme_data, $val))
+ {
+ $theme['version'] = trim($val[1]);
+ }
+ if ( preg_match("|Theme URI: (.*)|", $theme_data, $val) )
+ {
+ $theme['uri'] = trim($val[1]);
+ }
+ if ($desc = load_language('description.txt', $path.'/', array('return' => true)))
+ {
+ $theme['description'] = trim($desc);
+ }
+ elseif ( preg_match("|Description: (.*)|", $theme_data, $val) )
+ {
+ $theme['description'] = trim($val[1]);
+ }
+ if ( preg_match("|Author: (.*)|", $theme_data, $val) )
+ {
+ $theme['author'] = trim($val[1]);
+ }
+ if ( preg_match("|Author URI: (.*)|", $theme_data, $val) )
+ {
+ $theme['author uri'] = trim($val[1]);
+ }
+ if (!empty($theme['uri']) and strpos($theme['uri'] , 'extension_view.php?eid='))
+ {
+ list( , $extension) = explode('extension_view.php?eid=', $theme['uri']);
+ if (is_numeric($extension)) $theme['extension'] = $extension;
+ }
+ if (preg_match('/["\']parent["\'][^"\']+["\']([^"\']+)["\']/', $theme_data, $val))
+ {
+ $theme['parent'] = $val[1];
+ }
+ if (preg_match('/["\']activable["\'].*?(true|false)/', $theme_data, $val))
+ {
+ $theme['activable'] = get_boolean($val[1]);
+ }
+
+ // screenshot
+ $screenshot_path = $path.'/screenshot.png';
+ if (file_exists($screenshot_path))
+ {
+ $theme['screenshot'] = $screenshot_path;
+ }
+ else
+ {
+ global $conf;
+ $theme['screenshot'] =
+ PHPWG_ROOT_PATH.'admin/themes/'
+ .$conf['admin_theme']
+ .'/images/missing_screenshot.png'
+ ;
+ }
+
+ $admin_file = $path.'/admin/admin.inc.php';
+ if (file_exists($admin_file))
+ {
+ $theme['admin_uri'] = get_root_url().'admin.php?page=theme&theme='.$file;
+ }
+
+ // IMPORTANT SECURITY !
+ $theme = array_map('htmlspecialchars', $theme);
+ $this->fs_themes[$file] = $theme;
+ }
+ }
+ }
+ closedir($dir);
+ }
+
+ /**
+ * Sort fs_themes
+ */
+ function sort_fs_themes($order='name')
+ {
+ switch ($order)
+ {
+ case 'name':
+ uasort($this->fs_themes, 'name_compare');
+ break;
+ case 'status':
+ $this->sort_themes_by_state();
+ break;
+ case 'author':
+ uasort($this->fs_themes, array($this, 'theme_author_compare'));
+ break;
+ case 'id':
+ uksort($this->fs_themes, 'strcasecmp');
+ break;
+ }
+ }
+
+ /**
+ * Retrieve PEM server datas to $server_themes
+ */
+ function get_server_themes($new=false)
+ {
+ global $user;
+
+ $pem_category_id = 10;
+
+ // Retrieve PEM versions
+ $version = PHPWG_VERSION;
+ $versions_to_check = array();
+ $url = PEM_URL . '/api/get_version_list.php?category_id='.$pem_category_id.'&format=php';
+ if (fetchRemote($url, $result) 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;
+ }
+
+ // Themes to check
+ $themes_to_check = array();
+ foreach($this->fs_themes as $fs_theme)
+ {
+ if (isset($fs_theme['extension']))
+ {
+ $themes_to_check[] = $fs_theme['extension'];
+ }
+ }
+
+ // Retrieve PEM themes infos
+ $url = PEM_URL . '/api/get_revision_list.php?category_id='.$pem_category_id.'&format=php&last_revision_only=true';
+ $url .= '&version=' . implode(',', $versions_to_check);
+ $url .= '&lang=' . substr($user['language'], 0, 2);
+ $url .= '&get_nb_downloads=true';
+
+ if (!empty($themes_to_check))
+ {
+ $url .= $new ? '&extension_exclude=' : '&extension_include=';
+ $url .= implode(',', $themes_to_check);
+ }
+ if (fetchRemote($url, $result))
+ {
+ $pem_themes = @unserialize($result);
+ if (!is_array($pem_themes))
+ {
+ return false;
+ }
+ foreach ($pem_themes as $theme)
+ {
+ $this->server_themes[$theme['extension_id']] = $theme;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sort $server_themes
+ */
+ function sort_server_themes($order='date')
+ {
+ switch ($order)
+ {
+ case 'date':
+ krsort($this->server_themes);
+ break;
+ case 'revision':
+ usort($this->server_themes, array($this, 'extension_revision_compare'));
+ break;
+ case 'name':
+ uasort($this->server_themes, array($this, 'extension_name_compare'));
+ break;
+ case 'author':
+ uasort($this->server_themes, array($this, 'extension_author_compare'));
+ break;
+ case 'downloads':
+ usort($this->server_themes, array($this, 'extension_downloads_compare'));
+ break;
+ }
+ }
+
+ /**
+ * Extract theme files from archive
+ *
+ * @param string - install or upgrade
+ * @param string - remote revision identifier (numeric)
+ * @param string - theme id or extension id
+ */
+ function extract_theme_files($action, $revision, $dest)
+ {
+ if ($archive = tempnam( PHPWG_THEMES_PATH, 'zip'))
+ {
+ $url = PEM_URL . '/download.php?rid=' . $revision;
+ $url .= '&origin=piwigo_' . $action;
+
+ if ($handle = @fopen($archive, 'wb') and fetchRemote($url, $handle))
+ {
+ fclose($handle);
+ include(PHPWG_ROOT_PATH.'admin/include/pclzip.lib.php');
+ $zip = new PclZip($archive);
+ if ($list = $zip->listContent())
+ {
+ foreach ($list as $file)
+ {
+ // we search main.inc.php in archive
+ if (basename($file['filename']) == 'themeconf.inc.php'
+ and (!isset($main_filepath)
+ or strlen($file['filename']) < strlen($main_filepath)))
+ {
+ $main_filepath = $file['filename'];
+ }
+ }
+ if (isset($main_filepath))
+ {
+ $root = dirname($main_filepath); // main.inc.php path in archive
+ if ($action == 'upgrade')
+ {
+ $extract_path = PHPWG_THEMES_PATH . $dest;
+ }
+ else
+ {
+ $extract_path = PHPWG_THEMES_PATH . ($root == '.' ? 'extension_' . $dest : basename($root));
+ }
+ if (
+ $result = $zip->extract(
+ PCLZIP_OPT_PATH, $extract_path,
+ PCLZIP_OPT_REMOVE_PATH, $root,
+ PCLZIP_OPT_REPLACE_NEWER
+ )
+ )
+ {
+ foreach ($result as $file)
+ {
+ if ($file['stored_filename'] == $main_filepath)
+ {
+ $status = $file['status'];
+ break;
+ }
+ }
+ if (file_exists($extract_path.'/obsolete.list')
+ and $old_files = file($extract_path.'/obsolete.list', FILE_IGNORE_NEW_LINES)
+ and !empty($old_files))
+ {
+ array_push($old_files, 'obsolete.list');
+ foreach($old_files as $old_file)
+ {
+ $path = $extract_path.'/'.$old_file;
+ if (is_file($path))
+ {
+ @unlink($path);
+ }
+ elseif (is_dir($path))
+ {
+ if (!$this->deltree($path))
+ {
+ $this->send_to_trash($path);
+ }
+ }
+ }
+ }
+ }
+ else $status = 'extract_error';
+ }
+ else $status = 'archive_error';
+ }
+ else $status = 'archive_error';
+ }
+ else $status = 'dl_archive_error';
+ }
+ else $status = 'temp_path_error';
+
+ @unlink($archive);
+ return $status;
+ }
+
+ /**
+ * delete $path directory
+ * @param string - path
+ */
+ function deltree($path)
+ {
+ if (is_dir($path))
+ {
+ $fh = opendir($path);
+ while ($file = readdir($fh))
+ {
+ if ($file != '.' and $file != '..')
+ {
+ $pathfile = $path . '/' . $file;
+ if (is_dir($pathfile))
+ {
+ $this->deltree($pathfile);
+ }
+ else
+ {
+ @unlink($pathfile);
+ }
+ }
+ }
+ closedir($fh);
+ return @rmdir($path);
+ }
+ }
+
+ /**
+ * send $path to trash directory
+ * @param string - path
+ */
+ function send_to_trash($path)
+ {
+ $trash_path = PHPWG_THEMES_PATH . 'trash';
+ if (!is_dir($trash_path))
+ {
+ @mkdir($trash_path);
+ $file = @fopen($trash_path . '/.htaccess', 'w');
+ @fwrite($file, 'deny from all');
+ @fclose($file);
+ }
+ while ($r = $trash_path . '/' . md5(uniqid(rand(), true)))
+ {
+ if (!is_dir($r))
+ {
+ @rename($path, $r);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Sort functions
+ */
+ function theme_version_compare($a, $b)
+ {
+ $pattern = array('/([a-z])/ei', '/\.+/', '/\.\Z|\A\./');
+ $replacement = array( "'.'.intval('\\1', 36).'.'", '.', '');
+
+ $array = preg_replace($pattern, $replacement, array($a, $b));
+
+ return version_compare($array[0], $array[1], '>=');
+ }
+
+ function extension_revision_compare($a, $b)
+ {
+ if ($a['revision_date'] < $b['revision_date']) return 1;
+ else return -1;
+ }
+
+ function extension_name_compare($a, $b)
+ {
+ return strcmp(strtolower($a['extension_name']), strtolower($b['extension_name']));
+ }
+
+ function extension_author_compare($a, $b)
+ {
+ $r = strcasecmp($a['author_name'], $b['author_name']);
+ if ($r == 0) return $this->extension_name_compare($a, $b);
+ else return $r;
+ }
+
+ function theme_author_compare($a, $b)
+ {
+ $r = strcasecmp($a['author'], $b['author']);
+ if ($r == 0) return name_compare($a, $b);
+ else return $r;
+ }
+
+ function extension_downloads_compare($a, $b)
+ {
+ if ($a['extension_nb_downloads'] < $b['extension_nb_downloads']) return 1;
+ else return -1;
+ }
+
+ function sort_themes_by_state()
+ {
+ uasort($this->fs_themes, 'name_compare');
+
+ $active_themes = array();
+ $inactive_themes = array();
+ $not_installed = array();
+
+ foreach($this->fs_themes as $theme_id => $theme)
+ {
+ if (isset($this->db_themes_by_id[$theme_id]))
+ {
+ $this->db_themes_by_id[$theme_id]['state'] == 'active' ?
+ $active_themes[$theme_id] = $theme : $inactive_themes[$theme_id] = $theme;
+ }
+ else
+ {
+ $not_installed[$theme_id] = $theme;
+ }
+ }
+ $this->fs_themes = $active_themes + $inactive_themes + $not_installed;
+ }
+
+ // themes specific methods
+ function get_fs_themes_with_ini()
+ {
+ $themes_dir = PHPWG_ROOT_PATH.'themes';
+
+ $fs_themes = array();
+
+ foreach (get_dirs($themes_dir) as $theme)
+ {
+ $conf_file = $themes_dir.'/'.$theme.'/themeconf.inc.php';
+ if (file_exists($conf_file))
+ {
+ $theme_data = array(
+ 'name' => $theme,
+ );
+
+ $ini_file = $themes_dir.'/'.$theme.'/theme.ini';
+ if (file_exists($ini_file))
+ {
+ $theme_ini = parse_ini_file($ini_file);
+ if (isset($theme_ini['extension_id']))
+ {
+ $theme_data['extension_id'] = $theme_ini['extension_id'];
+ }
+ }
+
+ array_push($fs_themes, $theme_data);
+ }
+ }
+
+ echo '
'; print_r($fs_themes); echo '
';
+ }
+
+
+}
+?>
Index: /tags/2.1.0/admin/include/uploadify/jquery.uploadify.v2.1.0.min.js
===================================================================
--- /tags/2.1.0/admin/include/uploadify/jquery.uploadify.v2.1.0.min.js (revision 6217)
+++ /tags/2.1.0/admin/include/uploadify/jquery.uploadify.v2.1.0.min.js (revision 6217)
@@ -0,0 +1,26 @@
+/*
+Uploadify v2.1.0
+Release Date: August 24, 2009
+
+Copyright (c) 2009 Ronnie Garcia, Travis Nickels
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+if(jQuery){(function(a){a.extend(a.fn,{uploadify:function(b){a(this).each(function(){settings=a.extend({id:a(this).attr("id"),uploader:"uploadify.swf",script:"uploadify.php",expressInstall:null,folder:"",height:30,width:110,cancelImg:"cancel.png",wmode:"opaque",scriptAccess:"sameDomain",fileDataName:"Filedata",method:"POST",queueSizeLimit:999,simUploadLimit:1,queueID:false,displayData:"percentage",onInit:function(){},onSelect:function(){},onQueueFull:function(){},onCheck:function(){},onCancel:function(){},onError:function(){},onProgress:function(){},onComplete:function(){},onAllComplete:function(){}},b);var e=location.pathname;e=e.split("/");e.pop();e=e.join("/")+"/";var f={};f.uploadifyID=settings.id;f.pagepath=e;if(settings.buttonImg){f.buttonImg=escape(settings.buttonImg)}if(settings.buttonText){f.buttonText=escape(settings.buttonText)}if(settings.rollover){f.rollover=true}f.script=settings.script;f.folder=escape(settings.folder);if(settings.scriptData){var g="";for(var d in settings.scriptData){g+="&"+d+"="+settings.scriptData[d]}f.scriptData=escape(g.substr(1))}f.width=settings.width;f.height=settings.height;f.wmode=settings.wmode;f.method=settings.method;f.queueSizeLimit=settings.queueSizeLimit;f.simUploadLimit=settings.simUploadLimit;if(settings.hideButton){f.hideButton=true}if(settings.fileDesc){f.fileDesc=settings.fileDesc}if(settings.fileExt){f.fileExt=settings.fileExt}if(settings.multi){f.multi=true}if(settings.auto){f.auto=true}if(settings.sizeLimit){f.sizeLimit=settings.sizeLimit}if(settings.checkScript){f.checkScript=settings.checkScript}if(settings.fileDataName){f.fileDataName=settings.fileDataName}if(settings.queueID){f.queueID=settings.queueID}if(settings.onInit()!==false){a(this).css("display","none");a(this).after('');swfobject.embedSWF(settings.uploader,settings.id+"Uploader",settings.width,settings.height,"9.0.24",settings.expressInstall,f,{quality:"high",wmode:settings.wmode,allowScriptAccess:settings.scriptAccess});if(settings.queueID==false){a("#"+a(this).attr("id")+"Uploader").after('')}}if(typeof(settings.onOpen)=="function"){a(this).bind("uploadifyOpen",settings.onOpen)}a(this).bind("uploadifySelect",{action:settings.onSelect,queueID:settings.queueID},function(j,h,i){if(j.data.action(j,h,i)!==false){var k=Math.round(i.size/1024*100)*0.01;var l="KB";if(k>1000){k=Math.round(k*0.001*100)*0.01;l="MB"}var m=k.toString().split(".");if(m.length>1){k=m[0]+"."+m[1].substr(0,2)}else{k=m[0]}if(i.name.length>20){fileName=i.name.substr(0,20)+"..."}else{fileName=i.name}queue="#"+a(this).attr("id")+"Queue";if(j.data.queueID){queue="#"+j.data.queueID}a(queue).append('
'+fileName+" ("+k+l+')
')}});if(typeof(settings.onSelectOnce)=="function"){a(this).bind("uploadifySelectOnce",settings.onSelectOnce)}a(this).bind("uploadifyQueueFull",{action:settings.onQueueFull},function(h,i){if(h.data.action(h,i)!==false){alert("The queue is full. The max size is "+i+".")}});a(this).bind("uploadifyCheckExist",{action:settings.onCheck},function(m,l,k,j,o){var i=new Object();i=k;i.folder=e+j;if(o){for(var h in k){var n=h}}a.post(l,i,function(r){for(var p in r){if(m.data.action(m,l,k,j,o)!==false){var q=confirm("Do you want to replace the file "+r[p]+"?");if(!q){document.getElementById(a(m.target).attr("id")+"Uploader").cancelFileUpload(p,true,true)}}}if(o){document.getElementById(a(m.target).attr("id")+"Uploader").startFileUpload(n,true)}else{document.getElementById(a(m.target).attr("id")+"Uploader").startFileUpload(null,true)}},"json")});a(this).bind("uploadifyCancel",{action:settings.onCancel},function(l,h,k,m,j){if(l.data.action(l,h,k,m,j)!==false){var i=(j==true)?0:250;a("#"+a(this).attr("id")+h).fadeOut(i,function(){a(this).remove()})}});if(typeof(settings.onClearQueue)=="function"){a(this).bind("uploadifyClearQueue",settings.onClearQueue)}var c=[];a(this).bind("uploadifyError",{action:settings.onError},function(l,h,k,j){if(l.data.action(l,h,k,j)!==false){var i=new Array(h,k,j);c.push(i);a("#"+a(this).attr("id")+h+" .percentage").text(" - "+j.type+" Error");a("#"+a(this).attr("id")+h).addClass("uploadifyError")}});a(this).bind("uploadifyProgress",{action:settings.onProgress,toDisplay:settings.displayData},function(j,h,i,k){if(j.data.action(j,h,i,k)!==false){a("#"+a(this).attr("id")+h+"ProgressBar").css("width",k.percentage+"%");if(j.data.toDisplay=="percentage"){displayData=" - "+k.percentage+"%"}if(j.data.toDisplay=="speed"){displayData=" - "+k.speed+"KB/s"}if(j.data.toDisplay==null){displayData=" "}a("#"+a(this).attr("id")+h+" .percentage").text(displayData)}});a(this).bind("uploadifyComplete",{action:settings.onComplete},function(k,h,j,i,l){if(k.data.action(k,h,j,unescape(i),l)!==false){a("#"+a(this).attr("id")+h+" .percentage").text(" - Completed");a("#"+a(this).attr("id")+h).fadeOut(250,function(){a(this).remove()})}});if(typeof(settings.onAllComplete)=="function"){a(this).bind("uploadifyAllComplete",{action:settings.onAllComplete},function(h,i){if(h.data.action(h,i)!==false){c=[]}})}})},uploadifySettings:function(f,j,c){var g=false;a(this).each(function(){if(f=="scriptData"&&j!=null){if(c){var i=j}else{var i=a.extend(settings.scriptData,j)}var l="";for(var k in i){l+="&"+k+"="+escape(i[k])}j=l.substr(1)}g=document.getElementById(a(this).attr("id")+"Uploader").updateSettings(f,j)});if(j==null){if(f=="scriptData"){var b=unescape(g).split("&");var e=new Object();for(var d=0;d
+ is released under the MIT License
+*/
+var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab
Index: /tags/2.1.0/admin/index.php
===================================================================
--- /tags/2.1.0/admin/index.php (revision 6217)
+++ /tags/2.1.0/admin/index.php (revision 6217)
@@ -0,0 +1,30 @@
+
Index: /tags/2.1.0/admin/intro.php
===================================================================
--- /tags/2.1.0/admin/intro.php (revision 6217)
+++ /tags/2.1.0/admin/intro.php (revision 6217)
@@ -0,0 +1,294 @@
+ PHPWG_VERSION);
+ $lines = @explode("\r\n", $result);
+
+ // if the current version is a BSF (development branch) build, we check
+ // the first line, for stable versions, we check the second line
+ if (preg_match('/^BSF/', $versions['current']))
+ {
+ $versions['latest'] = trim($lines[0]);
+
+ // because integer are limited to 4,294,967,296 we need to split BSF
+ // versions in date.time
+ foreach ($versions as $key => $value)
+ {
+ $versions[$key] =
+ preg_replace('/BSF_(\d{8})(\d{4})/', '$1.$2', $value);
+ }
+ }
+ else
+ {
+ $versions['latest'] = trim($lines[1]);
+ }
+
+ if ('' == $versions['latest'])
+ {
+ array_push(
+ $page['errors'],
+ l10n('Check for upgrade failed for unknown reasons.')
+ );
+ }
+ // concatenation needed to avoid automatic transformation by release
+ // script generator
+ else if ('%'.'PWGVERSION'.'%' == $versions['current'])
+ {
+ array_push(
+ $page['infos'],
+ l10n('You are running on development sources, no check possible.')
+ );
+ }
+ else if (version_compare($versions['current'], $versions['latest']) < 0)
+ {
+ array_push(
+ $page['infos'],
+ l10n('A new version of Piwigo is available.')
+ );
+ }
+ else
+ {
+ array_push(
+ $page['infos'],
+ l10n('You are running the latest version of Piwigo.')
+ );
+ }
+ }
+}
+// Show phpinfo() output
+else if (isset($_GET['action']) and 'phpinfo' == $_GET['action'])
+{
+ phpinfo();
+ exit();
+}
+
+// +-----------------------------------------------------------------------+
+// | template init |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(array('intro' => 'intro.tpl'));
+
+if ($conf['show_newsletter_subscription']) {
+ $template->assign(
+ array(
+ 'EMAIL' => $user['email'],
+ 'SUBSCRIBE_BASE_URL' => get_newsletter_subscribe_base_url($user['language']),
+ )
+ );
+}
+
+$php_current_timestamp = date("Y-m-d H:i:s");
+$db_version = pwg_get_db_version();
+list($db_current_timestamp) = pwg_db_fetch_row(pwg_query('SELECT CURRENT_TIMESTAMP;'));
+
+$query = '
+SELECT COUNT(*)
+ FROM '.IMAGES_TABLE.'
+;';
+list($nb_elements) = pwg_db_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+ FROM '.CATEGORIES_TABLE.'
+;';
+list($nb_categories) = pwg_db_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+ FROM '.CATEGORIES_TABLE.'
+ WHERE dir IS NULL
+;';
+list($nb_virtual) = pwg_db_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+ FROM '.CATEGORIES_TABLE.'
+ WHERE dir IS NOT NULL
+;';
+list($nb_physical) = pwg_db_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+ FROM '.IMAGE_CATEGORY_TABLE.'
+;';
+list($nb_image_category) = pwg_db_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+ FROM '.TAGS_TABLE.'
+;';
+list($nb_tags) = pwg_db_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+ FROM '.IMAGE_TAG_TABLE.'
+;';
+list($nb_image_tag) = pwg_db_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+ FROM '.USERS_TABLE.'
+;';
+list($nb_users) = pwg_db_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+ FROM '.GROUPS_TABLE.'
+;';
+list($nb_groups) = pwg_db_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+ FROM '.COMMENTS_TABLE.'
+;';
+list($nb_comments) = pwg_db_fetch_row(pwg_query($query));
+
+$template->assign(
+ array(
+ 'PHPWG_URL' => PHPWG_URL,
+ 'PWG_VERSION' => PHPWG_VERSION,
+ 'OS' => PHP_OS,
+ 'PHP_VERSION' => phpversion(),
+ 'DB_ENGINE' => $conf['dblayer'],
+ 'DB_VERSION' => $db_version,
+ 'DB_ELEMENTS' => l10n_dec('%d image', '%d images', $nb_elements),
+ 'DB_CATEGORIES' =>
+ l10n_dec('%d category including', '%d categories including',
+ $nb_categories).
+ l10n_dec('%d physical', '%d physical',
+ $nb_physical).
+ l10n_dec(' and %d virtual', ' and %d virtual',
+ $nb_virtual),
+ 'DB_IMAGE_CATEGORY' => l10n_dec('%d association', '%d associations', $nb_image_category),
+ 'DB_TAGS' => l10n_dec('%d tag', '%d tags', $nb_tags),
+ 'DB_IMAGE_TAG' => l10n_dec('%d association', '%d associations', $nb_image_tag),
+ 'DB_USERS' => l10n_dec('%d user', '%d users', $nb_users),
+ 'DB_GROUPS' => l10n_dec('%d group', '%d groups', $nb_groups),
+ 'DB_COMMENTS' => l10n_dec('%d comment', '%d comments', $nb_comments),
+ 'U_CHECK_UPGRADE' => PHPWG_ROOT_PATH.'admin.php?action=check_upgrade',
+ 'U_PHPINFO' => PHPWG_ROOT_PATH.'admin.php?action=phpinfo',
+ 'PHP_DATATIME' => $php_current_timestamp,
+ 'DB_DATATIME' => $db_current_timestamp,
+ )
+ );
+
+if ($nb_elements > 0)
+{
+ $query = '
+SELECT MIN(date_available)
+ FROM '.IMAGES_TABLE.'
+;';
+ list($first_date) = pwg_db_fetch_row(pwg_query($query));
+
+ $template->assign(
+ 'first_added',
+ array(
+ 'DB_DATE' =>
+ sprintf(
+ l10n('first element added on %s'),
+ format_date($first_date)
+ )
+ )
+ );
+}
+
+// waiting elements
+$query = '
+SELECT COUNT(*)
+ FROM '.WAITING_TABLE.'
+ WHERE validated=\'false\'
+;';
+list($nb_waiting) = pwg_db_fetch_row(pwg_query($query));
+
+if ($nb_waiting > 0)
+{
+ $template->assign(
+ 'waiting',
+ array(
+ 'URL' => PHPWG_ROOT_PATH.'admin.php?page=upload',
+ 'INFO' => sprintf(l10n('%d waiting for validation'), $nb_waiting)
+ )
+ );
+}
+
+// unvalidated comments
+$query = '
+SELECT COUNT(*)
+ FROM '.COMMENTS_TABLE.'
+ WHERE validated=\'false\'
+;';
+list($nb_comments) = pwg_db_fetch_row(pwg_query($query));
+
+if ($nb_comments > 0)
+{
+ $template->assign(
+ 'unvalidated',
+ array(
+ 'URL' => PHPWG_ROOT_PATH.'admin.php?page=comments',
+ 'INFO' => sprintf(l10n('%d waiting for validation'), $nb_comments)
+ )
+ );
+}
+
+// +-----------------------------------------------------------------------+
+// | sending html code |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'intro');
+
+// Check integrity
+$c13y = new check_integrity();
+// add internal checks
+new c13y_internal();
+// check and display
+$c13y->check();
+$c13y->display();
+
+?>
Index: /tags/2.1.0/admin/languages_installed.php
===================================================================
--- /tags/2.1.0/admin/languages_installed.php (revision 6217)
+++ /tags/2.1.0/admin/languages_installed.php (revision 6217)
@@ -0,0 +1,131 @@
+set_filenames(array('languages' => 'languages_installed.tpl'));
+
+$base_url = get_root_url().'admin.php?page='.$page['page'];
+
+$languages = new languages();
+$languages->get_db_languages();
+$languages->set_tabsheet($page['page']);
+
+//--------------------------------------------------perform requested actions
+if (isset($_GET['action']) and isset($_GET['language']) and !is_adviser())
+{
+ $page['errors'] = $languages->perform_action($_GET['action'], $_GET['language']);
+
+ if (empty($page['errors']))
+ {
+ redirect($base_url);
+ }
+}
+
+// +-----------------------------------------------------------------------+
+// | start template output |
+// +-----------------------------------------------------------------------+
+$default_language = get_default_language();
+
+$tpl_languages = array();
+
+foreach($languages->fs_languages as $language_id => $language_name)
+{
+ $language = array(
+ 'id' => $language_id,
+ 'name' => $language_name,
+ 'u_action' => $base_url.'&language='.$language_id,
+ );
+
+ if (in_array($language_id, array_keys($languages->db_languages)))
+ {
+ $language['state'] = 'active';
+ $language['deactivable'] = true;
+
+ if (count($languages->db_languages) <= 1)
+ {
+ $language['deactivable'] = false;
+ $language['deactivate_tooltip'] = l10n('Impossible to deactivate this language, you need at least one language.');
+ }
+
+ if ($language_id == $default_language)
+ {
+ $language['deactivable'] = false;
+ $language['deactivate_tooltip'] = l10n('Impossible to deactivate this language, first set another language as default.');
+ }
+ }
+ else
+ {
+ $language['state'] = 'inactive';
+ }
+
+ if ($language_id == $default_language)
+ {
+ $language['is_default'] = true;
+ array_unshift($tpl_languages, $language);
+ }
+ else
+ {
+ $language['is_default'] = false;
+ array_push($tpl_languages, $language);
+ }
+}
+
+$template->assign(
+ array(
+ 'languages' => $tpl_languages,
+ )
+ );
+$template->append('language_states', 'active');
+$template->append('language_states', 'inactive');
+
+
+$missing_language_ids = array_diff(
+ array_keys($languages->db_languages),
+ array_keys($languages->fs_languages)
+ );
+
+foreach($missing_language_ids as $language_id)
+{
+ $query = '
+UPDATE '.USER_INFOS_TABLE.'
+ SET language = "'.get_default_language().'"
+ WHERE language = "'.$language_id.'"
+;';
+ pwg_query($query);
+
+ $query = "
+DELETE
+ FROM ".LANGUAGES_TABLE."
+ WHERE id= '".$language_id."'
+;";
+ pwg_query($query);
+}
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'languages');
+?>
Index: /tags/2.1.0/admin/languages_new.php
===================================================================
--- /tags/2.1.0/admin/languages_new.php (revision 6217)
+++ /tags/2.1.0/admin/languages_new.php (revision 6217)
@@ -0,0 +1,139 @@
+set_filenames(array('languages' => 'languages_new.tpl'));
+
+$base_url = get_root_url().'admin.php?page='.$page['page'];
+
+$languages = new languages();
+$languages->get_db_languages();
+$languages->set_tabsheet($page['page']);
+
+// +-----------------------------------------------------------------------+
+// | setup check |
+// +-----------------------------------------------------------------------+
+
+$languages_dir = PHPWG_ROOT_PATH.'language';
+if (!is_writable($languages_dir))
+{
+ array_push(
+ $page['errors'],
+ sprintf(
+ l10n('Add write access to the "%s" directory'),
+ 'language'
+ )
+ );
+}
+
+// +-----------------------------------------------------------------------+
+// | perform installation |
+// +-----------------------------------------------------------------------+
+
+if (isset($_GET['revision']) and !is_adviser())
+{
+ if (!is_webmaster())
+ {
+ array_push($page['errors'], l10n('Webmaster status is required.'));
+ }
+ else
+ {
+ check_pwg_token();
+
+ $install_status = $languages->extract_language_files('install', $_GET['revision']);
+
+ redirect($base_url.'&installstatus='.$install_status);
+ }
+}
+
+// +-----------------------------------------------------------------------+
+// | installation result |
+// +-----------------------------------------------------------------------+
+if (isset($_GET['installstatus']))
+{
+ switch ($_GET['installstatus'])
+ {
+ case 'ok':
+ array_push($page['infos'],
+ l10n('Language has been successfully installed')
+ );
+ break;
+
+ case 'temp_path_error':
+ array_push($page['errors'], l10n('Can\'t create temporary file.'));
+ break;
+
+ case 'dl_archive_error':
+ array_push($page['errors'], l10n('Can\'t download archive.'));
+ break;
+
+ case 'archive_error':
+ array_push($page['errors'], l10n('Can\'t read or extract archive.'));
+ break;
+
+ default:
+ array_push($page['errors'],
+ sprintf(l10n('An error occured during extraction (%s).'), $_GET['installstatus'])
+ );
+ }
+}
+
+// +-----------------------------------------------------------------------+
+// | start template output |
+// +-----------------------------------------------------------------------+
+if ($languages->get_server_languages())
+{
+ foreach($languages->server_languages as $language)
+ {
+ list($date, ) = explode(' ', $language['revision_date']);
+
+ $url_auto_install = htmlentities($base_url)
+ . '&revision=' . $language['revision_id']
+ . '&pwg_token='.get_pwg_token()
+ ;
+
+ $template->append('languages', array(
+ 'EXT_NAME' => $language['extension_name'],
+ 'EXT_DESC' => $language['extension_description'],
+ 'EXT_URL' => PEM_URL.'/extension_view.php?eid='.$language['extension_id'],
+ 'VERSION' => $language['revision_name'],
+ 'VER_DESC' => $language['revision_description'],
+ 'DATE' => $date,
+ 'AUTHOR' => $language['author_name'],
+ 'URL_INSTALL' => $url_auto_install,
+ 'URL_DOWNLOAD' => $language['download_url'] . '&origin=piwigo_download'));
+ }
+}
+else
+{
+ array_push($page['errors'], l10n('Can\'t connect to server.'));
+}
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'languages');
+?>
Index: /tags/2.1.0/admin/maintenance.php
===================================================================
--- /tags/2.1.0/admin/maintenance.php (revision 6217)
+++ /tags/2.1.0/admin/maintenance.php (revision 6217)
@@ -0,0 +1,182 @@
+maintenance();
+ break;
+ }
+ case 'search' :
+ {
+ $query = '
+DELETE
+ FROM '.SEARCH_TABLE.'
+;';
+ pwg_query($query);
+ break;
+ }
+ case 'compiled-templates' :
+ {
+ $template->delete_compiled_templates();
+ break;
+ }
+ default :
+ {
+ break;
+ }
+}
+
+// +-----------------------------------------------------------------------+
+// | template init |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(array('maintenance'=>'maintenance.tpl'));
+
+$start_url = get_root_url().'admin.php?page=maintenance&action=';
+
+$template->assign(
+ array(
+ 'U_MAINT_CATEGORIES' => $start_url.'categories',
+ 'U_MAINT_IMAGES' => $start_url.'images',
+ 'U_MAINT_HISTORY_DETAIL' => $start_url.'history_detail',
+ 'U_MAINT_HISTORY_SUMMARY' => $start_url.'history_summary',
+ 'U_MAINT_SESSIONS' => $start_url.'sessions',
+ 'U_MAINT_FEEDS' => $start_url.'feeds',
+ 'U_MAINT_DATABASE' => $start_url.'database',
+ 'U_MAINT_C13Y' => $start_url.'c13y',
+ 'U_MAINT_SEARCH' => $start_url.'search',
+ 'U_MAINT_COMPILED_TEMPLATES' => $start_url.'compiled-templates',
+ 'U_HELP' => get_root_url().'admin/popuphelp.php?page=maintenance',
+ )
+ );
+
+// +-----------------------------------------------------------------------+
+// | Define advanced features |
+// +-----------------------------------------------------------------------+
+
+$advanced_features = array();
+
+array_push(
+ $advanced_features,
+ array(
+ 'CAPTION' => l10n('Not linked elements'),
+ 'URL' => get_root_url().'admin.php?page=element_set&cat=not_linked'
+ )
+ );
+
+array_push(
+ $advanced_features,
+ array(
+ 'CAPTION' => l10n('Files with same name in more than one physical category'),
+ 'URL' => get_root_url().'admin.php?page=element_set&cat=duplicates'
+ )
+ );
+
+//$advanced_features is array of array composed of CAPTION & URL
+$advanced_features = trigger_event(
+ 'get_admin_advanced_features_links',
+ $advanced_features
+ );
+
+$template->assign('advanced_features', $advanced_features);
+
+// +-----------------------------------------------------------------------+
+// | sending html code |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'maintenance');
+?>
Index: /tags/2.1.0/admin/menubar.php
===================================================================
--- /tags/2.1.0/admin/menubar.php (revision 6217)
+++ /tags/2.1.0/admin/menubar.php (revision 6217)
@@ -0,0 +1,171 @@
+$pos)
+ {
+ $orders[$id] = $step * ($pos<0 ? -$crt : $crt);
+ $crt++;
+ }
+}
+
+
+global $template;
+
+include_once(PHPWG_ROOT_PATH.'include/block.class.php');
+
+$menu = new BlockManager('menubar');
+$menu->load_registered_blocks();
+$reg_blocks = $menu->get_registered_blocks();
+
+$mb_conf = @$conf[ 'blk_'.$menu->get_id() ];
+if ( is_string($mb_conf) )
+ $mb_conf = unserialize( $mb_conf );
+if ( !is_array($mb_conf) )
+ $mb_conf=array();
+
+foreach ($mb_conf as $id => $pos)
+{
+ if (!isset($reg_blocks[$id]))
+ unset($mb_conf[$id]);
+}
+
+if ( isset($_POST['reset']) and !is_adviser())
+{
+ $mb_conf = array();
+ $query = '
+UPDATE '.CONFIG_TABLE.'
+ SET value=\'\'
+ WHERE param=\'blk_'.addslashes($menu->get_id()).'\'
+ LIMIT 1';
+ pwg_query($query);
+}
+
+
+$idx=1;
+foreach ($reg_blocks as $id => $block)
+{
+ if ( !isset($mb_conf[$id]) )
+ $mb_conf[$id] = $idx*50;
+ $idx++;
+}
+
+
+if ( isset($_POST['submit']) and !is_adviser() )
+{
+ foreach ( $mb_conf as $id => $pos )
+ {
+ $hide = isset($_POST['hide_'.$id]);
+ $mb_conf[$id] = ($hide ? -1 : +1)*abs($pos);
+
+ $pos = (int)@$_POST['pos_'.$id];
+ if ($pos>0)
+ $mb_conf[$id] = $mb_conf[$id] > 0 ? $pos : -$pos;
+ }
+ make_consecutive( $mb_conf );
+
+ // BEGIN OPTIM - DONT ASK ABOUT THIS ALGO - but optimizes the size of the array we save in DB
+ /* !!! OPTIM DISABLED UNTIL IT HAS BEEN FIXED !!!
+ $reg_keys = array_keys($reg_blocks);
+ $cnf_keys = array_keys($mb_conf);
+ $best_slice = array( 'len'=>0 );
+ for ($i=0; $i$best_slice['len'])
+ {
+ $best_slice['len'] = 1+$k;
+ $best_slice['start_cnf'] = $j;
+ }
+ }
+ else
+ break;
+ }
+ }
+ }
+ */
+ $mb_conf_db = $mb_conf;
+ /*
+ if ($best_slice['len'])
+ {
+ for ($j=0; $j<$best_slice['start_cnf']; $j++ )
+ {
+ $sign = $mb_conf_db[ $cnf_keys[$j] ] > 0 ? 1 : -1;
+ $mb_conf_db[ $cnf_keys[$j] ] = $sign * ( ($best_slice['start_cnf'])*50 - ($best_slice['start_cnf']-$j) );
+ }
+ for ($j=$best_slice['start_cnf']; $j<$best_slice['start_cnf']+$best_slice['len']; $j++ )
+ {
+ if ($mb_conf_db[ $cnf_keys[$j] ] > 0)
+ unset( $mb_conf_db[ $cnf_keys[$j] ] );
+ }
+ }
+ //var_export( $best_slice ); var_export($mb_conf); var_export($mb_conf_db);
+ // END OPTIM
+ */
+ $query = '
+UPDATE '.CONFIG_TABLE.'
+ SET value=\''.addslashes(serialize($mb_conf_db)).'\'
+ WHERE param=\'blk_'.addslashes($menu->get_id()).'\'
+ ';
+ pwg_query($query);
+
+ array_push($page['infos'], l10n('Order of menubar items has been updated successfully.'));
+}
+
+make_consecutive( $mb_conf );
+
+foreach ($mb_conf as $id => $pos )
+{
+ $template->append( 'blocks',
+ array(
+ 'pos' => $pos/5,
+ 'reg' => $reg_blocks[$id]
+ )
+ );
+}
+
+$action = get_root_url().'admin.php?page=menubar';
+$template->assign(array('F_ACTION'=>$action));
+
+$template->set_filename( 'menubar_admin_content', 'menubar.tpl' );
+$template->assign_var_from_handle( 'ADMIN_CONTENT', 'menubar_admin_content');
+?>
Index: /tags/2.1.0/admin/notification_by_mail.php
===================================================================
--- /tags/2.1.0/admin/notification_by_mail.php (revision 6217)
+++ /tags/2.1.0/admin/notification_by_mail.php (revision 6217)
@@ -0,0 +1,737 @@
+ 0)
+ {
+ $inserts = array();
+ $check_key_list = array();
+
+ while ($nbm_user = pwg_db_fetch_assoc($result))
+ {
+ // Calculate key
+ $nbm_user['check_key'] = find_available_check_key();
+
+ // Save key
+ array_push($check_key_list, $nbm_user['check_key']);
+
+ // Insert new nbm_users
+ array_push
+ (
+ $inserts,
+ array
+ (
+ 'user_id' => $nbm_user['user_id'],
+ 'check_key' => $nbm_user['check_key'],
+ 'enabled' => 'false' // By default if false, set to true with specific functions
+ )
+ );
+
+ array_push
+ (
+ $page['infos'],
+ sprintf(
+ l10n('User %s [%s] added.'),
+ stripslashes($nbm_user['username']),
+ get_email_address_as_display_text($nbm_user['mail_address'])
+ )
+ );
+ }
+
+ // Insert new nbm_users
+ mass_inserts(USER_MAIL_NOTIFICATION_TABLE, array('user_id', 'check_key', 'enabled'), $inserts);
+ // Update field enabled with specific function
+ $check_key_treated = do_subscribe_unsubscribe_notification_by_mail
+ (
+ true,
+ $conf['nbm_default_value_user_enabled'],
+ $check_key_list
+ );
+
+ // On timeout simulate like tabsheet send
+ if ($env_nbm['is_sendmail_timeout'])
+ {
+ $quoted_check_key_list = quote_check_key_list(array_diff($check_key_list, $check_key_treated));
+ if (count($quoted_check_key_list) != 0 )
+ {
+ $query = 'delete from '.USER_MAIL_NOTIFICATION_TABLE.' where check_key in ('.implode(",", $quoted_check_key_list).');';
+ $result = pwg_query($query);
+
+ redirect($base_url.get_query_string_diff(array(), false), l10n('Processing treatment.')."\n".l10n('Please wait...'));
+ }
+ }
+ }
+}
+
+/*
+ * Apply global functions to mail content
+ * return customize mail content rendered
+ */
+function render_global_customize_mail_content($customize_mail_content)
+{
+ global $conf;
+
+ if ($conf['nbm_send_html_mail'] and !(strpos($customize_mail_content, '<') === 0))
+ {
+ // On HTML mail, detects if the content are HTML format.
+ // If it's plain text format, convert content to readable HTML
+ return nl2br(htmlspecialchars($customize_mail_content));
+ }
+ else
+ {
+ return $customize_mail_content;
+ }
+}
+
+/*
+ * Send mail for notification to all users
+ * Return list of "selected" users for 'list_to_send'
+ * Return list of "treated" check_key for 'send'
+ */
+function do_action_send_mail_notification($action = 'list_to_send', $check_key_list = array(), $customize_mail_content = '')
+{
+ global $conf, $page, $user, $lang_info, $lang, $env_nbm;
+ $return_list = array();
+
+ if (in_array($action, array('list_to_send', 'send')))
+ {
+ list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();'));
+
+ $is_action_send = ($action == 'send');
+
+ // disabled and null mail_address are not selected in the list
+ $data_users = get_user_notifications('send', $check_key_list);
+
+ // List all if it's define on options or on timeout
+ $is_list_all_without_test = ($env_nbm['is_sendmail_timeout'] or $conf['nbm_list_all_enabled_users_to_send']);
+
+ // Check if exist news to list user or send mails
+ if ((!$is_list_all_without_test) or ($is_action_send))
+ {
+ if (count($data_users) > 0)
+ {
+ $datas = array();
+
+ if (!isset($customize_mail_content))
+ {
+ $customize_mail_content = $conf['nbm_complementary_mail_content'];
+ }
+
+ $customize_mail_content =
+ trigger_event('nbm_render_global_customize_mail_content', $customize_mail_content);
+
+
+ // Prepare message after change language
+ if ($is_action_send)
+ {
+ $msg_break_timeout = l10n('Time to send mail is limited. Others mails are skipped.');
+ }
+ else
+ {
+ $msg_break_timeout = l10n('Prepared time for list of users to send mail is limited. Others users are not listed.');
+ }
+
+ // Begin nbm users environment
+ begin_users_env_nbm($is_action_send);
+
+ foreach ($data_users as $nbm_user)
+ {
+ if ((!$is_action_send) and check_sendmail_timeout())
+ {
+ // Stop fill list on 'list_to_send', if the quota is override
+ array_push($page['infos'], $msg_break_timeout);
+ break;
+ }
+ if (($is_action_send) and check_sendmail_timeout())
+ {
+ // Stop fill list on 'send', if the quota is override
+ array_push($page['errors'], $msg_break_timeout);
+ break;
+ }
+
+ // set env nbm user
+ set_user_on_env_nbm($nbm_user, $is_action_send);
+
+ if ($is_action_send)
+ {
+ set_make_full_url();
+ // Fill return list of "treated" check_key for 'send'
+ array_push($return_list, $nbm_user['check_key']);
+
+ if ($conf['nbm_send_detailed_content'])
+ {
+ $news = news($nbm_user['last_send'], $dbnow, false, $conf['nbm_send_html_mail']);
+ $exist_data = count($news) > 0;
+ }
+ else
+ {
+ $exist_data = news_exists($nbm_user['last_send'], $dbnow);
+ }
+
+ if ($exist_data)
+ {
+ $subject = '['.$conf['gallery_title'].']: '.l10n('New elements added');
+
+ // Assign current var for nbm mail
+ assign_vars_nbm_mail_content($nbm_user);
+
+ if (!is_null($nbm_user['last_send']))
+ {
+ $env_nbm['mail_template']->assign
+ (
+ 'content_new_elements_between',
+ array
+ (
+ 'DATE_BETWEEN_1' => $nbm_user['last_send'],
+ 'DATE_BETWEEN_2' => $dbnow,
+ )
+ );
+ }
+ else
+ {
+ $env_nbm['mail_template']->assign
+ (
+ 'content_new_elements_single',
+ array
+ (
+ 'DATE_SINGLE' => $dbnow,
+ )
+ );
+ }
+
+ if ($conf['nbm_send_detailed_content'])
+ {
+ $env_nbm['mail_template']->assign('global_new_lines', $news);
+ }
+
+ $nbm_user_customize_mail_content =
+ trigger_event('nbm_render_user_customize_mail_content',
+ $customize_mail_content, $nbm_user);
+ if (!empty($nbm_user_customize_mail_content))
+ {
+ $env_nbm['mail_template']->assign
+ (
+ 'custom_mail_content', $nbm_user_customize_mail_content
+ );
+ }
+
+ if ($conf['nbm_send_html_mail'] and $conf['nbm_send_recent_post_dates'])
+ {
+ $recent_post_dates = get_recent_post_dates_array(
+ $conf['recent_post_dates']['NBM']);
+ foreach ($recent_post_dates as $date_detail)
+ {
+ $env_nbm['mail_template']->append
+ (
+ 'recent_posts',
+ array
+ (
+ 'TITLE' => get_title_recent_post_date($date_detail),
+ 'HTML_DATA' => get_html_description_recent_post_date($date_detail)
+ )
+ );
+ }
+ }
+
+ $env_nbm['mail_template']->assign
+ (
+ array
+ (
+ 'GOTO_GALLERY_TITLE' => $conf['gallery_title'],
+ 'GOTO_GALLERY_URL' => $conf['gallery_url'],
+ 'SEND_AS_NAME' => $env_nbm['send_as_name'],
+ )
+ );
+
+ if (pwg_mail
+ (
+ format_email(stripslashes($nbm_user['username']), $nbm_user['mail_address']),
+ array
+ (
+ 'from' => $env_nbm['send_as_mail_formated'],
+ 'subject' => $subject,
+ 'email_format' => $env_nbm['email_format'],
+ 'content' => $env_nbm['mail_template']->parse('notification_by_mail', true),
+ 'content_format' => $env_nbm['email_format'],
+ 'theme' => $nbm_user['theme']
+ )
+ ))
+ {
+ inc_mail_sent_success($nbm_user);
+
+ $data = array('user_id' => $nbm_user['user_id'],
+ 'last_send' => $dbnow);
+ array_push($datas, $data);
+ }
+ else
+ {
+ inc_mail_sent_failed($nbm_user);
+ }
+
+ unset_make_full_url();
+ }
+ }
+ else
+ {
+ if (news_exists($nbm_user['last_send'], $dbnow))
+ {
+ // Fill return list of "selected" users for 'list_to_send'
+ array_push($return_list, $nbm_user);
+ }
+ }
+
+ // unset env nbm user
+ unset_user_on_env_nbm();
+ }
+
+ // Restore nbm environment
+ end_users_env_nbm();
+
+ if ($is_action_send)
+ {
+ mass_updates(
+ USER_MAIL_NOTIFICATION_TABLE,
+ array(
+ 'primary' => array('user_id'),
+ 'update' => array('last_send')
+ ),
+ $datas
+ );
+
+ display_counter_info();
+ }
+ }
+ else
+ {
+ if ($is_action_send)
+ {
+ array_push($page['errors'], l10n('No user to send notifications by mail.'));
+ }
+ }
+ }
+ else
+ {
+ // Quick List, don't check news
+ // Fill return list of "selected" users for 'list_to_send'
+ $return_list = $data_users;
+ }
+ }
+
+ // Return list of "selected" users for 'list_to_send'
+ // Return list of "treated" check_key for 'send'
+ return $return_list;
+}
+
+// +-----------------------------------------------------------------------+
+// | Main |
+// +-----------------------------------------------------------------------+
+if (!isset($_GET['mode']))
+{
+ $page['mode'] = 'send';
+}
+else
+{
+ $page['mode'] = $_GET['mode'];
+}
+
+// +-----------------------------------------------------------------------+
+// | Check Access and exit when user status is not ok |
+// +-----------------------------------------------------------------------+
+check_status(get_tab_status($page['mode']));
+
+
+// +-----------------------------------------------------------------------+
+// | Add event handler |
+// +-----------------------------------------------------------------------+
+add_event_handler('nbm_render_global_customize_mail_content', 'render_global_customize_mail_content');
+trigger_action('nbm_event_handler_added');
+
+
+// +-----------------------------------------------------------------------+
+// | Insert new users with mails |
+// +-----------------------------------------------------------------------+
+if (!isset($_POST) or (count($_POST) ==0))
+{
+ // No insert data in post mode
+ insert_new_data_user_mail_notification();
+}
+
+// +-----------------------------------------------------------------------+
+// | Treatment of tab post |
+// +-----------------------------------------------------------------------+
+switch ($page['mode'])
+{
+ case 'param' :
+ {
+ if (isset($_POST['param_submit']) and !is_adviser())
+ {
+ $updated_param_count = 0;
+ // Update param
+ $result = pwg_query('select param, value from '.CONFIG_TABLE.' where param like \'nbm\\_%\'');
+ while ($nbm_user = pwg_db_fetch_assoc($result))
+ {
+ if (isset($_POST[$nbm_user['param']]))
+ {
+ $value = $_POST[$nbm_user['param']];
+
+ $query = '
+update
+'.CONFIG_TABLE.'
+set
+ value = \''. str_replace("\'", "''", $value).'\'
+where
+ param = \''.$nbm_user['param'].'\';';
+ pwg_query($query);
+ $updated_param_count += 1;
+ }
+ }
+
+ array_push($page['infos'],
+ l10n_dec('%d parameter was updated.', '%d parameters were updated.',
+ $updated_param_count));
+
+ // Reload conf with new values
+ load_conf_from_db('param like \'nbm\\_%\'');
+ }
+ }
+ case 'subscribe' :
+ {
+ if (!is_adviser())
+ {
+ if (isset($_POST['falsify']) and isset($_POST['cat_true']))
+ {
+ $check_key_treated = unsubscribe_notification_by_mail(true, $_POST['cat_true']);
+ do_timeout_treatment('cat_true', $check_key_treated);
+ }
+ else
+ if (isset($_POST['trueify']) and isset($_POST['cat_false']))
+ {
+ $check_key_treated = subscribe_notification_by_mail(true, $_POST['cat_false']);
+ do_timeout_treatment('cat_false', $check_key_treated);
+ }
+ }
+ break;
+ }
+
+ case 'send' :
+ {
+ if (isset($_POST['send_submit']) and isset($_POST['send_selection']) and isset($_POST['send_customize_mail_content']) and !is_adviser())
+ {
+ $check_key_treated = do_action_send_mail_notification('send', $_POST['send_selection'], stripslashes($_POST['send_customize_mail_content']));
+ do_timeout_treatment('send_selection', $check_key_treated);
+ }
+ }
+}
+
+// +-----------------------------------------------------------------------+
+// | template initialization |
+// +-----------------------------------------------------------------------+
+$template->set_filenames
+(
+ array
+ (
+ 'double_select' => 'double_select.tpl',
+ 'notification_by_mail'=>'notification_by_mail.tpl'
+ )
+);
+
+$template->assign
+(
+ array
+ (
+ 'U_HELP' => get_root_url().'admin/popuphelp.php?page=notification_by_mail',
+ 'F_ACTION'=> $base_url.get_query_string_diff(array())
+ )
+);
+
+if (is_autorize_status(ACCESS_WEBMASTER))
+{
+ // TabSheet
+ $tabsheet = new tabsheet();
+ // TabSheet initialization
+ $tabsheet->add('param', l10n('Parameter'),
+ add_url_params($base_url.get_query_string_diff(array('mode', 'select')),
+ array('mode' => 'param')));
+ $tabsheet->add('subscribe', l10n('Subscribe'),
+ add_url_params($base_url.get_query_string_diff(array('mode', 'select')),
+ array('mode' => 'subscribe')));
+ $tabsheet->add('send', l10n('Send'),
+ add_url_params($base_url.get_query_string_diff(array('mode', 'select')),
+ array('mode' => 'send')));
+ // TabSheet selection
+ $tabsheet->select($page['mode']);
+ // Assign tabsheet to template
+ $tabsheet->assign();
+}
+
+if ($must_repost)
+{
+ // Get name of submit button
+ $repost_submit_name = '';
+ if (isset($_POST['falsify']))
+ {
+ $repost_submit_name = 'falsify';
+ }
+ elseif (isset($_POST['trueify']))
+ {
+ $repost_submit_name = 'trueify';
+ }
+ elseif (isset($_POST['send_submit']))
+ {
+ $repost_submit_name = 'send_submit';
+ }
+
+ $template->assign('REPOST_SUBMIT_NAME', $repost_submit_name);
+}
+
+switch ($page['mode'])
+{
+ case 'param' :
+ {
+ $template->assign(
+ $page['mode'],
+ array(
+ 'SEND_HTML_MAIL' => $conf['nbm_send_html_mail'],
+ 'SEND_MAIL_AS' => $conf['nbm_send_mail_as'],
+ 'SEND_DETAILED_CONTENT' => $conf['nbm_send_detailed_content'],
+ 'COMPLEMENTARY_MAIL_CONTENT' => $conf['nbm_complementary_mail_content'],
+ 'SEND_RECENT_POST_DATES' => $conf['nbm_send_recent_post_dates'],
+ ));
+ break;
+ }
+
+ case 'subscribe' :
+ {
+ $template->assign( $page['mode'], true );
+
+ $template->assign(
+ array(
+ 'L_CAT_OPTIONS_TRUE' => l10n('Subscribed'),
+ 'L_CAT_OPTIONS_FALSE' => l10n('Unsubscribed')
+ )
+ );
+
+ $data_users = get_user_notifications('subscribe');
+
+ $opt_true = array();
+ $opt_true_selected = array();
+ $opt_false = array();
+ $opt_false_selected = array();
+ foreach ($data_users as $nbm_user)
+ {
+ if (get_boolean($nbm_user['enabled']))
+ {
+ $opt_true[ $nbm_user['check_key'] ] = stripslashes($nbm_user['username']).'['.get_email_address_as_display_text($nbm_user['mail_address']).']';
+ if ((isset($_POST['falsify']) and isset($_POST['cat_true']) and in_array($nbm_user['check_key'], $_POST['cat_true'])))
+ {
+ $opt_true_selected[] = $nbm_user['check_key'];
+ }
+ }
+ else
+ {
+ $opt_false[ $nbm_user['check_key'] ] = stripslashes($nbm_user['username']).'['.get_email_address_as_display_text($nbm_user['mail_address']).']';
+ if (isset($_POST['trueify']) and isset($_POST['cat_false']) and in_array($nbm_user['check_key'], $_POST['cat_false']))
+ {
+ $opt_false_selected[] = $nbm_user['check_key'];
+ }
+ }
+ }
+ $template->assign( array(
+ 'category_option_true' => $opt_true,
+ 'category_option_true_selected' => $opt_true_selected,
+ 'category_option_false' => $opt_false,
+ 'category_option_false_selected' => $opt_false_selected,
+ )
+ );
+ $template->assign_var_from_handle('DOUBLE_SELECT', 'double_select');
+ break;
+ }
+
+ case 'send' :
+ {
+ $tpl_var = array('users'=> array() );
+
+ $data_users = do_action_send_mail_notification('list_to_send');
+
+ $tpl_var['CUSTOMIZE_MAIL_CONTENT'] =
+ isset($_POST['send_customize_mail_content'])
+ ? stripslashes($_POST['send_customize_mail_content'])
+ : $conf['nbm_complementary_mail_content'];
+
+ if (count($data_users))
+ {
+ foreach ($data_users as $nbm_user)
+ {
+ if (
+ (!$must_repost) or // Not timeout, normal treatment
+ (($must_repost) and in_array($nbm_user['check_key'], $_POST['send_selection'])) // Must be repost, show only user to send
+ )
+ {
+ $tpl_var['users'][] =
+ array(
+ 'ID' => $nbm_user['check_key'],
+ 'CHECKED' => ( // not check if not selected, on init select stripslashes($nbm_user['username']),
+ 'EMAIL' => get_email_address_as_display_text($nbm_user['mail_address']),
+ 'LAST_SEND'=> $nbm_user['last_send']
+ );
+ }
+ }
+ }
+ $template->assign($page['mode'], $tpl_var);
+ break;
+ }
+}
+
+// +-----------------------------------------------------------------------+
+// | Sending html code |
+// +-----------------------------------------------------------------------+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'notification_by_mail');
+
+?>
Index: /tags/2.1.0/admin/permalinks.php
===================================================================
--- /tags/2.1.0/admin/permalinks.php (revision 6217)
+++ /tags/2.1.0/admin/permalinks.php (revision 6217)
@@ -0,0 +1,179 @@
+ $value)
+ {
+ if (!in_array($key, $get_rejects) and $key!=$get_param)
+ {
+ $base_url .= $is_first ? '?' : '&';
+ $is_first = false;
+ $base_url .= $key.'='.urlencode($value);
+ }
+ }
+
+ $ret = array();
+ foreach( $sortable_by as $field)
+ {
+ $url = $base_url;
+ $disp = '⇓'; // TODO: an small image is better
+
+ if ( $field !== @$_GET[$get_param] )
+ {
+ if ( !isset($default_field) or $default_field!=$field )
+ { // the first should be the default
+ $url = add_url_params($url, array($get_param=>$field) );
+ }
+ elseif (isset($default_field) and !isset($_GET[$get_param]) )
+ {
+ array_push($ret, $field);
+ $disp = ''.$disp.'';
+ }
+ }
+ else
+ {
+ array_push($ret, $field);
+ $disp = ''.$disp.'';
+ }
+ if ( isset($template_var) )
+ {
+ $template->assign( $template_var.strtoupper($field),
+ ''.$disp.''
+ );
+ }
+ }
+ return $ret;
+}
+
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+include_once(PHPWG_ROOT_PATH.'admin/include/functions_permalinks.php');
+
+$selected_cat = array();
+if ( isset($_POST['set_permalink']) and $_POST['cat_id']>0 and !is_adviser() )
+{
+ $permalink = $_POST['permalink'];
+ if ( empty($permalink) )
+ delete_cat_permalink($_POST['cat_id'], isset($_POST['save']) );
+ else
+ set_cat_permalink($_POST['cat_id'], $permalink, isset($_POST['save']) );
+ $selected_cat = array( $_POST['cat_id'] );
+}
+elseif ( isset($_GET['delete_permanent']) and !is_adviser() )
+{
+ $query = '
+DELETE FROM '.OLD_PERMALINKS_TABLE.'
+ WHERE permalink="'.$_GET['delete_permanent'].'"
+ LIMIT 1';
+ $result = pwg_query($query);
+ if (pwg_db_changes($result)==0)
+ array_push($page['errors'], l10n('Cannot delete the old permalink !'));
+}
+
+
+$template->set_filename('permalinks', 'permalinks.tpl' );
+
+$query = '
+SELECT
+ id, permalink,
+ '.pwg_db_concat(array('id', '\' - \'', 'name')).' AS name,
+ uppercats, global_rank
+FROM '.CATEGORIES_TABLE;
+
+display_select_cat_wrapper( $query, $selected_cat, 'categories', false );
+
+
+// --- generate display of active permalinks -----------------------------------
+$sort_by = parse_sort_variables(
+ array('id', 'name', 'permalink'), 'name',
+ 'psf',
+ array('delete_permanent'),
+ 'SORT_' );
+
+$query = '
+SELECT id, permalink, uppercats, global_rank
+ FROM '.CATEGORIES_TABLE.'
+ WHERE permalink IS NOT NULL
+';
+if ( $sort_by[0]=='id' or $sort_by[0]=='permalink' )
+{
+ $query .= ' ORDER BY '.$sort_by[0];
+}
+$categories=array();
+$result=pwg_query($query);
+while ( $row = pwg_db_fetch_assoc($result) )
+{
+ $row['name'] = get_cat_display_name_cache( $row['uppercats'] );
+ $categories[] = $row;
+}
+
+if ( $sort_by[0]=='name')
+{
+ usort($categories, 'global_rank_compare');
+}
+$template->assign( 'permalinks', $categories );
+
+// --- generate display of old permalinks --------------------------------------
+
+$sort_by = parse_sort_variables(
+ array('cat_id','permalink','date_deleted','last_hit','hit'), null,
+ 'dpsf',
+ array('delete_permanent'),
+ 'SORT_OLD_', '#old_permalinks' );
+
+$url_del_base = get_root_url().'admin.php?page=permalinks';
+$query = 'SELECT * FROM '.OLD_PERMALINKS_TABLE;
+if ( count($sort_by) )
+{
+ $query .= ' ORDER BY '.$sort_by[0];
+}
+$result = pwg_query($query);
+$deleted_permalinks=array();
+while ( $row = pwg_db_fetch_assoc($result) )
+{
+ $row['name'] = get_cat_display_name_cache($row['cat_id']);
+ $row['U_DELETE'] =
+ add_url_params(
+ $url_del_base,
+ array( 'delete_permanent'=> $row['permalink'] )
+ );
+ $deleted_permalinks[] = $row;
+}
+$template->assign('deleted_permalinks', $deleted_permalinks);
+$template->assign('U_HELP', get_root_url().'admin/popuphelp.php?page=permalinks');
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'permalinks');
+?>
Index: /tags/2.1.0/admin/photos_add.php
===================================================================
--- /tags/2.1.0/admin/photos_add.php (revision 6217)
+++ /tags/2.1.0/admin/photos_add.php (revision 6217)
@@ -0,0 +1,207 @@
+ array(
+ 'default' => true,
+ 'can_be_null' => false,
+ ),
+
+ 'websize_maxwidth' => array(
+ 'default' => 800,
+ 'min' => 100,
+ 'max' => 1600,
+ 'pattern' => '/^\d+$/',
+ 'can_be_null' => true,
+ 'error_message' => l10n('The websize maximum width must be a number between %d and %d'),
+ ),
+
+ 'websize_maxheight' => array(
+ 'default' => 600,
+ 'min' => 100,
+ 'max' => 1200,
+ 'pattern' => '/^\d+$/',
+ 'can_be_null' => true,
+ 'error_message' => l10n('The websize maximum height must be a number between %d and %d'),
+ ),
+
+ 'websize_quality' => array(
+ 'default' => 95,
+ 'min' => 50,
+ 'max' => 100,
+ 'pattern' => '/^\d+$/',
+ 'can_be_null' => false,
+ 'error_message' => l10n('The websize image quality must be a number between %d and %d'),
+ ),
+
+ 'thumb_maxwidth' => array(
+ 'default' => 128,
+ 'min' => 50,
+ 'max' => 300,
+ 'pattern' => '/^\d+$/',
+ 'can_be_null' => false,
+ 'error_message' => l10n('The thumbnail maximum width must be a number between %d and %d'),
+ ),
+
+ 'thumb_maxheight' => array(
+ 'default' => 96,
+ 'min' => 50,
+ 'max' => 300,
+ 'pattern' => '/^\d+$/',
+ 'can_be_null' => false,
+ 'error_message' => l10n('The thumbnail maximum height must be a number between %d and %d'),
+ ),
+
+ 'thumb_quality' => array(
+ 'default' => 95,
+ 'min' => 50,
+ 'max' => 100,
+ 'pattern' => '/^\d+$/',
+ 'can_be_null' => false,
+ 'error_message' => l10n('The thumbnail image quality must be a number between %d and %d'),
+ ),
+ );
+
+$inserts = array();
+
+foreach ($upload_form_config as $param_shortname => $param)
+{
+ $param_name = 'upload_form_'.$param_shortname;
+
+ if (!isset($conf[$param_name]))
+ {
+ $param_value = boolean_to_string($param['default']);
+
+ array_push(
+ $inserts,
+ array(
+ 'param' => $param_name,
+ 'value' => $param_value,
+ )
+ );
+ $conf[$param_name] = $param_value;
+ }
+}
+
+if (count($inserts) > 0)
+{
+ mass_inserts(
+ CONFIG_TABLE,
+ array_keys($inserts[0]),
+ $inserts
+ );
+}
+
+// +-----------------------------------------------------------------------+
+// | Tabs |
+// +-----------------------------------------------------------------------+
+
+$tabs = array(
+ array(
+ 'code' => 'direct',
+ 'label' => l10n('Upload Photos'),
+ ),
+ array(
+ 'code' => 'settings',
+ 'label' => l10n('Settings'),
+ ),
+ array(
+ 'code' => 'ploader',
+ 'label' => l10n('Piwigo Uploader'),
+ ),
+ array(
+ 'code' => 'ftp',
+ 'label' => l10n('FTP + Synchronization'),
+ ),
+ );
+
+$tab_codes = array_map(
+ create_function('$a', 'return $a["code"];'),
+ $tabs
+ );
+
+if (isset($_GET['section']) and in_array($_GET['section'], $tab_codes))
+{
+ $page['tab'] = $_GET['section'];
+}
+else
+{
+ $page['tab'] = $tabs[0]['code'];
+}
+
+$tabsheet = new tabsheet();
+foreach ($tabs as $tab)
+{
+ $tabsheet->add(
+ $tab['code'],
+ $tab['label'],
+ PHOTOS_ADD_BASE_URL.'§ion='.$tab['code']
+ );
+}
+$tabsheet->select($page['tab']);
+$tabsheet->assign();
+
+// +-----------------------------------------------------------------------+
+// | template init |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(
+ array(
+ 'photos_add' => 'photos_add_'.$page['tab'].'.tpl'
+ )
+ );
+
+// $template->append(
+// 'head_elements',
+// ''."\n"
+// );
+
+// +-----------------------------------------------------------------------+
+// | Load the tab |
+// +-----------------------------------------------------------------------+
+
+include(PHPWG_ROOT_PATH.'admin/photos_add_'.$page['tab'].'.php');
+?>
Index: /tags/2.1.0/admin/photos_add_direct.php
===================================================================
--- /tags/2.1.0/admin/photos_add_direct.php (revision 6217)
+++ /tags/2.1.0/admin/photos_add_direct.php (revision 6217)
@@ -0,0 +1,464 @@
+ $user['id'],
+ 'element_id' => $image_id,
+ )
+ );
+ }
+ mass_inserts(
+ CADDIE_TABLE,
+ array_keys($inserts[0]),
+ $inserts
+ );
+
+ redirect(get_root_url().'admin.php?page=element_set&cat=caddie');
+}
+
+// +-----------------------------------------------------------------------+
+// | process form |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST['submit_upload']))
+{
+// echo '