diff options
Diffstat (limited to 'BSF/admin')
53 files changed, 21588 insertions, 0 deletions
diff --git a/BSF/admin/advanced_feature.php b/BSF/admin/advanced_feature.php new file mode 100644 index 000000000..da3452e84 --- /dev/null +++ b/BSF/admin/advanced_feature.php @@ -0,0 +1,107 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die ("Hacking attempt!"); +} + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | Actions | +// +-----------------------------------------------------------------------+ + +/*$action = (isset($_GET['action']) and !is_adviser()) ? $_GET['action'] : ''; + +switch ($action) +{ + case '???' : + { + break; + } + default : + { + break; + } +}*/ + +// +-----------------------------------------------------------------------+ +// | Define advanced features | +// +-----------------------------------------------------------------------+ + +$advanced_features = array(); + +// Add advanced features +/*array_push($advanced_features, + array + ( + 'CAPTION' => l10n('???'), + 'URL' => $start_url.'???' + ));*/ + +array_push($advanced_features, + array + ( + 'CAPTION' => l10n('Elements_not_linked'), + 'URL' => get_root_url().'admin.php?page=element_set&cat=not_linked' + )); + +array_push($advanced_features, + array + ( + 'CAPTION' => l10n('Duplicates'), + '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 init | +// +-----------------------------------------------------------------------+ + +$template->set_filename('advanced_feature', 'admin/advanced_feature.tpl'); + +$start_url = get_root_url().'admin.php?page=advanced_feature&action='; + +$template->assign( + array + ( + 'U_HELP' => get_root_url().'popuphelp.php?page=advanced_feature' + )); + +// advanced_features +$template->assign('advanced_features', $advanced_features); + +// +-----------------------------------------------------------------------+ +// | Sending html code | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('ADMIN_CONTENT', 'advanced_feature'); + +?> diff --git a/BSF/admin/cat_list.php b/BSF/admin/cat_list.php new file mode 100644 index 000000000..b8407c2f8 --- /dev/null +++ b/BSF/admin/cat_list.php @@ -0,0 +1,253 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die('Hacking attempt!'); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | functions | +// +-----------------------------------------------------------------------+ + +/** + * save the rank depending on given categories order + * + * The list of ordered categories id is supposed to be in the same parent + * category + * + * @param array categories + * @return void + */ +function save_categories_order($categories) +{ + $current_rank = 0; + $datas = array(); + foreach ($categories as $id) + { + array_push($datas, array('id' => $id, 'rank' => ++$current_rank)); + } + $fields = array('primary' => array('id'), 'update' => array('rank')); + mass_updates(CATEGORIES_TABLE, $fields, $datas); + + update_global_rank(); +} + +// +-----------------------------------------------------------------------+ +// | initialization | +// +-----------------------------------------------------------------------+ + +$categories = array(); + +$base_url = get_root_url().'admin.php?page=cat_list'; +$navigation = '<a href="'.$base_url.'">'; +$navigation.= l10n('home'); +$navigation.= '</a>'; + +// +-----------------------------------------------------------------------+ +// | virtual categories management | +// +-----------------------------------------------------------------------+ +// request to delete a virtual category / not for an adviser +if (isset($_GET['delete']) and is_numeric($_GET['delete']) and !is_adviser()) +{ + delete_categories(array($_GET['delete'])); + array_push($page['infos'], l10n('cat_virtual_deleted')); + update_global_rank(); +} +// request to add a virtual category +else if (isset($_POST['submitAdd'])) +{ + $output_create = create_virtual_category( + $_POST['virtual_name'], + @$_GET['parent_id'] + ); + + if (isset($output_create['error'])) + { + array_push($page['errors'], $output_create['error']); + } + else + { + array_push($page['infos'], $output_create['info']); + } +} +// save manual category ordering +else if (isset($_POST['submitOrder'])) +{ + asort($_POST['catOrd'], SORT_NUMERIC); + save_categories_order(array_keys($_POST['catOrd'])); + + array_push( + $page['infos'], + l10n('Categories manual order was saved') + ); +} +// sort categories alpha-numerically +else if (isset($_POST['submitOrderAlphaNum'])) +{ + $query = ' +SELECT id, name + FROM '.CATEGORIES_TABLE.' + WHERE id_uppercat '. + (!isset($_GET['parent_id']) ? 'IS NULL' : '= '.$_GET['parent_id']).' +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $categories[ $row['id'] ] = strtolower($row['name']); + } + + asort($categories, SORT_REGULAR); + save_categories_order(array_keys($categories)); + + array_push( + $page['infos'], + l10n('Categories ordered alphanumerically') + ); +} + +// +-----------------------------------------------------------------------+ +// | Navigation path | +// +-----------------------------------------------------------------------+ + +if (isset($_GET['parent_id'])) +{ + $navigation.= $conf['level_separator']; + + $navigation.= get_cat_display_name_from_id( + $_GET['parent_id'], + $base_url.'&parent_id=', + false + ); +} +// +-----------------------------------------------------------------------+ +// | template initialization | +// +-----------------------------------------------------------------------+ +$template->set_filename('categories', 'admin/cat_list.tpl'); + +$form_action = PHPWG_ROOT_PATH.'admin.php?page=cat_list'; +if (isset($_GET['parent_id'])) +{ + $form_action.= '&parent_id='.$_GET['parent_id']; +} + +$template->assign(array( + 'CATEGORIES_NAV'=>$navigation, + 'F_ACTION'=>$form_action, + )); + +// +-----------------------------------------------------------------------+ +// | Categories display | +// +-----------------------------------------------------------------------+ + +$categories = array(); + +$query = ' +SELECT id, name, permalink, dir, rank, status + FROM '.CATEGORIES_TABLE; +if (!isset($_GET['parent_id'])) +{ + $query.= ' + WHERE id_uppercat IS NULL'; +} +else +{ + $query.= ' + WHERE id_uppercat = '.$_GET['parent_id']; +} +$query.= ' + ORDER BY rank ASC +;'; +$categories = hash_from_query($query, 'id'); + +// get the categories containing images directly +$categories_with_images = array(); +if ( count($categories) ) +{ + $query = ' +SELECT DISTINCT category_id + FROM '.IMAGE_CATEGORY_TABLE.' + WHERE category_id IN ('.implode(',', array_keys($categories)).')'; + $categories_with_images = array_flip( array_from_query($query, 'category_id') ); +} + +$template->assign('categories', array()); +$base_url = get_root_url().'admin.php?page='; +foreach ($categories as $category) +{ + $cat_list_url = $base_url.'cat_list'; + + $self_url = $cat_list_url; + if (isset($_GET['parent_id'])) + { + $self_url.= '&parent_id='.$_GET['parent_id']; + } + + $tpl_cat = + array( + 'NAME' => $category['name'], + 'ID' => $category['id'], + 'RANK' => $category['rank']*10, + + 'U_JUMPTO' => make_index_url( + array( + 'category' => $category + ) + ), + + 'U_CHILDREN' => $cat_list_url.'&parent_id='.$category['id'], + 'U_EDIT' => $base_url.'cat_modify&cat_id='.$category['id'], + + 'IS_VIRTUAL' => empty($category['dir']) + ); + + if (empty($category['dir'])) + { + $tpl_cat['U_DELETE'] = $self_url.'&delete='.$category['id']; + } + + if ( array_key_exists($category['id'], $categories_with_images) ) + { + $tpl_cat['U_MANAGE_ELEMENTS']= + $base_url.'element_set&cat='.$category['id']; + } + + if ('private' == $category['status']) + { + $tpl_cat['U_MANAGE_PERMISSIONS']= + $base_url.'cat_perm&cat='.$category['id']; + } + $template->append('categories', $tpl_cat); +} +// +-----------------------------------------------------------------------+ +// | sending html code | +// +-----------------------------------------------------------------------+ +$template->assign_var_from_handle('ADMIN_CONTENT', 'categories'); +?> diff --git a/BSF/admin/cat_modify.php b/BSF/admin/cat_modify.php new file mode 100644 index 000000000..90310527f --- /dev/null +++ b/BSF/admin/cat_modify.php @@ -0,0 +1,553 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die('Hacking attempt!'); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); +include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +//---------------------------------------------------------------- verification +if ( !isset( $_GET['cat_id'] ) || !is_numeric( $_GET['cat_id'] ) ) +{ + $_GET['cat_id'] = '-1'; +} + +//--------------------------------------------------------- form criteria check +if (isset($_POST['submit'])) +{ + $data = + array( + 'id' => $_GET['cat_id'], + 'name' => @$_POST['name'], + 'commentable' => $_POST['commentable'], + 'uploadable' => + isset($_POST['uploadable']) ? $_POST['uploadable'] : 'false', + 'comment' => + $conf['allow_html_descriptions'] ? + @$_POST['comment'] : strip_tags(@$_POST['comment']) + ); + + mass_updates( + CATEGORIES_TABLE, + array( + 'primary' => array('id'), + 'update' => array_diff(array_keys($data), array('id')) + ), + array($data) + ); + + set_cat_visible(array($_GET['cat_id']), $_POST['visible']); + set_cat_status(array($_GET['cat_id']), $_POST['status']); + + if (isset($_POST['parent'])) + { + move_categories( + array($_GET['cat_id']), + $_POST['parent'] + ); + } + + $image_order = ''; + if ( !isset($_POST['image_order_default']) ) + { + for ($i=1; $i<=3; $i++) + { + if ( !empty($_POST['order_field_'.$i]) ) + { + if (! empty($image_order) ) + { + $image_order .= ','; + } + $image_order .= $_POST['order_field_'.$i]; + if ($_POST['order_direction_'.$i]=='DESC') + { + $image_order .= ' DESC'; + } + } + } + } + $image_order = empty($image_order) ? 'null' : "'$image_order'"; + $query = ' +UPDATE '.CATEGORIES_TABLE.' SET image_order='.$image_order.' +WHERE '; + if (isset($_POST['image_order_subcats'])) + { + $query .= 'uppercats REGEXP \'(^|,)'.$_GET['cat_id'].'(,|$)\''; + } + else + { + $query .= 'id='.$_GET['cat_id'].';'; + } + pwg_query($query); + + array_push($page['infos'], l10n('editcat_confirm')); +} +else if (isset($_POST['set_random_representant'])) +{ + set_random_representant(array($_GET['cat_id'])); +} +else if (isset($_POST['delete_representant'])) +{ + $query = ' +UPDATE '.CATEGORIES_TABLE.' + SET representative_picture_id = NULL + WHERE id = '.$_GET['cat_id'].' +;'; + pwg_query($query); +} +else if (isset($_POST['submitAdd'])) +{ + $output_create = create_virtual_category( + $_POST['virtual_name'], + (0 == $_POST['parent'] ? null : $_POST['parent']) + ); + + if (isset($output_create['error'])) + { + array_push($page['errors'], $output_create['error']); + } + else + { + // Virtual category creation succeeded + // + // Add the information in the information list + array_push($page['infos'], $output_create['info']); + + // Link the new category to the current category + associate_categories_to_categories( + array($_GET['cat_id']), + array($output_create['id']) + ); + + // information + array_push( + $page['infos'], + sprintf( + l10n('Category elements associated to the following categories: %s'), + '<ul><li>' + .get_cat_display_name_from_id($output_create['id']) + .'</li></ul>' + ) + ); + } +} +else if (isset($_POST['submitDestinations']) + and isset($_POST['destinations']) + and count($_POST['destinations']) > 0) +{ + associate_categories_to_categories( + array($_GET['cat_id']), + $_POST['destinations'] + ); + + $category_names = array(); + foreach ($_POST['destinations'] as $category_id) + { + array_push( + $category_names, + get_cat_display_name_from_id($category_id) + ); + } + + array_push( + $page['infos'], + sprintf( + l10n('Category elements associated to the following categories: %s'), + '<ul><li>'.implode('</li><li>', $category_names).'</li></ul>' + ) + ); +} + +$query = ' +SELECT * + FROM '.CATEGORIES_TABLE.' + WHERE id = '.$_GET['cat_id'].' +;'; +$category = mysql_fetch_array( pwg_query( $query ) ); +// nullable fields +foreach (array('comment','dir','site_id', 'id_uppercat') as $nullable) +{ + if (!isset($category[$nullable])) + { + $category[$nullable] = ''; + } +} + +$category['is_virtual'] = empty($category['dir']) ? true : false; + +$query = 'SELECT DISTINCT category_id + FROM '.IMAGE_CATEGORY_TABLE.' + WHERE category_id = '.$_GET['cat_id'].' + LIMIT 1'; +$result = pwg_query($query); +$category['has_images'] = mysql_num_rows($result)>0 ? true : false; + +// Navigation path +$navigation = get_cat_display_name_cache( + $category['uppercats'], + get_root_url().'admin.php?page=cat_modify&cat_id=' + ); + +$form_action = get_root_url().'admin.php?page=cat_modify&cat_id='.$_GET['cat_id']; + +//----------------------------------------------------- template initialization +$template->set_filename( 'categories', 'admin/cat_modify.tpl'); + +$base_url = get_root_url().'admin.php?page='; +$cat_list_url = $base_url.'cat_list'; + +$self_url = $cat_list_url; +if (!empty($category['id_uppercat'])) +{ + $self_url.= '&parent_id='.$category['id_uppercat']; +} + +$template->assign( + array( + 'CATEGORIES_NAV' => $navigation, + 'CAT_NAME' => @htmlspecialchars($category['name']), + 'CAT_COMMENT' => @htmlspecialchars($category['comment']), + + 'status_values' => array('public','private'), + + 'CAT_STATUS' => $category['status'], + 'CAT_VISIBLE' => $category['visible'], + 'CAT_COMMENTABLE' => $category['commentable'], + 'CAT_UPLOADABLE' => $category['uploadable'], + + 'IMG_ORDER_DEFAULT' => empty($category['image_order']) ? + 'checked="checked"' : '', + + 'U_JUMPTO' => make_index_url( + array( + 'category' => $category + ) + ), + + 'MAIL_CONTENT' => empty($_POST['mail_content']) + ? '' : stripslashes($_POST['mail_content']), + 'U_CHILDREN' => $cat_list_url.'&parent_id='.$category['id'], + 'U_HELP' => get_root_url().'popuphelp.php?page=cat_modify', + + 'F_ACTION' => $form_action, + ) + ); + + +if ('private' == $category['status']) +{ + $template->assign( 'U_MANAGE_PERMISSIONS', + $base_url.'cat_perm&cat='.$category['id'] + ); +} + +// manage category elements link +if ($category['has_images']) +{ + $template->assign( 'U_MANAGE_ELEMENTS', + $base_url.'element_set&cat='.$category['id'] + ); +} + +if ($category['is_virtual']) +{ + $template->assign( + array( + 'U_DELETE' => $self_url.'&delete='.$category['id'], + ) + ); +} +else +{ + $category['cat_full_dir'] = get_complete_dir($_GET['cat_id']); + $template->assign( + array( + 'CAT_FULL_DIR' => preg_replace('/\/$/', + '', + $category['cat_full_dir'] ) + ) + ); + if (!url_is_remote($category['cat_full_dir']) ) + { + $template->assign('SHOW_UPLOADABLE', true); + } +} + +// image order management + +$sort_fields = array( + '' => '', + 'date_creation' => l10n('Creation date'), + 'date_available' => l10n('Post date'), + 'average_rate' => l10n('Average rate'), + 'hit' => l10n('most_visited_cat'), + 'file' => l10n('File name'), + 'id' => 'Id', + ); + +$sort_directions = array( + 'ASC' => l10n('ascending'), + 'DESC' => l10n('descending'), + ); + +$template->assign( 'image_order_field_options', $sort_fields); +$template->assign( 'image_order_direction_options', $sort_directions); + +$matches = array(); +if ( !empty( $category['image_order'] ) ) +{ + preg_match_all('/([a-z_]+) *(?:(asc|desc)(?:ending)?)? *(?:, *|$)/i', + $category['image_order'], $matches); +} + +for ($i=0; $i<3; $i++) // 3 fields +{ + $tpl_image_order_select = array( + 'ID' => $i+1, + 'FIELD' => array(''), + 'DIRECTION' => array('ASC'), + ); + + if ( isset($matches[1][$i]) ) + { + $tpl_image_order_select['FIELD'] = array($matches[1][$i]); + } + + if (isset($matches[2][$i]) and strcasecmp($matches[2][$i],'DESC')==0) + { + $tpl_image_order_select['DIRECTION'] = array('DESC'); + } + $template->append( 'image_orders', $tpl_image_order_select); +} + + +// representant management +if ($category['has_images'] + or !empty($category['representative_picture_id'])) +{ + $tpl_representant = array(); + + // picture to display : the identified representant or the generic random + // representant ? + if (!empty($category['representative_picture_id'])) + { + $query = ' +SELECT id,tn_ext,path + FROM '.IMAGES_TABLE.' + WHERE id = '.$category['representative_picture_id'].' +;'; + $row = mysql_fetch_array(pwg_query($query)); + $src = get_thumbnail_url($row); + $url = get_root_url().'admin.php?page=picture_modify'; + $url.= '&image_id='.$category['representative_picture_id']; + + $tpl_representant['picture'] = + array( + 'SRC' => $src, + 'URL' => $url + ); + } + + // can the admin choose to set a new random representant ? + $tpl_representant['ALLOW_SET_RANDOM'] = ($category['has_images']) ? true : false; + + // can the admin delete the current representant ? + if ( + ($category['has_images'] + and $conf['allow_random_representative']) + or + (!$category['has_images'] + and !empty($category['representative_picture_id']))) + { + $tpl_representant['ALLOW_DELETE'] = true; + } + $template->assign('representant', $tpl_representant); +} + +if ($category['is_virtual']) +{ + // the category can be moved in any category but in itself, in any + // sub-category + $unmovables = get_subcat_ids(array($category['id'])); + + $query = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE id NOT IN ('.implode(',', $unmovables).') +;'; + + display_select_cat_wrapper( + $query, + empty($category['id_uppercat']) ? array() : array($category['id_uppercat']), + 'move_cat_options' + ); +} + + +// create virtual in parent and link +$query = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' +;'; +display_select_cat_wrapper( + $query, + array(), + 'create_new_parent_options' + ); + + +// destination categories +$query = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE id != '.$category['id'].' +;'; +display_select_cat_wrapper( + $query, + array(), + 'category_destination_options' + ); + +// info by email to an access granted group of category informations +if (isset($_POST['submitEmail']) and !empty($_POST['group'])) +{ + set_make_full_url(); + + /* TODO: if $category['representative_picture_id'] + is empty find child representative_picture_id */ + if (!empty($category['representative_picture_id'])) + { + $query = ' +SELECT id, file, path, tn_ext + FROM '.IMAGES_TABLE.' + WHERE id = '.$category['representative_picture_id'].' +;'; + + $result = pwg_query($query); + if (mysql_num_rows($result) > 0) + { + $element = mysql_fetch_assoc($result); + + $img_url = '<a href="'. + make_picture_url(array( + 'image_id' => $element['id'], + 'image_file' => $element['file'], + 'category' => $category + )) + .'"><img src="'.get_thumbnail_url($element).'"/></a>'; + } + } + + if (!isset($img_url)) + { + $img_url = ''; + } + + // TODO Mettre un array pour traduction subjet + pwg_mail_group( + $_POST['group'], + get_str_email_format(true), /* TODO add a checkbox in order to choose format*/ + get_l10n_args('[%s] Come to visit the category %s', + array($conf['gallery_title'], $category['name'])), + 'admin', + 'cat_group_info', + array + ( + 'IMG_URL' => $img_url, + 'CAT_NAME' => $category['name'], + 'LINK' => make_index_url( + array( + 'category' => array( + 'id' => $category['id'], + 'name' => $category['name'], + 'permalink' => $category['permalink'] + ))), + 'CPL_CONTENT' => empty($_POST['mail_content']) + ? '' : stripslashes($_POST['mail_content']) + ), + '' /* TODO Add listbox in order to choose Language selected */); + + unset_make_full_url(); + + $query = ' +SELECT + name + FROM '.GROUPS_TABLE.' + WHERE id = '.$_POST['group'].' +;'; + list($group_name) = mysql_fetch_row(pwg_query($query)); + + array_push( + $page['infos'], + sprintf( + l10n('An information email was sent to group "%s"'), + $group_name + ) + ); +} + +if ('private' == $category['status']) +{ + $query = ' +SELECT + group_id + FROM '.GROUP_ACCESS_TABLE.' + WHERE cat_id = '.$category['id'].' +;'; +} +else +{ + $query = ' +SELECT + id AS group_id + FROM '.GROUPS_TABLE.' +;'; +} +$group_ids = array_from_query($query, 'group_id'); + +if (count($group_ids) > 0) +{ + $query = ' +SELECT + id, + name + FROM '.GROUPS_TABLE.' + WHERE id IN ('.implode(',', $group_ids).') + ORDER BY name ASC +;'; + $template->assign('group_mail_options', + simple_hash_from_query($query, 'id', 'name') + ); +} + +//----------------------------------------------------------- sending html code +$template->assign_var_from_handle('ADMIN_CONTENT', 'categories'); +?> diff --git a/BSF/admin/cat_move.php b/BSF/admin/cat_move.php new file mode 100644 index 000000000..412b1412f --- /dev/null +++ b/BSF/admin/cat_move.php @@ -0,0 +1,104 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die('Hacking attempt!'); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | functions | +// +-----------------------------------------------------------------------+ + + +// +-----------------------------------------------------------------------+ +// | categories movement | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['submit'])) +{ + if (count($_POST['selection']) > 0) + { + // TODO: tests + move_categories($_POST['selection'], $_POST['parent']); + } + else + { + array_push( + $page['errors'], + l10n('Select at least one category') + ); + } +} + +// +-----------------------------------------------------------------------+ +// | template initialization | +// +-----------------------------------------------------------------------+ +$template->set_filename('cat_move', 'admin/cat_move.tpl'); + +$template->assign( + array( + 'U_HELP' => PHPWG_ROOT_PATH.'popuphelp.php?page=cat_move', + 'F_ACTION' => PHPWG_ROOT_PATH.'admin.php?page=cat_move', + ) + ); + +// +-----------------------------------------------------------------------+ +// | Categories display | +// +-----------------------------------------------------------------------+ + +$query = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE dir IS NULL +;'; +display_select_cat_wrapper( + $query, + array(), + 'category_to_move_options' + ); + +$query = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' +;'; + +display_select_cat_wrapper( + $query, + array(), + 'category_parent_options' + ); + +// +-----------------------------------------------------------------------+ +// | sending html code | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('ADMIN_CONTENT', 'cat_move'); +?> diff --git a/BSF/admin/cat_options.php b/BSF/admin/cat_options.php new file mode 100644 index 000000000..810534f0b --- /dev/null +++ b/BSF/admin/cat_options.php @@ -0,0 +1,312 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); +include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | modification registration | +// +-----------------------------------------------------------------------+ + +// print '<pre>'; +// print_r($_POST); +// print '</pre>'; +if (isset($_POST['falsify']) + and isset($_POST['cat_true']) + and count($_POST['cat_true']) > 0) +{ + switch ($_GET['section']) + { + case 'upload' : + { + $query = ' +UPDATE '.CATEGORIES_TABLE.' + SET uploadable = \'false\' + WHERE id IN ('.implode(',', $_POST['cat_true']).') +;'; + pwg_query($query); + break; + } + case 'comments' : + { + $query = ' +UPDATE '.CATEGORIES_TABLE.' + SET commentable = \'false\' + WHERE id IN ('.implode(',', $_POST['cat_true']).') +;'; + pwg_query($query); + break; + } + case 'visible' : + { + set_cat_visible($_POST['cat_true'], 'false'); + break; + } + case 'status' : + { + set_cat_status($_POST['cat_true'], 'private'); + break; + } + case 'representative' : + { + $query = ' +UPDATE '.CATEGORIES_TABLE.' + SET representative_picture_id = NULL + WHERE id IN ('.implode(',', $_POST['cat_true']).') +;'; + pwg_query($query); + break; + } + } +} +else if (isset($_POST['trueify']) + and isset($_POST['cat_false']) + and count($_POST['cat_false']) > 0) +{ + switch ($_GET['section']) + { + case 'upload' : + { + $query = ' +UPDATE '.CATEGORIES_TABLE.' + SET uploadable = \'true\' + WHERE id IN ('.implode(',', $_POST['cat_false']).') +;'; + pwg_query($query); + break; + } + case 'comments' : + { + $query = ' +UPDATE '.CATEGORIES_TABLE.' + SET commentable = \'true\' + WHERE id IN ('.implode(',', $_POST['cat_false']).') +;'; + pwg_query($query); + break; + } + case 'visible' : + { + set_cat_visible($_POST['cat_false'], 'true'); + break; + } + case 'status' : + { + set_cat_status($_POST['cat_false'], 'public'); + break; + } + case 'representative' : + { + // theoretically, all categories in $_POST['cat_false'] contain at + // least one element, so Piwigo can find a representant. + set_random_representant($_POST['cat_false']); + break; + } + } +} + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filenames( + array( + 'cat_options' => 'admin/cat_options.tpl', + 'double_select' => 'admin/double_select.tpl' + ) + ); + +$page['section'] = isset($_GET['section']) ? $_GET['section'] : 'status'; +$base_url = PHPWG_ROOT_PATH.'admin.php?page=cat_options&section='; + +$template->assign( + array( + 'U_HELP' => PHPWG_ROOT_PATH.'/popuphelp.php?page=cat_options', + 'F_ACTION'=>$base_url.$page['section'] + ) + ); + +// TabSheet +$tabsheet = new tabsheet(); +// TabSheet initialization +$opt_link = $link_start.'cat_options&section='; +$tabsheet->add('status', l10n('cat_security'), $opt_link.'status'); +$tabsheet->add('visible', l10n('lock'), $opt_link.'visible'); +$tabsheet->add('upload', l10n('upload'), $opt_link.'upload'); +$tabsheet->add('comments', l10n('comments'), $opt_link.'comments'); +if ($conf['allow_random_representative']) +{ + $tabsheet->add('representative', l10n('Representative'), $opt_link.'representative'); +} +// TabSheet selection +$tabsheet->select($page['section']); +// Assign tabsheet to template +$tabsheet->assign(); + +// +-----------------------------------------------------------------------+ +// | form display | +// +-----------------------------------------------------------------------+ + +// for each section, categories in the multiselect field can be : +// +// - true : uploadable for upload section +// - false : un-uploadable for upload section +// - NA : (not applicable) for virtual categories +// +// for true and false status, we associates an array of category ids, +// function display_select_categories will use the given CSS class for each +// option +$cats_true = array(); +$cats_false = array(); +switch ($page['section']) +{ + case 'upload' : + { + $query_true = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE uploadable = \'true\' + AND dir IS NOT NULL + AND site_id = 1 +;'; + $query_false = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE uploadable = \'false\' + AND dir IS NOT NULL + AND site_id = 1 +;'; + $template->assign( + array( + 'L_SECTION' => l10n('cat_upload_title'), + 'L_CAT_OPTIONS_TRUE' => l10n('authorized'), + 'L_CAT_OPTIONS_FALSE' => l10n('forbidden'), + ) + ); + break; + } + case 'comments' : + { + $query_true = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE commentable = \'true\' +;'; + $query_false = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE commentable = \'false\' +;'; + $template->assign( + array( + 'L_SECTION' => l10n('cat_comments_title'), + 'L_CAT_OPTIONS_TRUE' => l10n('authorized'), + 'L_CAT_OPTIONS_FALSE' => l10n('forbidden'), + ) + ); + break; + } + case 'visible' : + { + $query_true = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE visible = \'true\' +;'; + $query_false = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE visible = \'false\' +;'; + $template->assign( + array( + 'L_SECTION' => l10n('cat_lock_title'), + 'L_CAT_OPTIONS_TRUE' => l10n('unlocked'), + 'L_CAT_OPTIONS_FALSE' => l10n('locked'), + ) + ); + break; + } + case 'status' : + { + $query_true = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE status = \'public\' +;'; + $query_false = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE status = \'private\' +;'; + $template->assign( + array( + 'L_SECTION' => l10n('cat_status_title'), + 'L_CAT_OPTIONS_TRUE' => l10n('cat_public'), + 'L_CAT_OPTIONS_FALSE' => l10n('cat_private'), + ) + ); + break; + } + case 'representative' : + { + $query_true = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE representative_picture_id IS NOT NULL +;'; + $query_false = ' +SELECT DISTINCT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id=category_id + WHERE representative_picture_id IS NULL +;'; + $template->assign( + array( + 'L_SECTION' => l10n('Representative'), + 'L_CAT_OPTIONS_TRUE' => l10n('singly represented'), + 'L_CAT_OPTIONS_FALSE' => l10n('randomly represented') + ) + ); + break; + } +} +display_select_cat_wrapper($query_true,array(),'category_option_true'); +display_select_cat_wrapper($query_false,array(),'category_option_false'); + +// +-----------------------------------------------------------------------+ +// | sending html code | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('DOUBLE_SELECT', 'double_select'); +$template->assign_var_from_handle('ADMIN_CONTENT', 'cat_options'); +?>
\ No newline at end of file diff --git a/BSF/admin/cat_perm.php b/BSF/admin/cat_perm.php new file mode 100644 index 000000000..45eb15937 --- /dev/null +++ b/BSF/admin/cat_perm.php @@ -0,0 +1,330 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | variable initialization | +// +-----------------------------------------------------------------------+ + +// if the category is not correct (not numeric, not private) +if (isset($_GET['cat']) and is_numeric($_GET['cat'])) +{ + $query = ' +SELECT status + FROM '.CATEGORIES_TABLE.' + WHERE id = '.$_GET['cat'].' +;'; + list($status) = mysql_fetch_array(pwg_query($query)); + + if ('private' == $status) + { + $page['cat'] = $_GET['cat']; + } +} + +if (!isset($page['cat'])) +{ + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE status = \'private\' + LIMIT 0,1 +;'; + + list($page['cat']) = mysql_fetch_array(pwg_query($query)); +} + +// +-----------------------------------------------------------------------+ +// | form submission | +// +-----------------------------------------------------------------------+ + + +if (isset($_POST['deny_groups_submit']) + and isset($_POST['deny_groups']) + and count($_POST['deny_groups']) > 0) +{ + // if you forbid access to a category, all sub-categories become + // automatically forbidden + $query = ' +DELETE + FROM '.GROUP_ACCESS_TABLE.' + WHERE group_id IN ('.implode(',', $_POST['deny_groups']).') + AND cat_id IN ('.implode(',', get_subcat_ids(array($page['cat']))).') +;'; + pwg_query($query); +} +else if (isset($_POST['grant_groups_submit']) + and isset($_POST['grant_groups']) + and count($_POST['grant_groups']) > 0) +{ + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE id IN ('.implode(',', get_uppercat_ids(array($page['cat']))).') + AND status = \'private\' +;'; + $private_uppercats = array_from_query($query, 'id'); + + // We must not reinsert already existing lines in group_access table + $granteds = array(); + foreach ($private_uppercats as $cat_id) + { + $granteds[$cat_id] = array(); + } + + $query = ' +SELECT group_id, cat_id + FROM '.GROUP_ACCESS_TABLE.' + WHERE cat_id IN ('.implode(',', $private_uppercats).') + AND group_id IN ('.implode(',', $_POST['grant_groups']).') +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($granteds[$row['cat_id']], $row['group_id']); + } + + $inserts = array(); + + foreach ($private_uppercats as $cat_id) + { + $group_ids = array_diff($_POST['grant_groups'], $granteds[$cat_id]); + foreach ($group_ids as $group_id) + { + array_push($inserts, array('group_id' => $group_id, + 'cat_id' => $cat_id)); + } + } + + mass_inserts(GROUP_ACCESS_TABLE, array('group_id','cat_id'), $inserts); +} +else if (isset($_POST['deny_users_submit']) + and isset($_POST['deny_users']) + and count($_POST['deny_users']) > 0) +{ + // if you forbid access to a category, all sub-categories become + // automatically forbidden + $query = ' +DELETE + FROM '.USER_ACCESS_TABLE.' + WHERE user_id IN ('.implode(',', $_POST['deny_users']).') + AND cat_id IN ('.implode(',', get_subcat_ids(array($page['cat']))).') +;'; + pwg_query($query); +} +else if (isset($_POST['grant_users_submit']) + and isset($_POST['grant_users']) + and count($_POST['grant_users']) > 0) +{ + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE id IN ('.implode(',', get_uppercat_ids(array($page['cat']))).') + AND status = \'private\' +;'; + $private_uppercats = array_from_query($query, 'id'); + + // We must not reinsert already existing lines in user_access table + $granteds = array(); + foreach ($private_uppercats as $cat_id) + { + $granteds[$cat_id] = array(); + } + + $query = ' +SELECT user_id, cat_id + FROM '.USER_ACCESS_TABLE.' + WHERE cat_id IN ('.implode(',', $private_uppercats).') + AND user_id IN ('.implode(',', $_POST['grant_users']).') +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($granteds[$row['cat_id']], $row['user_id']); + } + + $inserts = array(); + + foreach ($private_uppercats as $cat_id) + { + $user_ids = array_diff($_POST['grant_users'], $granteds[$cat_id]); + foreach ($user_ids as $user_id) + { + array_push($inserts, array('user_id' => $user_id, + 'cat_id' => $cat_id)); + } + } + + mass_inserts(USER_ACCESS_TABLE, array('user_id','cat_id'), $inserts); +} + +// +-----------------------------------------------------------------------+ +// | template initialization | +// +-----------------------------------------------------------------------+ + +$template->set_filename('cat_perm', 'admin/cat_perm.tpl'); + +$template->assign( + array( + 'CATEGORIES_NAV' => + get_cat_display_name_from_id( + $page['cat'], + 'admin.php?page=cat_modify&cat_id=' + ), + 'U_HELP' => get_root_url().'popuphelp.php?page=cat_perm', + 'F_ACTION' => get_root_url().'admin.php?page=cat_perm&cat='.$page['cat'] + ) + ); + +// +-----------------------------------------------------------------------+ +// | form construction | +// +-----------------------------------------------------------------------+ + +// groups denied are the groups not granted. So we need to find all groups +// minus groups granted to find groups denied. + +$groups = array(); + +$query = ' +SELECT id, name + FROM '.GROUPS_TABLE.' + ORDER BY name ASC +;'; +$groups = simple_hash_from_query($query, 'id', 'name'); +$template->assign('all_groups', $groups); + +// groups granted to access the category +$query = ' +SELECT group_id + FROM '.GROUP_ACCESS_TABLE.' + WHERE cat_id = '.$page['cat'].' +;'; +$group_granted_ids = array_from_query($query, 'group_id'); +$group_granted_ids = order_by_name($group_granted_ids, $groups); +$template->assign('group_granted_ids', $group_granted_ids); + + +// groups denied +$template->assign('group_denied_ids', + order_by_name(array_diff(array_keys($groups), $group_granted_ids), $groups) + ); + +// users... +$users = array(); + +$query = ' +SELECT '.$conf['user_fields']['id'].' AS id, + '.$conf['user_fields']['username'].' AS username + FROM '.USERS_TABLE.' +;'; +$users = simple_hash_from_query($query, 'id', 'username'); +$template->assign('all_users', $users); + + +$query = ' +SELECT user_id + FROM '.USER_ACCESS_TABLE.' + WHERE cat_id = '.$page['cat'].' +;'; +$user_granted_direct_ids = array_from_query($query, 'user_id'); +$user_granted_direct_ids = order_by_name($user_granted_direct_ids, $users); +$template->assign('user_granted_direct_ids', $user_granted_direct_ids); + + + +$user_granted_indirect_ids = array(); +if (count($group_granted_ids) > 0) +{ + $granted_groups = array(); + + $query = ' +SELECT user_id, group_id + FROM '.USER_GROUP_TABLE.' + WHERE group_id IN ('.implode(',', $group_granted_ids).') +'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + if (!isset($granted_groups[$row['group_id']])) + { + $granted_groups[$row['group_id']] = array(); + } + array_push($granted_groups[$row['group_id']], $row['user_id']); + } + + $user_granted_by_group_ids = array(); + + foreach ($granted_groups as $group_users) + { + $user_granted_by_group_ids = array_merge($user_granted_by_group_ids, + $group_users); + } + $user_granted_by_group_ids = array_unique($user_granted_by_group_ids); + + + $user_granted_indirect_ids = array_diff($user_granted_by_group_ids, + $user_granted_direct_ids); + $user_granted_indirect_ids = + order_by_name($user_granted_indirect_ids, $users); + foreach ($user_granted_indirect_ids as $user_id) + { + foreach ($granted_groups as $group_id => $group_users) + { + if (in_array($user_id, $group_users)) + { + $template->append( + 'user_granted_indirects', + array( + 'USER'=>$users[$user_id], + 'GROUP'=>$groups[$group_id] + ) + ); + break; + } + } + } +} + +$user_denied_ids = array_diff(array_keys($users), + $user_granted_indirect_ids, + $user_granted_direct_ids); +$user_denied_ids = order_by_name($user_denied_ids, $users); +$template->assign('user_denied_ids', $user_denied_ids); + + +// +-----------------------------------------------------------------------+ +// | sending html code | +// +-----------------------------------------------------------------------+ +$template->assign_var_from_handle('ADMIN_CONTENT', 'cat_perm'); +?> diff --git a/BSF/admin/comments.php b/BSF/admin/comments.php new file mode 100644 index 000000000..200451989 --- /dev/null +++ b/BSF/admin/comments.php @@ -0,0 +1,179 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); +include_once(PHPWG_ROOT_PATH.'admin/include/functions_waiting.inc.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | actions | +// +-----------------------------------------------------------------------+ + +if (isset($_POST)) +{ + $to_validate = array(); + $to_reject = array(); + + if (isset($_POST['submit']) and !is_adviser()) + { + foreach (explode(',', $_POST['list']) as $comment_id) + { + if (isset($_POST['action-'.$comment_id])) + { + switch ($_POST['action-'.$comment_id]) + { + case 'reject' : + { + array_push($to_reject, $comment_id); + break; + } + case 'validate' : + { + array_push($to_validate, $comment_id); + break; + } + } + } + } + } + else if (isset($_POST['validate-all']) and !empty($_POST['list']) and !is_adviser()) + { + $to_validate = explode(',', $_POST['list']); + } + else if (isset($_POST['reject-all']) and !empty($_POST['list']) and !is_adviser()) + { + $to_reject = explode(',', $_POST['list']); + } + + if (count($to_validate) > 0) + { + $query = ' +UPDATE '.COMMENTS_TABLE.' + SET validated = \'true\' + , validation_date = NOW() + WHERE id IN ('.implode(',', $to_validate).') +;'; + pwg_query($query); + + array_push( + $page['infos'], + l10n_dec( + '%d user comment validated', '%d user comments validated', + count($to_validate) + ) + ); + } + + if (count($to_reject) > 0) + { + $query = ' +DELETE + FROM '.COMMENTS_TABLE.' + WHERE id IN ('.implode(',', $to_reject).') +;'; + pwg_query($query); + + array_push( + $page['infos'], + l10n_dec( + '%d user comment rejected', '%d user comments rejected', + count($to_reject) + ) + ); + } +} + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filenames(array('comments'=>'admin/comments.tpl')); + +// TabSheet initialization +waiting_tabsheet(); + +$template->assign( + array( + 'F_ACTION' => get_root_url().'admin.php?page=comments' + ) + ); + +// +-----------------------------------------------------------------------+ +// | comments display | +// +-----------------------------------------------------------------------+ + +$list = array(); + +$query = ' +SELECT c.id, c.image_id, c.date, c.author, c.content, i.path, i.tn_ext + FROM '.COMMENTS_TABLE.' AS c + INNER JOIN '.IMAGES_TABLE.' AS i + ON i.id = c.image_id + WHERE validated = \'false\' + ORDER BY c.date DESC +;'; +$result = pwg_query($query); +while ($row = mysql_fetch_assoc($result)) +{ + $thumb = get_thumbnail_url( + array( + 'id'=>$row['image_id'], + 'path'=>$row['path'], + 'tn_ext'=>@$row['tn_ext'] + ) + ); + $template->append( + 'comments', + array( + 'U_PICTURE' => + PHPWG_ROOT_PATH.'admin.php?page=picture_modify'. + '&image_id='.$row['image_id'], + 'ID' => $row['id'], + 'TN_SRC' => $thumb, + 'AUTHOR' => trigger_event('render_comment_author', $row['author']), + 'DATE' => format_date($row['date'],'mysql_datetime',true), + 'CONTENT' => trigger_event('render_comment_content',$row['content']) + ) + ); + + array_push($list, $row['id']); +} + +$template->assign('LIST', implode(',', $list) ); + +// +-----------------------------------------------------------------------+ +// | sending html code | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('ADMIN_CONTENT', 'comments'); + +?> diff --git a/BSF/admin/configuration.php b/BSF/admin/configuration.php new file mode 100644 index 000000000..8e69d9c16 --- /dev/null +++ b/BSF/admin/configuration.php @@ -0,0 +1,301 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if( !defined("PHPWG_ROOT_PATH") ) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); +include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +//-------------------------------------------------------- sections definitions +if (!isset($_GET['section'])) +{ + $page['section'] = 'main'; +} +else +{ + $page['section'] = $_GET['section']; +} + +$main_checkboxes = array( + 'gallery_locked', + 'allow_user_registration', + 'obligatory_user_mail_address', + 'rate', + 'rate_anonymous', + 'email_admin_on_new_user', + ); + +$history_checkboxes = array( + 'log', + 'history_admin', + 'history_guest' + ); + +$upload_checkboxes = array( + 'upload_link_everytime', + 'email_admin_on_picture_uploaded', + ); + +$comments_checkboxes = array( + 'comments_forall', + 'comments_validation', + 'email_admin_on_comment', + 'email_admin_on_comment_validation', + ); + +//------------------------------ verification and registration of modifications +if (isset($_POST['submit']) and !is_adviser()) +{ + $int_pattern = '/^\d+$/'; + + switch ($page['section']) + { + case 'main' : + { + if ( !url_is_remote($_POST['gallery_url']) ) + { + array_push($page['errors'], l10n('conf_gallery_url_error')); + } + foreach( $main_checkboxes as $checkbox) + { + $_POST[$checkbox] = empty($_POST[$checkbox])?'false':'true'; + } + break; + } + case 'history' : + { + foreach( $history_checkboxes as $checkbox) + { + $_POST[$checkbox] = empty($_POST[$checkbox])?'false':'true'; + } + break; + } + case 'comments' : + { + // the number of comments per page must be an integer between 5 and 50 + // included + if (!preg_match($int_pattern, $_POST['nb_comment_page']) + or $_POST['nb_comment_page'] < 5 + or $_POST['nb_comment_page'] > 50) + { + array_push($page['errors'], l10n('conf_nb_comment_page_error')); + } + foreach( $comments_checkboxes as $checkbox) + { + $_POST[$checkbox] = empty($_POST[$checkbox])?'false':'true'; + } + break; + } + case 'upload' : + { + foreach( $upload_checkboxes as $checkbox) + { + $_POST[$checkbox] = empty($_POST[$checkbox])?'false':'true'; + } + break; + } + case 'default' : + { + // Never go here + break; + } + } + + // updating configuration if no error found + if (count($page['errors']) == 0) + { + //echo '<pre>'; print_r($_POST); echo '</pre>'; + $result = pwg_query('SELECT param FROM '.CONFIG_TABLE); + while ($row = mysql_fetch_array($result)) + { + if (isset($_POST[$row['param']])) + { + $value = $_POST[$row['param']]; + + if ('gallery_title' == $row['param']) + { + if (!$conf['allow_html_descriptions']) + { + $value = strip_tags($value); + } + } + + $query = ' +UPDATE '.CONFIG_TABLE.' +SET value = \''. str_replace("\'", "''", $value).'\' +WHERE param = \''.$row['param'].'\' +;'; + pwg_query($query); + } + } + array_push($page['infos'], l10n('conf_confirmation')); + } + + //------------------------------------------------------ $conf reinitialization + load_conf_from_db(); +} + +//----------------------------------------------------- template initialization +$template->set_filename('config', 'admin/configuration.tpl'); + +// TabSheet +$tabsheet = new tabsheet(); +// TabSheet initialization +$tabsheet->add('main', l10n('conf_main_title'), $conf_link.'main'); +$tabsheet->add('history', l10n('conf_history_title'), $conf_link.'history'); +$tabsheet->add('comments', l10n('conf_comments_title'), $conf_link.'comments'); +$tabsheet->add('upload', l10n('conf_upload_title'), $conf_link.'upload'); +$tabsheet->add('default', l10n('conf_display'), $conf_link.'default'); +// TabSheet selection +$tabsheet->select($page['section']); +// Assign tabsheet to template +$tabsheet->assign(); + +$action = get_root_url().'admin.php?page=configuration'; +$action.= '&section='.$page['section']; + +$template->assign( + array( + 'U_HELP' => get_root_url().'popuphelp.php?page=configuration', + 'F_ACTION'=>$action + )); + +switch ($page['section']) +{ + case 'main' : + { + $template->assign( + 'main', + array( + 'CONF_GALLERY_TITLE' => htmlspecialchars($conf['gallery_title']), + 'CONF_PAGE_BANNER' => htmlspecialchars($conf['page_banner']), + 'CONF_GALLERY_URL' => $conf['gallery_url'], + )); + + foreach ($main_checkboxes as $checkbox) + { + $template->append( + 'main', + array( + $checkbox => $conf[$checkbox] + ), + true + ); + } + break; + } + case 'history' : + { + //Necessary for merge_block_vars + foreach ($history_checkboxes as $checkbox) + { + $template->append( + 'history', + array( + $checkbox => $conf[$checkbox] + ), + true + ); + } + break; + } + case 'comments' : + { + $template->assign( + 'comments', + array( + 'NB_COMMENTS_PAGE'=>$conf['nb_comment_page'], + )); + + foreach ($comments_checkboxes as $checkbox) + { + $template->append( + 'comments', + array( + $checkbox => $conf[$checkbox] + ), + true + ); + } + break; + } + case 'upload' : + { + $template->assign( + 'upload', + array( + 'upload_user_access_options'=> get_user_access_level_html_options(ACCESS_GUEST), + 'upload_user_access_options_selected' => array($conf['upload_user_access']) + ) + ); + //Necessary for merge_block_vars + foreach ($upload_checkboxes as $checkbox) + { + $template->append( + 'upload', + array( + $checkbox => $conf[$checkbox] + ), + true + ); + } + break; + } + case 'default' : + { + $edit_user = build_user($conf['default_user_id'], false); + include_once(PHPWG_ROOT_PATH.'profile.php'); + + $errors = array(); + if ( !is_adviser() ) + { + if (save_profile_from_post($edit_user, $errors)) + { + // Reload user + $edit_user = build_user($conf['default_user_id'], false); + array_push($page['infos'], l10n('conf_confirmation')); + } + } + $page['errors'] = array_merge($page['errors'], $errors); + + load_profile_in_template( + $action, + '', + $edit_user + ); + $template->assign('default', array()); + break; + } +} + +//----------------------------------------------------------- sending html code +$template->assign_var_from_handle('ADMIN_CONTENT', 'config'); +?> diff --git a/BSF/admin/element_set.php b/BSF/admin/element_set.php new file mode 100644 index 000000000..5513a5e64 --- /dev/null +++ b/BSF/admin/element_set.php @@ -0,0 +1,232 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * Management of elements set. Elements can belong to a category or to the + * user caddie. + * + */ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die('Hacking attempt!'); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | caddie management | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['submit_caddie'])) +{ + if (isset($_POST['caddie_action'])) + { + switch ($_POST['caddie_action']) + { + case 'empty_all' : + { + $query = ' +DELETE FROM '.CADDIE_TABLE.' + WHERE user_id = '.$user['id'].' +;'; + pwg_query($query); + break; + } + case 'empty_selected' : + { + if (isset($_POST['selection']) and count($_POST['selection']) > 0) + { + $query = ' +DELETE + FROM '.CADDIE_TABLE.' + WHERE element_id IN ('.implode(',', $_POST['selection']).') + AND user_id = '.$user['id'].' +;'; + pwg_query($query); + } + else + { + // TODO : add error + } + break; + } + case 'add_selected' : + { + if (isset($_POST['selection']) and count($_POST['selection']) > 0) + { + fill_caddie($_POST['selection']); + } + else + { + // TODO : add error + } + break; + } + } + } + else + { + // TODO : add error + } +} + +// +-----------------------------------------------------------------------+ +// | initialize info about category | +// +-----------------------------------------------------------------------+ + +// To element_set_(global|unit).php, we must provide the elements id of the +// managed category in $page['cat_elements_id'] array. + +if (is_numeric($_GET['cat'])) +{ + $page['title'] = + get_cat_display_name_from_id( + $_GET['cat'], + PHPWG_ROOT_PATH.'admin.php?page=cat_modify&cat_id=', + false + ); + + $query = ' +SELECT image_id + FROM '.IMAGE_CATEGORY_TABLE.' + WHERE category_id = '.$_GET['cat'].' +;'; + $page['cat_elements_id'] = array_from_query($query, 'image_id'); +} +else if ('caddie' == $_GET['cat']) +{ + $page['title'] = l10n('caddie'); + + $query = ' +SELECT element_id + FROM '.CADDIE_TABLE.' + WHERE user_id = '.$user['id'].' +;'; + $page['cat_elements_id'] = array_from_query($query, 'element_id'); +} +else if ('not_linked' == $_GET['cat']) +{ + $page['title'] = l10n('Elements_not_linked'); + + // we are searching elements not linked to any virtual category + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE dir IS NULL +;'; + $virtual_categories = array_from_query($query, 'id'); + + if (!empty($virtual_categories)) + { + $query = ' +SELECT DISTINCT(image_id) + FROM '.IMAGE_CATEGORY_TABLE.' +;'; + $all_elements = array_from_query($query, 'image_id'); + + $query = ' +SELECT DISTINCT(image_id) + FROM '.IMAGE_CATEGORY_TABLE.' + WHERE category_id IN ('.implode(',', $virtual_categories).') +;'; + $linked_to_virtual = array_from_query($query, 'image_id'); + + $page['cat_elements_id'] = array_diff($all_elements, $linked_to_virtual); + } + else + { + $page['cat_elements_id'] = array(); + } +} +else if ('duplicates' == $_GET['cat']) +{ + $page['title'] = l10n('Duplicates'); + + // we are searching related elements twice or more to physical categories + // 1 - Retrieve Files + $query = ' +SELECT DISTINCT(file) + FROM '.IMAGES_TABLE.' + GROUP BY file +HAVING COUNT(DISTINCT storage_category_id) > 1 +;'; + + $duplicate_files = array_from_query($query, 'file'); + $duplicate_files[]='Nofiles'; + // 2 - Retrives related picture ids + $query = ' +SELECT id, file + FROM '.IMAGES_TABLE.' +WHERE file IN (\''.implode("','", $duplicate_files).'\') +ORDER BY file, id +;'; + + $page['cat_elements_id'] = array_from_query($query, 'id'); + $page['cat_elements_id'][] = 0; +} +// +-----------------------------------------------------------------------+ +// | first element to display | +// +-----------------------------------------------------------------------+ + +// $page['start'] contains the number of the first element in its +// category. For exampe, $page['start'] = 12 means we must show elements #12 +// and $page['nb_images'] next elements + +if (!isset($_GET['start']) + or !is_numeric($_GET['start']) + or $_GET['start'] < 0 + or (isset($_GET['display']) and 'all' == $_GET['display'])) +{ + $page['start'] = 0; +} +else +{ + $page['start'] = $_GET['start']; +} + +// +-----------------------------------------------------------------------+ +// | open specific mode | +// +-----------------------------------------------------------------------+ + +$_GET['mode'] = !empty($_GET['mode']) ? $_GET['mode'] : 'global'; + +switch ($_GET['mode']) +{ + case 'global' : + { + include(PHPWG_ROOT_PATH.'admin/element_set_global.php'); + break; + } + case 'unit' : + { + include(PHPWG_ROOT_PATH.'admin/element_set_unit.php'); + break; + } +} +?> diff --git a/BSF/admin/element_set_global.php b/BSF/admin/element_set_global.php new file mode 100644 index 000000000..e4725a059 --- /dev/null +++ b/BSF/admin/element_set_global.php @@ -0,0 +1,382 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * Management of elements set. Elements can belong to a category or to the + * user caddie. + * + */ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die('Hacking attempt!'); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | global mode form submission | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['submit'])) +{ + $collection = array(); + +// echo '<pre>'; +// print_r($_POST); +// echo '</pre>'; +// exit(); + + switch ($_POST['target']) + { + case 'all' : + { + $collection = $page['cat_elements_id']; + break; + } + case 'selection' : + { + if (!isset($_POST['selection']) or count($_POST['selection']) == 0) + { + array_push($page['errors'], l10n('Select at least one picture')); + } + else + { + $collection = $_POST['selection']; + } + break; + } + } + + if (isset($_POST['add_tags']) and count($collection) > 0) + { + add_tags($_POST['add_tags'], $collection); + } + + if (isset($_POST['del_tags']) and count($collection) > 0) + { + $query = ' +DELETE + FROM '.IMAGE_TAG_TABLE.' + WHERE image_id IN ('.implode(',', $collection).') + AND tag_id IN ('.implode(',', $_POST['del_tags']).') +;'; + pwg_query($query); + } + + if ($_POST['associate'] != 0 and count($collection) > 0) + { + associate_images_to_categories( + $collection, + array($_POST['associate']) + ); + } + + if ($_POST['dissociate'] != 0 and count($collection) > 0) + { + // physical links must not be broken, so we must first retrieve image_id + // which create virtual links with the category to "dissociate from". + $query = ' +SELECT id + FROM '.IMAGE_CATEGORY_TABLE.' + INNER JOIN '.IMAGES_TABLE.' ON image_id = id + WHERE category_id = '.$_POST['dissociate'].' + AND id IN ('.implode(',', $collection).') + AND category_id != storage_category_id +;'; + $dissociables = array_from_query($query, 'id'); + + if (!empty($dissociables)) + { + $query = ' +DELETE + FROM '.IMAGE_CATEGORY_TABLE.' + WHERE category_id = '.$_POST['dissociate'].' + AND image_id IN ('.implode(',', $dissociables).') +'; + pwg_query($query); + + $page['cat_elements_id'] = array_diff( + $page['cat_elements_id'], + $dissociables + ); + } + + update_category($_POST['dissociate']); + } + + $datas = array(); + $dbfields = array('primary' => array('id'), 'update' => array()); + + $formfields = array('author', 'name', 'date_creation', 'level'); + foreach ($formfields as $formfield) + { + if ($_POST[$formfield.'_action'] != 'leave') + { + array_push($dbfields['update'], $formfield); + } + } + + // updating elements is useful only if needed... + if (count($dbfields['update']) > 0 and count($collection) > 0) + { + $query = ' +SELECT id + FROM '.IMAGES_TABLE.' + WHERE id IN ('.implode(',', $collection).') +;'; + $result = pwg_query($query); + + while ($row = mysql_fetch_array($result)) + { + $data = array(); + $data['id'] = $row['id']; + + if ('set' == $_POST['author_action']) + { + $data['author'] = $_POST['author']; + if ('' == $data['author']) + { + unset($data['author']); + } + } + + if ('set' == $_POST['name_action']) + { + $data['name'] = $_POST['name']; + if ('' == $data['name']) + { + unset($data['name']); + } + } + + if ('set' == $_POST['date_creation_action']) + { + $data['date_creation'] = + $_POST['date_creation_year'] + .'-'.$_POST['date_creation_month'] + .'-'.$_POST['date_creation_day'] + ; + } + + if ('set' == $_POST['level_action']) + { + $data['level'] = $_POST['level']; + } + + array_push($datas, $data); + } + // echo '<pre>'; print_r($datas); echo '</pre>'; + mass_updates(IMAGES_TABLE, $dbfields, $datas); + } +} + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ +$template->set_filenames( + array('element_set_global' => 'admin/element_set_global.tpl')); + +$base_url = get_root_url().'admin.php'; + +// $form_action = $base_url.'?page=element_set_global'; + +$template->assign( + array( + 'CATEGORIES_NAV'=>$page['title'], + + 'U_DISPLAY'=>$base_url.get_query_string_diff(array('display')), + + 'U_UNIT_MODE' + => + $base_url + .get_query_string_diff(array('mode','display')) + .'&mode=unit', + + 'F_ACTION'=>$base_url.get_query_string_diff(array()), + ) + ); + +// +-----------------------------------------------------------------------+ +// | caddie options | +// +-----------------------------------------------------------------------+ + +$template->assign('IN_CADDIE', 'caddie' == $_GET['cat'] ? true : false ); + +// +-----------------------------------------------------------------------+ +// | global mode form | +// +-----------------------------------------------------------------------+ + +// Virtualy associate a picture to a category +$query = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' +;'; +display_select_cat_wrapper($query, array(), 'associate_options', true); + +// Dissociate from a category : categories listed for dissociation can +// only represent virtual links. Links to physical categories can't be +// broken +if (count($page['cat_elements_id']) > 0) +{ + $query = ' +SELECT DISTINCT(category_id) AS id, c.name, uppercats, global_rank + FROM '.IMAGE_CATEGORY_TABLE.' AS ic, + '.CATEGORIES_TABLE.' AS c, + '.IMAGES_TABLE.' AS i + WHERE ic.image_id IN ('.implode(',', $page['cat_elements_id']).') + AND ic.category_id = c.id + AND ic.image_id = i.id + AND ic.category_id != i.storage_category_id +;'; + display_select_cat_wrapper($query, array(), 'dissociate_options', true); +} + +$all_tags = get_all_tags(); + +if (count($all_tags) > 0) +{// add tags + $template->assign( + array( + 'ADD_TAG_SELECTION' => get_html_tag_selection( + $all_tags, + 'add_tags' + ), + ) + ); +} + +if (count($page['cat_elements_id']) > 0) +{ + // remove tags + $tags = get_common_tags($page['cat_elements_id'], -1); + usort($tags, 'name_compare'); + + $template->assign( + array( + 'DEL_TAG_SELECTION' => get_html_tag_selection($tags, 'del_tags'), + ) + ); +} + +// creation date +$day = +empty($_POST['date_creation_day']) ? date('j') : $_POST['date_creation_day']; + +$month = +empty($_POST['date_creation_month']) ? date('n') : $_POST['date_creation_month']; + +$year = +empty($_POST['date_creation_year']) ? date('Y') : $_POST['date_creation_year']; + +$month_list = $lang['month']; +$month_list[0]='------------'; +ksort($month_list); +$template->assign( array( + 'month_list' => $month_list, + 'DATE_CREATION_DAY' => (int)$day, + 'DATE_CREATION_MONTH'=> (int)$month, + 'DATE_CREATION_YEAR' => (int)$year, + ) + ); + +// image level options +$tpl_options = array(); +foreach ($conf['available_permission_levels'] as $level) +{ + $tpl_options[$level] = l10n( sprintf('Level %d', $level) ); +} +$template->assign( + array( + 'level_options'=> $tpl_options, + ) + ); + +// +-----------------------------------------------------------------------+ +// | global mode thumbnails | +// +-----------------------------------------------------------------------+ + +// how many items to display on this page +if (!empty($_GET['display'])) +{ + if ('all' == $_GET['display']) + { + $page['nb_images'] = count($page['cat_elements_id']); + } + else + { + $page['nb_images'] = intval($_GET['display']); + } +} +else +{ + $page['nb_images'] = 20; +} + +if (count($page['cat_elements_id']) > 0) +{ + $nav_bar = create_navigation_bar( + $base_url.get_query_string_diff(array('start')), + count($page['cat_elements_id']), + $page['start'], + $page['nb_images'] + ); + $template->assign('NAV_BAR', $nav_bar); + + $query = ' +SELECT id,path,tn_ext,file,filesize,level + FROM '.IMAGES_TABLE.' + WHERE id IN ('.implode(',', $page['cat_elements_id']).') + '.$conf['order_by'].' + LIMIT '.$page['start'].', '.$page['nb_images'].' +;'; + //echo '<pre>'.$query.'</pre>'; + $result = pwg_query($query); + + // template thumbnail initialization + + while ($row = mysql_fetch_assoc($result)) + { + $src = get_thumbnail_url($row); + + $template->append( + 'thumbnails', + array( + 'ID' => $row['id'], + 'TN_SRC' => $src, + 'FILE' => $row['file'], + 'TITLE' => get_thumbnail_title($row), + 'LEVEL' => $row['level'] + ) + ); + } +} + +//----------------------------------------------------------- sending html code +$template->assign_var_from_handle('ADMIN_CONTENT', 'element_set_global'); +?> diff --git a/BSF/admin/element_set_unit.php b/BSF/admin/element_set_unit.php new file mode 100644 index 000000000..28b1cd828 --- /dev/null +++ b/BSF/admin/element_set_unit.php @@ -0,0 +1,274 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * Management of elements set. Elements can belong to a category or to the + * user caddie. + * + */ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die('Hacking attempt!'); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | unit mode form submission | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['submit'])) +{ + $collection = explode(',', $_POST['element_ids']); + + $datas = array(); + + $query = ' +SELECT id, date_creation + FROM '.IMAGES_TABLE.' + WHERE id IN ('.implode(',', $collection).') +;'; + $result = pwg_query($query); + + while ($row = mysql_fetch_array($result)) + { + $data = array(); + + $data{'id'} = $row['id']; + $data{'name'} = $_POST['name-'.$row['id']]; + $data{'author'} = $_POST['author-'.$row['id']]; + + foreach (array('name', 'author') as $field) + { + if (!empty($_POST[$field.'-'.$row['id']])) + { + $data{$field} = strip_tags($_POST[$field.'-'.$row['id']]); + } + } + + if ($conf['allow_html_descriptions']) + { + $data{'comment'} = @$_POST['description-'.$row['id']]; + } + else + { + $data{'comment'} = strip_tags(@$_POST['description-'.$row['id']]); + } + + if (isset($_POST['date_creation_action-'.$row['id']])) + { + if ('set' == $_POST['date_creation_action-'.$row['id']]) + { + $data{'date_creation'} = + $_POST['date_creation_year-'.$row['id']] + .'-'.$_POST['date_creation_month-'.$row['id']] + .'-'.$_POST['date_creation_day-'.$row['id']]; + } + else if ('unset' == $_POST['date_creation_action-'.$row['id']]) + { + $data{'date_creation'} = ''; + } + } + else + { + $data{'date_creation'} = $row['date_creation']; + } + + array_push($datas, $data); + + // tags management + if (isset($_POST[ 'tags-'.$row['id'] ])) + { + set_tags($_POST[ 'tags-'.$row['id'] ], $row['id']); + } + } + + mass_updates( + IMAGES_TABLE, + array( + 'primary' => array('id'), + 'update' => array('name','author','comment','date_creation') + ), + $datas + ); + + array_push($page['infos'], l10n('Picture informations updated')); +} + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filenames( + array('element_set_unit' => 'admin/element_set_unit.tpl')); + +$base_url = PHPWG_ROOT_PATH.'admin.php'; + +$month_list = $lang['month']; +$month_list[0]='------------'; +ksort($month_list); + +$template->assign( + array( + 'CATEGORIES_NAV'=>$page['title'], + + 'U_ELEMENTS_PAGE' + =>$base_url.get_query_string_diff(array('display','start')), + + 'U_GLOBAL_MODE' + => + $base_url + .get_query_string_diff(array('mode','display')) + .'&mode=global', + + 'F_ACTION'=>$base_url.get_query_string_diff(array()), + + 'month_list' => $month_list + ) + ); + +// +-----------------------------------------------------------------------+ +// | global mode thumbnails | +// +-----------------------------------------------------------------------+ + +// how many items to display on this page +if (!empty($_GET['display'])) +{ + if ('all' == $_GET['display']) + { + $page['nb_images'] = count($page['cat_elements_id']); + } + else + { + $page['nb_images'] = intval($_GET['display']); + } +} +else +{ + $page['nb_images'] = 5; +} + + + +if (count($page['cat_elements_id']) > 0) +{ + $nav_bar = create_navigation_bar( + $base_url.get_query_string_diff(array('start')), + count($page['cat_elements_id']), + $page['start'], + $page['nb_images'] + ); + $template->assign(array('NAV_BAR' => $nav_bar)); + + // tags + $all_tags = get_all_tags(); + + $element_ids = array(); + + $query = ' +SELECT id,path,tn_ext,name,date_creation,comment,author,file + FROM '.IMAGES_TABLE.' + WHERE id IN ('.implode(',', $page['cat_elements_id']).') + '.$conf['order_by'].' + LIMIT '.$page['start'].', '.$page['nb_images'].' +;'; + $result = pwg_query($query); + + while ($row = mysql_fetch_assoc($result)) + { + // echo '<pre>'; print_r($row); echo '</pre>'; + array_push($element_ids, $row['id']); + + $src = get_thumbnail_url($row); + + $query = ' +SELECT tag_id + FROM '.IMAGE_TAG_TABLE.' + WHERE image_id = '.$row['id'].' +;'; + $selected_tags = array_from_query($query, 'tag_id'); + + // creation date + if (!empty($row['date_creation'])) + { + list($year,$month,$day) = explode('-', $row['date_creation']); + } + else + { + list($year,$month,$day) = array('',0,0); + } + + if (count($all_tags) > 0) + { + $tag_selection = get_html_tag_selection( + $all_tags, + 'tags-'.$row['id'], + $selected_tags + ); + } + else + { + $tag_selection = + '<p>'. + l10n('No tag defined. Use Administration>Pictures>Tags'). + '</p>'; + } + + $template->append( + 'elements', + array( + 'ID' => $row['id'], + 'TN_SRC' => $src, + 'LEGEND' => + !empty($row['name']) ? + $row['name'] : get_name_from_file($row['file']), + 'U_EDIT' => + PHPWG_ROOT_PATH.'admin.php?page=picture_modify'. + '&image_id='.$row['id'], + 'NAME' => @$row['name'], + 'AUTHOR' => @$row['author'], + 'DESCRIPTION' => @$row['comment'], + 'DATE_CREATION_YEAR' => $year, + 'DATE_CREATION_MONTH' => (int)$month, + 'DATE_CREATION_DAY' => (int)$day, + + 'TAG_SELECTION' => $tag_selection, + ) + ); + } + + $template->assign('ELEMENT_IDS', implode(',', $element_ids)); +} + +// +-----------------------------------------------------------------------+ +// | sending html code | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('ADMIN_CONTENT', 'element_set_unit'); +?>
\ No newline at end of file diff --git a/BSF/admin/group_list.php b/BSF/admin/group_list.php new file mode 100644 index 000000000..323674bc1 --- /dev/null +++ b/BSF/admin/group_list.php @@ -0,0 +1,207 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if( !defined("PHPWG_ROOT_PATH") ) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | delete a group | +// +-----------------------------------------------------------------------+ + +if (isset($_GET['delete']) and is_numeric($_GET['delete']) and !is_adviser()) +{ + // destruction of the access linked to the group + $query = ' +DELETE + FROM '.GROUP_ACCESS_TABLE.' + WHERE group_id = '.$_GET['delete'].' +;'; + pwg_query($query); + + // destruction of the users links for this group + $query = ' +DELETE + FROM '.USER_GROUP_TABLE.' + WHERE group_id = '.$_GET['delete'].' +;'; + pwg_query($query); + + $query = ' +SELECT name + FROM '.GROUPS_TABLE.' + WHERE id = '.$_GET['delete'].' +;'; + list($groupname) = mysql_fetch_row(pwg_query($query)); + + // destruction of the group + $query = ' +DELETE + FROM '.GROUPS_TABLE.' + WHERE id = '.$_GET['delete'].' +;'; + pwg_query($query); + + array_push( + $page['infos'], + sprintf(l10n('group "%s" deleted'), $groupname) + ); +} + +// +-----------------------------------------------------------------------+ +// | add a group | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['submit_add']) and !is_adviser()) +{ + if (empty($_POST['groupname'])) + { + array_push($page['errors'], l10n('group_add_error1')); + } + if (count($page['errors']) == 0) + { + // is the group not already existing ? + $query = ' +SELECT COUNT(*) + FROM '.GROUPS_TABLE.' + WHERE name = \''.$_POST['groupname'].'\' +;'; + list($count) = mysql_fetch_row(pwg_query($query)); + if ($count != 0) + { + array_push($page['errors'], l10n('group_add_error2')); + } + } + if (count($page['errors']) == 0) + { + // creating the group + $query = ' +INSERT INTO '.GROUPS_TABLE.' + (name) + VALUES + (\''.mysql_escape_string($_POST['groupname']).'\') +;'; + pwg_query($query); + + array_push( + $page['infos'], + sprintf(l10n('group "%s" added'), $_POST['groupname']) + ); + } +} + +// +-----------------------------------------------------------------------+ +// | toggle is default group property | +// +-----------------------------------------------------------------------+ + +if (isset($_GET['toggle_is_default']) and is_numeric($_GET['toggle_is_default']) and !is_adviser()) +{ + $query = ' +SELECT name, is_default + FROM '.GROUPS_TABLE.' + WHERE id = '.$_GET['toggle_is_default'].' +;'; + list($groupname, $is_default) = mysql_fetch_row(pwg_query($query)); + + // update of the group + $query = ' +UPDATE '.GROUPS_TABLE.' + SET is_default = \''.boolean_to_string(!get_boolean($is_default)).'\' + WHERE id = '.$_GET['toggle_is_default'].' +;'; + pwg_query($query); + + array_push( + $page['infos'], + sprintf(l10n('group "%s" updated'), $groupname) + ); +} + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filenames(array('group_list' => 'admin/group_list.tpl')); + +$template->assign( + array( + 'F_ADD_ACTION' => get_root_url().'admin.php?page=group_list', + 'U_HELP' => get_root_url().'popuphelp.php?page=group_list', + ) + ); + +// +-----------------------------------------------------------------------+ +// | group list | +// +-----------------------------------------------------------------------+ + +$query = ' +SELECT id, name, is_default + FROM '.GROUPS_TABLE.' + ORDER BY name ASC +;'; +$result = pwg_query($query); + +$admin_url = get_root_url().'admin.php?page='; +$perm_url = $admin_url.'group_perm&group_id='; +$del_url = $admin_url.'group_list&delete='; +$members_url = $admin_url.'user_list&group='; +$toggle_is_default_url = $admin_url.'group_list&toggle_is_default='; + +while ($row = mysql_fetch_array($result)) +{ + $query = ' +SELECT COUNT(*) + FROM '.USER_GROUP_TABLE.' + WHERE group_id = '.$row['id'].' +;'; + list($counter) = mysql_fetch_row(pwg_query($query)); + + $template->append( + 'groups', + array( + 'NAME' => $row['name'], + 'IS_DEFAULT' => (get_boolean($row['is_default']) ? ' ['.l10n('is_default_group').']' : ''), + 'MEMBERS' => l10n_dec('%d member', '%d members', $counter), + 'U_MEMBERS' => $members_url.$row['id'], + 'U_DELETE' => $del_url.$row['id'], + 'U_PERM' => $perm_url.$row['id'], + 'U_ISDEFAULT' => $toggle_is_default_url.$row['id'] + ) + ); +} + +// +-----------------------------------------------------------------------+ +// | sending html code | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('ADMIN_CONTENT', 'group_list'); + +?> diff --git a/BSF/admin/group_perm.php b/BSF/admin/group_perm.php new file mode 100644 index 000000000..430730001 --- /dev/null +++ b/BSF/admin/group_perm.php @@ -0,0 +1,185 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if( !defined("PHPWG_ROOT_PATH") ) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | variables init | +// +-----------------------------------------------------------------------+ + +if (isset($_GET['group_id']) and is_numeric($_GET['group_id'])) +{ + $page['group'] = $_GET['group_id']; +} +else +{ + die('group_id URL parameter is missing'); +} + +// +-----------------------------------------------------------------------+ +// | updates | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['falsify']) + and isset($_POST['cat_true']) + and count($_POST['cat_true']) > 0) +{ + // if you forbid access to a category, all sub-categories become + // automatically forbidden + $subcats = get_subcat_ids($_POST['cat_true']); + $query = ' +DELETE + FROM '.GROUP_ACCESS_TABLE.' + WHERE group_id = '.$page['group'].' + AND cat_id IN ('.implode(',', $subcats).') +;'; + pwg_query($query); +} +else if (isset($_POST['trueify']) + and isset($_POST['cat_false']) + and count($_POST['cat_false']) > 0) +{ + $uppercats = get_uppercat_ids($_POST['cat_false']); + $private_uppercats = array(); + + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE id IN ('.implode(',', $uppercats).') + AND status = \'private\' +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($private_uppercats, $row['id']); + } + + // retrying to authorize a category which is already authorized may cause + // an error (in SQL statement), so we need to know which categories are + // accesible + $authorized_ids = array(); + + $query = ' +SELECT cat_id + FROM '.GROUP_ACCESS_TABLE.' + WHERE group_id = '.$page['group'].' +;'; + $result = pwg_query($query); + + while ($row = mysql_fetch_array($result)) + { + array_push($authorized_ids, $row['cat_id']); + } + + $inserts = array(); + $to_autorize_ids = array_diff($private_uppercats, $authorized_ids); + foreach ($to_autorize_ids as $to_autorize_id) + { + array_push( + $inserts, + array( + 'group_id' => $page['group'], + 'cat_id' => $to_autorize_id + ) + ); + } + + mass_inserts(GROUP_ACCESS_TABLE, array('group_id','cat_id'), $inserts); +} + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filenames( + array( + 'group_perm' => 'admin/group_perm.tpl', + 'double_select' => 'admin/double_select.tpl' + ) + ); + +$template->assign( + array( + 'TITLE' => + sprintf( + l10n('Manage permissions for group "%s"'), + get_groupname($page['group'] + ) + ), + 'L_CAT_OPTIONS_TRUE'=>l10n('authorized'), + 'L_CAT_OPTIONS_FALSE'=>l10n('forbidden'), + + 'F_ACTION' => + get_root_url(). + 'admin.php?page=group_perm&group_id='. + $page['group'] + ) + ); + +// only private categories are listed +$query_true = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' INNER JOIN '.GROUP_ACCESS_TABLE.' ON cat_id = id + WHERE status = \'private\' + AND group_id = '.$page['group'].' +;'; +display_select_cat_wrapper($query_true,array(),'category_option_true'); + +$result = pwg_query($query_true); +$authorized_ids = array(); +while ($row = mysql_fetch_array($result)) +{ + array_push($authorized_ids, $row['id']); +} + +$query_false = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE status = \'private\''; +if (count($authorized_ids) > 0) +{ + $query_false.= ' + AND id NOT IN ('.implode(',', $authorized_ids).')'; +} +$query_false.= ' +;'; +display_select_cat_wrapper($query_false,array(),'category_option_false'); + +// +-----------------------------------------------------------------------+ +// | html code display | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('DOUBLE_SELECT', 'double_select'); +$template->assign_var_from_handle('ADMIN_CONTENT', 'group_perm'); + +?> diff --git a/BSF/admin/help.php b/BSF/admin/help.php new file mode 100644 index 000000000..051a10073 --- /dev/null +++ b/BSF/admin/help.php @@ -0,0 +1,32 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +$template->assign('ADMIN_CONTENT', load_language('help.html','','',true) ); +?> diff --git a/BSF/admin/history.php b/BSF/admin/history.php new file mode 100644 index 000000000..c064e7516 --- /dev/null +++ b/BSF/admin/history.php @@ -0,0 +1,685 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * Display filtered history lines + */ + +// +-----------------------------------------------------------------------+ +// | functions | +// +-----------------------------------------------------------------------+ + +// +-----------------------------------------------------------------------+ +// | initialization | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die('Hacking attempt!'); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); +include_once(PHPWG_ROOT_PATH.'admin/include/functions_history.inc.php'); + +if (isset($_GET['start']) and is_numeric($_GET['start'])) +{ + $page['start'] = $_GET['start']; +} +else +{ + $page['start'] = 0; +} + +$types = array('none', 'picture', 'high', 'other'); +$display_thumbnails = array('no_display_thumbnail', 'display_thumbnail_classic', 'display_thumbnail_hoverbox'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ + +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | Build search criteria and redirect to results | +// +-----------------------------------------------------------------------+ + +$page['errors'] = array(); +$search = array(); + +if (isset($_POST['submit'])) +{ + // dates + if (!empty($_POST['start_year'])) + { + $search['fields']['date-after'] = sprintf( + '%d-%02d-%02d', + $_POST['start_year'], + $_POST['start_month'], + $_POST['start_day'] + ); + } + + if (!empty($_POST['end_year'])) + { + $search['fields']['date-before'] = sprintf( + '%d-%02d-%02d', + $_POST['end_year'], + $_POST['end_month'], + $_POST['end_day'] + ); + } + + if (empty($_POST['types'])) + { + $search['fields']['types'] = $types; + } + else + { + $search['fields']['types'] = $_POST['types']; + } + + $search['fields']['user'] = $_POST['user']; + + if (!empty($_POST['image_id'])) + { + $search['fields']['image_id'] = intval($_POST['image_id']); + } + + if (!empty($_POST['filename'])) + { + $search['fields']['filename'] = str_replace( + '*', + '%', + mysql_escape_string($_POST['filename']) + ); + } + + $search['fields']['display_thumbnail'] = $_POST['display_thumbnail']; + // Display choise are also save to one cookie + pwg_set_cookie_var('history_display_thumbnail', $_POST['display_thumbnail']); + + // TODO manage inconsistency of having $_POST['image_id'] and + // $_POST['filename'] simultaneously + + // echo '<pre>'; print_r($search); echo '</pre>'; + + if (!empty($search)) + { + // register search rules in database, then they will be available on + // thumbnails page and picture page. + $query =' +INSERT INTO '.SEARCH_TABLE.' + (rules) + VALUES + (\''.serialize($search).'\') +;'; + pwg_query($query); + + $search_id = mysql_insert_id(); + + redirect( + PHPWG_ROOT_PATH.'admin.php?page=history&search_id='.$search_id + ); + } + else + { + array_push($page['errors'], l10n('search_one_clause_at_least')); + } +} + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filename('history', 'admin/history.tpl'); + +// TabSheet initialization +history_tabsheet(); + +$template->assign( + array( + 'U_HELP' => PHPWG_ROOT_PATH.'popuphelp.php?page=history', + 'F_ACTION' => get_root_url().'admin.php?page=history' + ) + ); + +// +-----------------------------------------------------------------------+ +// | history lines | +// +-----------------------------------------------------------------------+ + +if (isset($_GET['search_id']) + and $page['search_id'] = (int)$_GET['search_id']) +{ + // what are the lines to display in reality ? + $query = ' +SELECT rules + FROM '.SEARCH_TABLE.' + WHERE id = '.$page['search_id'].' +;'; + list($serialized_rules) = mysql_fetch_row(pwg_query($query)); + + $page['search'] = unserialize($serialized_rules); + + if (isset($_GET['user_id'])) + { + if (!is_numeric($_GET['user_id'])) + { + die('user_id GET parameter must be an integer value'); + } + + $page['search']['fields']['user'] = $_GET['user_id']; + + $query =' +INSERT INTO '.SEARCH_TABLE.' + (rules) + VALUES + (\''.serialize($page['search']).'\') +;'; + pwg_query($query); + + $search_id = mysql_insert_id(); + + redirect( + PHPWG_ROOT_PATH.'admin.php?page=history&search_id='.$search_id + ); + } + + $data = trigger_event('get_history', array(), $page['search'], $types); + usort($data, 'history_compare'); + + $page['nb_lines'] = count($data); + + $history_lines = array(); + $user_ids = array(); + $username_of = array(); + $category_ids = array(); + $image_ids = array(); + $tag_ids = array(); + + foreach ($data as $row) + { + $user_ids[$row['user_id']] = 1; + + if (isset($row['category_id'])) + { + $category_ids[$row['category_id']] = 1; + } + + if (isset($row['image_id'])) + { + $image_ids[$row['image_id']] = 1; + } + + if (isset($row['tag_ids'])) + { + foreach (explode(',', $row['tag_ids']) as $tag_id) + { + array_push($tag_ids, $tag_id); + } + } + + array_push( + $history_lines, + $row + ); + } + + // prepare reference data (users, tags, categories...) + if (count($user_ids) > 0) + { + $query = ' +SELECT '.$conf['user_fields']['id'].' AS id + , '.$conf['user_fields']['username'].' AS username + FROM '.USERS_TABLE.' + WHERE id IN ('.implode(',', array_keys($user_ids)).') +;'; + $result = pwg_query($query); + + $username_of = array(); + while ($row = mysql_fetch_array($result)) + { + $username_of[$row['id']] = $row['username']; + } + } + + if (count($category_ids) > 0) + { + $query = ' +SELECT id, uppercats + FROM '.CATEGORIES_TABLE.' + WHERE id IN ('.implode(',', array_keys($category_ids)).') +;'; + $uppercats_of = simple_hash_from_query($query, 'id', 'uppercats'); + + $name_of_category = array(); + + foreach ($uppercats_of as $category_id => $uppercats) + { + $name_of_category[$category_id] = get_cat_display_name_cache( + $uppercats + ); + } + } + + if (count($image_ids) > 0) + { + $query = ' +SELECT + id, + IF(name IS NULL, file, name) AS label, + filesize, + high_filesize, + file, + path, + tn_ext + FROM '.IMAGES_TABLE.' + WHERE id IN ('.implode(',', array_keys($image_ids)).') +;'; + // $label_of_image = simple_hash_from_query($query, 'id', 'label'); + $label_of_image = array(); + $filesize_of_image = array(); + $high_filesize_of_image = array(); + $file_of_image = array(); + $path_of_image = array(); + $tn_ext_of_image = array(); + + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $label_of_image[ $row['id'] ] = $row['label']; + + if (isset($row['filesize'])) + { + $filesize_of_image[ $row['id'] ] = $row['filesize']; + } + + if (isset($row['high_filesize'])) + { + $high_filesize_of_image[ $row['id'] ] = $row['high_filesize']; + } + + $file_of_image[ $row['id'] ] = $row['file']; + $path_of_image[ $row['id'] ] = $row['path']; + $tn_ext_of_image[ $row['id'] ] = $row['tn_ext']; + } + + // echo '<pre>'; print_r($high_filesize_of_image); echo '</pre>'; + } + + 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 = mysql_fetch_array($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.= ' <a href="'; + $user_string.= PHPWG_ROOT_PATH.'admin.php?page=history'; + $user_string.= '&search_id='.$page['search_id']; + $user_string.= '&user_id='.$line['user_id']; + $user_string.= '">+</a>'; + + $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= '<a href="'.$picture_url.'">'.$image_title.'</a>'; + break; + } + case 'display_thumbnail_classic': + { + $image_string = + '<a class="thumbnail" href="'.$picture_url.'">' + .'<span><img src="'.get_thumbnail_url($element) + .'" alt="'.$image_title.'" title="'.$image_title.'">' + .'</span></a>'; + break; + } + case 'display_thumbnail_hoverbox': + { + $image_string = + '<a class="over" href="'.$picture_url.'">' + .'<span><img src="'.get_thumbnail_url($element) + .'" alt="'.$image_title.'" title="'.$image_title.'">' + .'</span>'.$image_title.'</a>'; + 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.' <a href="'; + $member_string.= get_root_url().'admin.php?page=history'; + $member_string.= '&search_id='.$page['search_id']; + $member_string.= '&user_id='.$user_id; + $member_string.= '">+</a>'; + + $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('NAV_BAR', $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('history_display_thumbnail', $display_thumbnails[2]); +} + + +$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( + array( + 'display_thumbnail_values' => $display_thumbnails, + 'display_thumbnail_selected' => array($form['display_thumbnail']), + ) + ); + +// +-----------------------------------------------------------------------+ +// | html code display | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('ADMIN_CONTENT', 'history'); +?>
\ No newline at end of file diff --git a/BSF/admin/images/index.php b/BSF/admin/images/index.php new file mode 100644 index 000000000..c15b15795 --- /dev/null +++ b/BSF/admin/images/index.php @@ -0,0 +1,30 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// Recursive call +$url = '../'; +header( 'Request-URI: '.$url ); +header( 'Content-Location: '.$url ); +header( 'Location: '.$url ); +exit(); +?> diff --git a/BSF/admin/include/c13y_internal.class.php b/BSF/admin/include/c13y_internal.class.php new file mode 100644 index 000000000..2e2c309b5 --- /dev/null +++ b/BSF/admin/include/c13y_internal.class.php @@ -0,0 +1,249 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +class c13y_internal +{ + function c13y_internal() + { + add_event_handler('list_check_integrity', array(&$this, 'c13y_version')); + add_event_handler('list_check_integrity', array(&$this, 'c13y_exif')); + add_event_handler('list_check_integrity', array(&$this, 'c13y_user')); + } + + /** + * Check version + * + * @param c13y object + * @return void + */ + function c13y_version($c13y) + { + $check_list = array(); + + $check_list[] = array('type' => 'PHP', 'current' => phpversion(), 'required' => REQUIRED_PHP_VERSION); + + list($mysql_version) = mysql_fetch_row(pwg_query('SELECT VERSION();')); + $check_list[] = array('type' => 'MySQL', 'current' => $mysql_version, 'required' => REQUIRED_MYSQL_VERSION); + + foreach ($check_list as $elem) + { + if (version_compare($elem['current'], $elem['required'], '<')) + { + $c13y->add_anomaly( + sprintf(l10n('c13y_version_anomaly'), $elem['type'], $elem['current'], $elem['required']), + null, + null, + l10n('c13y_version_correction') + .'<BR />'. + $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('c13y_exif_anomaly'), '$conf[\''.$value.'\']'), + null, + null, + sprintf(l10n('c13y_exif_correction'), '$conf[\''.$value.'\']') + .'<BR />'. + $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' => 'c13y_guest_non_existent', + 'l10n_bad_status' => 'c13y_bad_guest_status'); + + if ($conf['guest_id'] != $conf['default_user_id']) + { + $c13y_users[$conf['default_user_id']] = array( + 'password' => null, + 'l10n_non_existent' => 'c13y_default_non_existent'); + } + + $c13y_users[$conf['webmaster_id']] = array( + 'status' => 'webmaster', + 'l10n_non_existent' => 'c13y_webmaster_non_existent', + 'l10n_bad_status' => 'c13y_bad_webmaster_status'); + + $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 = mysql_fetch_array($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' => $name, + 'password' => $password + ), + ); + mass_inserts(USERS_TABLE, array_keys($inserts[0]), $inserts); + + create_user_infos($id); + + $page['infos'][] = sprintf(l10n('c13y_user_created'), $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('c13y_user_status_updated'), get_username($id)); + + $result = true; + } + break; + } + } + + return $result; + } +} + +?> diff --git a/BSF/admin/include/check_integrity.class.php b/BSF/admin/include/check_integrity.class.php new file mode 100644 index 000000000..b6f3ddd6a --- /dev/null +++ b/BSF/admin/include/check_integrity.class.php @@ -0,0 +1,345 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +class check_integrity +{ + var $ignore_list; + var $retrieve_list; + var $build_ignore_list; + + function check_integrity() + { + $this->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('c13y_anomaly_count', 'c13y_anomalies_count', + 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('c13y_anomaly_corrected_count', 'c13y_anomalies_corrected_count', + $corrected_count); + } + if ($not_corrected_count > 0) + { + $page['errors'][] = + l10n_dec('c13y_anomaly_not_corrected_count', 'c13y_anomalies_not_corrected_count', + $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('c13y_anomaly_ignored_count', 'c13y_anomalies_ignored_count', + $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' => 'admin/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 = '<a href="%s" onclick="window.open(this.href, \'\'); return false;">%s</a>'; + return + sprintf + ( + l10n('c13y_more_info'), + sprintf($link_fmt, $pwg_links['FORUM'], l10n('c13y_more_info_forum')), + sprintf($link_fmt, $pwg_links['WIKI'], l10n('c13y_more_info_wiki')) + ); + } + +} + +?> diff --git a/BSF/admin/include/functions.php b/BSF/admin/include/functions.php new file mode 100644 index 000000000..328a36ab7 --- /dev/null +++ b/BSF/admin/include/functions.php @@ -0,0 +1,1872 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +include(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php'); + + +// The function delete_site deletes a site and call the function +// delete_categories for each primary category of the site +function delete_site( $id ) +{ + // destruction of the categories of the site + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE site_id = '.$id.' +;'; + $result = pwg_query($query); + $category_ids = array(); + while ($row = mysql_fetch_array($result)) + { + array_push($category_ids, $row['id']); + } + delete_categories($category_ids); + + // destruction of the site + $query = ' +DELETE FROM '.SITES_TABLE.' + WHERE id = '.$id.' +;'; + pwg_query($query); +} + + +// The function delete_categories deletes the categories identified by the +// (numeric) key of the array $ids. It also deletes (in the database) : +// - all the elements of the category (delete_elements, see further) +// - all the links between elements and this category +// - all the restrictions linked to the category +// The function works recursively. +function delete_categories($ids) +{ + if (count($ids) == 0) + { + return; + } + + // add sub-category ids to the given ids : if a category is deleted, all + // sub-categories must be so + $ids = get_subcat_ids($ids); + + // destruction of all the related elements + $query = ' +SELECT id + FROM '.IMAGES_TABLE.' + WHERE storage_category_id IN ( +'.wordwrap(implode(', ', $ids), 80, "\n").') +;'; + $result = pwg_query($query); + $element_ids = array(); + while ($row = mysql_fetch_array($result)) + { + array_push($element_ids, $row['id']); + } + delete_elements($element_ids); + + // destruction of the links between images and this category + $query = ' +DELETE FROM '.IMAGE_CATEGORY_TABLE.' + WHERE category_id IN ( +'.wordwrap(implode(', ', $ids), 80, "\n").') +;'; + pwg_query($query); + + // destruction of the access linked to the category + $query = ' +DELETE FROM '.USER_ACCESS_TABLE.' + WHERE cat_id IN ( +'.wordwrap(implode(', ', $ids), 80, "\n").') +;'; + pwg_query($query); + + $query = ' +DELETE FROM '.GROUP_ACCESS_TABLE.' + WHERE cat_id IN ( +'.wordwrap(implode(', ', $ids), 80, "\n").') +;'; + pwg_query($query); + + // destruction of the category + $query = ' +DELETE FROM '.CATEGORIES_TABLE.' + WHERE id IN ( +'.wordwrap(implode(', ', $ids), 80, "\n").') +;'; + pwg_query($query); + + $query=' +DELETE FROM '.OLD_PERMALINKS_TABLE.' + WHERE cat_id IN ('.implode(',',$ids).')'; + pwg_query($query); + + trigger_action('delete_categories', $ids); +} + +// The function delete_elements deletes the elements identified by the +// (numeric) values of the array $ids. It also deletes (in the database) : +// - all the comments related to elements +// - all the links between categories and elements +// - all the favorites associated to elements +function delete_elements($ids) +{ + if (count($ids) == 0) + { + return; + } + + // destruction of the comments on the image + $query = ' +DELETE FROM '.COMMENTS_TABLE.' + WHERE image_id IN ( +'.wordwrap(implode(', ', $ids), 80, "\n").') +;'; + pwg_query($query); + + // destruction of the links between images and this category + $query = ' +DELETE FROM '.IMAGE_CATEGORY_TABLE.' + WHERE image_id IN ( +'.wordwrap(implode(', ', $ids), 80, "\n").') +;'; + pwg_query($query); + + // destruction of the links between images and tags + $query = ' +DELETE FROM '.IMAGE_TAG_TABLE.' + WHERE image_id IN ( +'.wordwrap(implode(', ', $ids), 80, "\n").') +;'; + pwg_query($query); + + // destruction of the favorites associated with the picture + $query = ' +DELETE FROM '.FAVORITES_TABLE.' + WHERE image_id IN ( +'.wordwrap(implode(', ', $ids), 80, "\n").') +;'; + pwg_query($query); + + // destruction of the rates associated to this element + $query = ' +DELETE FROM '.RATE_TABLE.' + WHERE element_id IN ( +'.wordwrap(implode(', ', $ids), 80, "\n").') +;'; + pwg_query($query); + + // destruction of the rates associated to this element + $query = ' +DELETE FROM '.CADDIE_TABLE.' + WHERE element_id IN ( +'.wordwrap(implode(', ', $ids), 80, "\n").') +;'; + pwg_query($query); + + // destruction of the image + $query = ' +DELETE FROM '.IMAGES_TABLE.' + WHERE id IN ( +'.wordwrap(implode(', ', $ids), 80, "\n").') +;'; + pwg_query($query); + + 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)); + } + } + } + } + } + + return $dirs; +} + +/** + * inserts multiple lines in a table + * + * @param string table_name + * @param array dbfields + * @param array inserts + * @return void + */ +function mass_inserts($table_name, $dbfields, $datas) +{ + if (count($datas) != 0) + { + $first = true; + + $query = 'SHOW VARIABLES LIKE \'max_allowed_packet\';'; + list(, $packet_size) = mysql_fetch_row(pwg_query($query)); + $packet_size = $packet_size - 2000; // The last list of values MUST not exceed 2000 character*/ + $query = ''; + + foreach ($datas as $insert) + { + if (strlen($query) >= $packet_size) + { + $query .= ' +;'; + pwg_query($query); + $first = true; + } + + if ($first) + { + $query = ' +INSERT INTO '.$table_name.' + ('.implode(',', $dbfields).') + VALUES'; + $first = false; + } + else + { + $query .= ' + , '; + } + + $query .= '('; + foreach ($dbfields as $field_id => $dbfield) + { + if ($field_id > 0) + { + $query .= ','; + } + + if (!isset($insert[$dbfield]) or $insert[$dbfield] === '') + { + $query .= 'NULL'; + } + else + { + $query .= "'".$insert[$dbfield]."'"; + } + } + $query .= ')'; + } + + $query .= ' +;'; + pwg_query($query); + } +} + +/** + * updates multiple lines in a table + * + * @param string table_name + * @param array dbfields + * @param array datas + * @return void + */ +function mass_updates($tablename, $dbfields, $datas) +{ + if (count($datas) != 0) + { + // depending on the MySQL version, we use the multi table update or N + // update queries + if (count($datas) < 10 or version_compare(mysql_get_server_info(), '4.0.4') < 0) + { + // MySQL is prior to version 4.0.4, multi table update feature is not + // available + foreach ($datas as $data) + { + $query = ' +UPDATE '.$tablename.' + SET '; + $is_first = true; + foreach ($dbfields['update'] as $key) + { + if (!$is_first) + { + $query.= ",\n "; + } + $query.= $key.' = '; + if (isset($data[$key]) and $data[$key] != '') + { + $query.= '\''.$data[$key].'\''; + } + else + { + $query.= 'NULL'; + } + $is_first = false; + } + $query.= ' + WHERE '; + + $is_first = true; + foreach ($dbfields['primary'] as $key) + { + if (!$is_first) + { + $query.= ' AND '; + } + if ( isset($data[$key]) ) + { + $query.= $key.' = \''.$data[$key].'\''; + } + else + { + $query.= $key.' IS NULL'; + } + $is_first = false; + } + $query.= ' +;'; + pwg_query($query); + } + } + else + { + // creation of the temporary table + $query = ' +SHOW FULL COLUMNS FROM '.$tablename.' +;'; + $result = pwg_query($query); + $columns = array(); + $all_fields = array_merge($dbfields['primary'], $dbfields['update']); + while ($row = mysql_fetch_array($result)) + { + if (in_array($row['Field'], $all_fields)) + { + $column = $row['Field']; + $column.= ' '.$row['Type']; + + $nullable = true; + if (!isset($row['Null']) or $row['Null'] == '' or $row['Null']=='NO') + { + $column.= ' NOT NULL'; + $nullable = false; + } + if (isset($row['Default'])) + { + $column.= " default '".$row['Default']."'"; + } + elseif ($nullable) + { + $column.= " default NULL"; + } + if (isset($row['Collation']) and $row['Collation'] != 'NULL') + { + $column.= " collate '".$row['Collation']."'"; + } + array_push($columns, $column); + } + } + + $temporary_tablename = $tablename.'_'.micro_seconds(); + + $query = ' + CREATE TABLE '.$temporary_tablename.' + ( + '.implode(",\n", $columns).', + UNIQUE KEY the_key ('.implode(',', $dbfields['primary']).') + ) +;'; + + pwg_query($query); + mass_inserts($temporary_tablename, $all_fields, $datas); + // update of images table by joining with temporary table + $query = ' +UPDATE '.$tablename.' AS t1, '.$temporary_tablename.' AS t2 + SET '. + implode( + "\n , ", + array_map( + create_function('$s', 'return "t1.$s = t2.$s";'), + $dbfields['update'] + ) + ).' + WHERE '. + implode( + "\n AND ", + array_map( + create_function('$s', 'return "t1.$s = t2.$s";'), + $dbfields['primary'] + ) + ).' + ;'; + pwg_query($query); + $query = ' +DROP TABLE '.$temporary_tablename.' +;'; + pwg_query($query); + } + } +} + +/** + * 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, if(id_uppercat is null,\'\',id_uppercat) AS 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 = mysql_fetch_array($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'))) + { + 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'))) + { + 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 = mysql_fetch_array($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 RAND() + LIMIT 0,1 +;'; + list($representative) = mysql_fetch_array(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 +;'; + $result = pwg_query($query); + $cat_dirs = array(); + while ($row = mysql_fetch_array($result)) + { + $cat_dirs[$row['id']] = $row['dir']; + } + + // caching galleries_url + $query = ' +SELECT id, galleries_url + FROM '.SITES_TABLE.' +;'; + $result = pwg_query($query); + $galleries_url = array(); + while ($row = mysql_fetch_array($result)) + { + $galleries_url[$row['id']] = $row['galleries_url']; + } + + // categories : id, site_id, uppercats + $categories = array(); + + $query = ' +SELECT id, uppercats, site_id + FROM '.CATEGORIES_TABLE.' + WHERE id IN ( +'.wordwrap(implode(', ', $cat_ids), 80, "\n").') +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($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.' +;'; + $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 = CONCAT(\''.$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 = mysql_fetch_array($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 = mysql_fetch_array($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) = mysql_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) = mysql_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('cat_error_name')); + } + + $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) = mysql_fetch_array(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 = mysql_fetch_array(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 = mysql_insert_id(); + + $query = ' +UPDATE + '.CATEGORIES_TABLE.' + SET uppercats = \''. + (isset($parent) ? $parent{'uppercats'}.',' : ''). + $inserted_id. + '\' + WHERE id = '.$inserted_id.' +;'; + pwg_query($query); + + return array( + 'info' => l10n('cat_virtual_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($tags) == 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] = mysql_insert_id(); + } + 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 + ); + } +} + +/** + * Do maintenance on all PWG tables + * + * @return nono + */ +function do_maintenance_all_tables() +{ + global $prefixeTable; + + $all_tables = array(); + + // List all tables + $query = 'SHOW TABLES LIKE \''.$prefixeTable.'%\';'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($all_tables, $row[0]); + } + + // Repair all tables + $query = 'REPAIR TABLE '.implode(', ', $all_tables).';'; + pwg_query($query); + + // Re-Order all tables + foreach ($all_tables as $table_name) + { + $all_primary_key = array(); + + $query = 'DESC '.$table_name.';'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + if ($row['Key'] == 'PRI') + { + array_push($all_primary_key, $row['Field']); + } + } + + if (count($all_primary_key) != 0) + { + $query = 'ALTER TABLE '.$table_name.' ORDER BY '.implode(', ', $all_primary_key).';'; + pwg_query($query); + } + } + + // Optimize all tables + $query = 'OPTIMIZE TABLE '.implode(', ', $all_tables).';'; + pwg_query($query); + +} + +/** + * 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); +} + +/** + * Create an XML file with Piwigo informations about a list of + * pictures. + * + * The goal of the export feature is to make easier the reading of + * informations related to pictures outside of Piwigo. + * + * @param array image_ids + */ +function export_pwg_data($image_ids) +{ + global $conf; + + if (count($image_ids) == 0) + { + return; + } + + $fp = fopen($conf['export_file'], 'w'); + $xml_string = '<export>'."\n"; + + $query = ' +SELECT tag_id, + image_id + FROM '.IMAGE_TAG_TABLE.' + WHERE image_id IN ('.implode(',', $image_ids).') +;'; + $result = pwg_query($query); + $tags_of = array(); + $all_tag_ids = array(); + $tag_name_of = array(); + + if (mysql_num_rows($result)) + { + while ($row = mysql_fetch_array($result)) + { + array_push($all_tag_ids, $row['tag_id']); + + if (!isset($tags_of[ $row['image_id'] ])) { + $tags_of[ $row['image_id'] ] = array(); + } + + array_push( + $tags_of[ $row['image_id'] ], + $row['tag_id'] + ); + } + + $all_tag_ids = array_unique($all_tag_ids); + + $query = ' +SELECT id, + name + FROM '.TAGS_TABLE.' + WHERE id IN ('.implode(',', $all_tag_ids).') +;'; + $result = pwg_query($query); + + while ($row = mysql_fetch_array($result)) + { + $tag_name_of[ $row['id'] ] = $row['name']; + } + } + + $query = ' +SELECT id, + path + FROM '.IMAGES_TABLE.' + WHERE id IN ('.implode(',', $image_ids).') +;'; + $result = pwg_query($query); + + while ($row = mysql_fetch_array($result)) + { + $xml_string.= " <photo>\n"; + $xml_string.= " <id>".$row['id']."</id>\n"; + $xml_string.= " <path>".$row['path']."</path>\n"; + + foreach ($tags_of[ $row['id'] ] as $tag_id) + { + $xml_string.= " <tag>".$tag_name_of[$tag_id]."</tag>\n"; + } + + $xml_string.= " </photo>\n"; + } + + $xml_string.= '</export>'; + fwrite($fp, $xml_string); + fclose($fp); +} + +/** + * Refer main Piwigo URLs (currently PHPWG_DOMAIN domain) + * + * @param void + * @return array like $conf['links'] + */ +function pwg_URL() +{ + global $lang_info; + $urls = array( + 'WIKI' => 'http://'.PHPWG_DOMAIN.'/doc/', + 'HOME' => 'http://'.PHPWG_DOMAIN.'/', + 'DEMO' => 'http://demo.'.PHPWG_DOMAIN.'/', + 'FORUM' => 'http://forum.'.PHPWG_DOMAIN.'/', + 'BUGS' => 'http://bugs.'.PHPWG_DOMAIN.'/', + 'EXTENSIONS' => 'http://'.PHPWG_DOMAIN.'/ext', + ); + if ( isset($lang_info['code']) and + in_array($lang_info['code'], array('fr','en')) ) + { /* current wiki languages are French or English */ + $urls['WIKI'] .= 'doku.php?id='.$lang_info['code'].':start'; + $urls['HOME'] .= '?lang='.$lang_info['code']; + } + return $urls; +} + +/** + * Invalidates cahed data (permissions and category counts) for all users. + */ +function invalidate_user_cache() +{ + $query = ' +UPDATE '.USER_CACHE_TABLE.' + SET need_update = \'true\' +;'; + pwg_query($query); + trigger_action('invalidate_user_cache'); +} + +/** + * 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 die('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; + } + $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; +} + +?>
\ No newline at end of file diff --git a/BSF/admin/include/functions_history.inc.php b/BSF/admin/include/functions_history.inc.php new file mode 100644 index 000000000..aa4a03fc8 --- /dev/null +++ b/BSF/admin/include/functions_history.inc.php @@ -0,0 +1,179 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php'); + +function history_tabsheet() +{ + global $page, $link_start; + + // TabSheet + $tabsheet = new tabsheet(); + // TabSheet initialization + $tabsheet->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 '<pre>'; print_r($search); echo '</pre>'; + + $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 '.$page['start'].', '.$conf['nb_logs_page'].' + + $result = pwg_query($query); + + while ($row = mysql_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'); + +?> diff --git a/BSF/admin/include/functions_metadata.php b/BSF/admin/include/functions_metadata.php new file mode 100644 index 000000000..e805aeba6 --- /dev/null +++ b/BSF/admin/include/functions_metadata.php @@ -0,0 +1,298 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +include_once(PHPWG_ROOT_PATH.'/include/functions_metadata.inc.php'); + +$page['datefields'] = array('date_creation', 'date_available'); + +function get_sync_iptc_data($file) +{ + global $conf, $page; + + $map = $conf['use_iptc_mapping']; + + $iptc = get_iptc_data($file, $map); + + foreach ($iptc as $pwg_key => $value) + { + if (in_array($pwg_key, $page['datefields'])) + { + 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, $page; + + $exif = get_exif_data($file, $conf['use_exif_mapping']); + + foreach ($exif as $pwg_key => $value) + { + if (in_array($pwg_key, $page['datefields'])) + { + 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").' +) +;'; + + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($has_high_images, $row['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 ($conf['use_iptc']) + { + $iptc = get_sync_iptc_data($file); + 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 + ); + } + + 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 REGEXP \'(^|,)'.$category_id.'(,|$)\' +'; + } + else + { + $query.= ' + AND id = '.$category_id.' +'; + } + } + $query.= ' +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($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 = mysql_fetch_array($result)) + { + $files[$row['id']] = $row['path']; + } + + return $files; +} +?>
\ No newline at end of file diff --git a/BSF/admin/include/functions_notification_by_mail.inc.php b/BSF/admin/include/functions_notification_by_mail.inc.php new file mode 100644 index 000000000..c7c9f1942 --- /dev/null +++ b/BSF/admin/include/functions_notification_by_mail.inc.php @@ -0,0 +1,522 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/* nbm_global_var */ +$env_nbm = array + ( + 'start_time' => 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) = mysql_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 = mysql_fetch_array($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('nbm_msg_mail_sent_to'); + $env_nbm['msg_error'] = l10n('nbm_msg_error_sending_email_to'); + } +} + +/* + * 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['template'] = $user['template']; + $nbm_user['theme'] = $user['theme']; + $env_nbm['mail_template'] = + get_mail_template($env_nbm['email_format'], + array('template' => $nbm_user['template'], 'theme' => $nbm_user['theme'])); + $env_nbm['mail_template']->set_filename('notification_by_mail', 'admin/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'], $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'], $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('nbm_msg_n_mail_not_send', 'nbm_msg_n_mails_not_send', $env_nbm['error_on_mail_count'])); + if ($env_nbm['sent_mail_count'] != 0) + array_push($page['infos'], l10n_dec('nbm_msg_n_mail_sent', 'nbm_msg_n_mails_sent', $env_nbm['sent_mail_count'])); + } + else + { + if ($env_nbm['sent_mail_count'] == 0) + array_push($page['infos'], l10n('nbm_no_mail_to_send')); + else + array_push($page['infos'], l10n_dec('nbm_msg_n_mail_sent', 'nbm_msg_n_mails_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' => $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('nbm_user_change_enabled_true'); + $msg_error = l10n('nbm_user_not_change_enabled_true'); + } + else + { + $msg_info = l10n('nbm_user_change_enabled_false'); + $msg_error = l10n('nbm_user_not_change_enabled_false'); + } + + 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('nbm_break_timeout_send_mail'); + + // 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('nbm_object_subscribe'): l10n('nbm_object_unsubscribe')); + + // 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( $section_action_by, true ); + + if (pwg_mail + ( + format_email($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'], + 'template' => $nbm_user['template'], + '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, $nbm_user['username'], $nbm_user['mail_address'])); + } + else + { + $error_on_updated_data_count += 1; + array_push($page['errors'], sprintf($msg_error, $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('nbm_user_change_enabled_updated_data_count', 'nbm_users_change_enabled_updated_data_count', $updated_data_count)); + if ($error_on_updated_data_count != 0) + { + array_push($page['errors'], + l10n_dec('nbm_user_change_enabled_error_on_updated_data_count', + 'nbm_users_change_enabled_error_on_updated_data_count', + $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); +} + +?> diff --git a/BSF/admin/include/functions_permalinks.php b/BSF/admin/include/functions_permalinks.php new file mode 100644 index 000000000..4b19f02e1 --- /dev/null +++ b/BSF/admin/include/functions_permalinks.php @@ -0,0 +1,204 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** returns a category id that corresponds to the given permalink (or null) + * @param string permalink + */ +function get_cat_id_from_permalink( $permalink ) +{ + $query =' +SELECT id FROM '.CATEGORIES_TABLE.' + WHERE permalink="'.$permalink.'"'; + $ids = array_from_query($query, 'id'); + if (!empty($ids)) + { + return $ids[0]; + } + return null; +} + +/** returns a category id that has used before this permalink (or null) + * @param string permalink + * @param boolean is_hit if true update the usage counters on the old permalinks + */ +function get_cat_id_from_old_permalink($permalink) +{ + $query=' +SELECT c.id + FROM '.OLD_PERMALINKS_TABLE.' op INNER JOIN '.CATEGORIES_TABLE.' c + ON op.cat_id=c.id + WHERE op.permalink="'.$permalink.'" + LIMIT 1'; + $result = pwg_query($query); + $cat_id = null; + if ( mysql_num_rows($result) ) + list( $cat_id ) = mysql_fetch_array($result); + return $cat_id; +} + + +/** deletes the permalink associated with a category + * returns true on success + * @param int cat_id the target category id + * @param boolean save if true, the current category-permalink association + * is saved in the old permalinks table in case external links hit it + */ +function delete_cat_permalink( $cat_id, $save ) +{ + global $page, $cache; + $query = ' +SELECT permalink + FROM '.CATEGORIES_TABLE.' + WHERE id="'.$cat_id.'" +;'; + $result = pwg_query($query); + if ( mysql_num_rows($result) ) + { + list($permalink) = mysql_fetch_array($result); + } + if ( !isset($permalink) ) + {// no permalink; nothing to do + return true; + } + if ($save) + { + $old_cat_id = get_cat_id_from_old_permalink($permalink); + if ( isset($old_cat_id) and $old_cat_id!=$cat_id ) + { + $page['errors'][] = + sprintf( + l10n('Permalink_%s_histo_used_by_%s'), + $permalink, $old_cat_id + ); + return false; + } + } + $query = ' +UPDATE '.CATEGORIES_TABLE.' + SET permalink=NULL + WHERE id='.$cat_id.' + LIMIT 1'; + pwg_query($query); + + unset( $cache['cat_names'] ); //force regeneration + if ($save) + { + if ( isset($old_cat_id) ) + { + $query = ' +UPDATE '.OLD_PERMALINKS_TABLE.' + SET date_deleted=NOW() + WHERE cat_id='.$cat_id.' AND permalink="'.$permalink.'"'; + } + else + { + $query = ' +INSERT INTO '.OLD_PERMALINKS_TABLE.' + (permalink, cat_id, date_deleted) +VALUES + ( "'.$permalink.'",'.$cat_id.',NOW() )'; + } + pwg_query( $query ); + } + return true; +} + +/** sets a new permalink for a category + * returns true on success + * @param int cat_id the target category id + * @param string permalink the new permalink + * @param boolean save if true, the current category-permalink association + * is saved in the old permalinks table in case external links hit it + */ +function set_cat_permalink( $cat_id, $permalink, $save ) +{ + global $page, $cache; + + $sanitized_permalink = preg_replace( '#[^a-zA-Z0-9_/-]#', '' ,$permalink); + $sanitized_permalink = trim($sanitized_permalink, '/'); + $sanitized_permalink = str_replace('//', '/', $sanitized_permalink); + if ( $sanitized_permalink != $permalink + or preg_match( '#^(\d)+(-.*)?$#', $permalink) ) + { + $page['errors'][] = l10n('Permalink_name_rule'); + return false; + } + + // check if the new permalink is actively used + $existing_cat_id = get_cat_id_from_permalink( $permalink ); + if ( isset($existing_cat_id) ) + { + if ( $existing_cat_id==$cat_id ) + {// no change required + return true; + } + else + { + $page['errors'][] = + sprintf( + l10n('Permalink %s is already used by category %s'), + $permalink, $existing_cat_id + ); + return false; + } + } + + // check if the new permalink was historically used + $old_cat_id = get_cat_id_from_old_permalink($permalink); + if ( isset($old_cat_id) and $old_cat_id!=$cat_id ) + { + $page['errors'][] = + sprintf( + l10n('Permalink_%s_histo_used_by_%s'), + $permalink, $old_cat_id + ); + return false; + } + + if ( !delete_cat_permalink($cat_id, $save ) ) + { + return false; + } + + if ( isset($old_cat_id) ) + {// the new permalink must not be active and old at the same time + assert( $old_cat_id==$cat_id ); + $query = ' +DELETE FROM '.OLD_PERMALINKS_TABLE.' + WHERE cat_id='.$old_cat_id.' AND permalink="'.$permalink.'"'; + pwg_query($query); + } + + $query = ' +UPDATE '.CATEGORIES_TABLE.' + SET permalink="'.$permalink.'" + WHERE id='.$cat_id.' + LIMIT 1'; + pwg_query($query); + + unset( $cache['cat_names'] ); //force regeneration + + return true; +} + +?> diff --git a/BSF/admin/include/functions_plugins.inc.php b/BSF/admin/include/functions_plugins.inc.php new file mode 100644 index 000000000..1395f34e0 --- /dev/null +++ b/BSF/admin/include/functions_plugins.inc.php @@ -0,0 +1,64 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * Retrieves an url for a plugin page. + * @param string file - php script full name + */ +function get_admin_plugin_menu_link($file) +{ + global $page; + $real_file = realpath($file); + $url = get_root_url().'admin.php?page=plugin'; + if (false!==$real_file) + { + $real_plugin_path = rtrim(realpath(PHPWG_PLUGINS_PATH), '\\/'); + $file = substr($real_file, strlen($real_plugin_path)+1); + $file = str_replace('\\', '/', $file);//Windows + $url .= '&section='.urlencode($file); + } + else if (isset($page['errors'])) + { + array_push($page['errors'], 'PLUGIN ERROR: "'.$file.'" is not a valid file'); + } + return $url; +} + +/** + * Set tabsheet for plugins pages. + * @param string selected page. + */ +function set_plugins_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('plugins_tab_list'), $link.'plugins_list'); + $tabsheet->add('plugins_update', l10n('plugins_tab_update'), $link.'plugins_update'); + $tabsheet->add('plugins_new', l10n('plugins_tab_new'), $link.'plugins_new'); + $tabsheet->select($selected); + $tabsheet->assign(); +} +?>
\ No newline at end of file diff --git a/BSF/admin/include/functions_upgrade.php b/BSF/admin/include/functions_upgrade.php new file mode 100644 index 000000000..7e9a93aef --- /dev/null +++ b/BSF/admin/include/functions_upgrade.php @@ -0,0 +1,98 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +function check_upgrade() +{ + // Is Piwigo already installed ? + if (!defined('PHPWG_IN_UPGRADE') or !PHPWG_IN_UPGRADE) + { + $message = 'Piwigo is not in upgrade mode. In include/mysql.inc.php, +insert line +<pre style="background-color:lightgray"> +define(\'PHPWG_IN_UPGRADE\', true); +</pre> +if you want to upgrade'; + die($message); + } +} + +// concerning upgrade, we use the default tables +function prepare_conf_upgrade() +{ + global $prefixeTable; + + // $conf is not used for users tables + // define cannot be re-defined + define('CATEGORIES_TABLE', $prefixeTable.'categories'); + define('COMMENTS_TABLE', $prefixeTable.'comments'); + define('CONFIG_TABLE', $prefixeTable.'config'); + define('FAVORITES_TABLE', $prefixeTable.'favorites'); + define('GROUP_ACCESS_TABLE', $prefixeTable.'group_access'); + define('GROUPS_TABLE', $prefixeTable.'groups'); + define('HISTORY_TABLE', $prefixeTable.'history'); + define('HISTORY_SUMMARY_TABLE', $prefixeTable.'history_summary'); + define('IMAGE_CATEGORY_TABLE', $prefixeTable.'image_category'); + define('IMAGES_TABLE', $prefixeTable.'images'); + define('SESSIONS_TABLE', $prefixeTable.'sessions'); + define('SITES_TABLE', $prefixeTable.'sites'); + define('USER_ACCESS_TABLE', $prefixeTable.'user_access'); + define('USER_GROUP_TABLE', $prefixeTable.'user_group'); + define('USERS_TABLE', $prefixeTable.'users'); + define('USER_INFOS_TABLE', $prefixeTable.'user_infos'); + define('USER_FEED_TABLE', $prefixeTable.'user_feed'); + define('WAITING_TABLE', $prefixeTable.'waiting'); + define('RATE_TABLE', $prefixeTable.'rate'); + define('USER_CACHE_TABLE', $prefixeTable.'user_cache'); + define('USER_CACHE_CATEGORIES_TABLE', $prefixeTable.'user_cache_categories'); + define('CADDIE_TABLE', $prefixeTable.'caddie'); + define('UPGRADE_TABLE', $prefixeTable.'upgrade'); + define('SEARCH_TABLE', $prefixeTable.'search'); + define('USER_MAIL_NOTIFICATION_TABLE', $prefixeTable.'user_mail_notification'); + define('TAGS_TABLE', $prefixeTable.'tags'); + define('IMAGE_TAG_TABLE', $prefixeTable.'image_tag'); + define('PLUGINS_TABLE', $prefixeTable.'plugins'); + define('WEB_SERVICES_ACCESS_TABLE', $prefixeTable.'ws_access'); + define('OLD_PERMALINKS_TABLE', $prefixeTable.'old_permalinks'); +} + +// Create empty local files to avoid log errors +function create_empty_local_files() +{ + $files = + array ( + PHPWG_ROOT_PATH . 'template-common/local-layout.css', + PHPWG_ROOT_PATH . 'template/yoga/local-layout.css' + ); + + foreach ($files as $path) + { + if (!file_exists ($path)) + { + $file = @fopen($path, "w"); + @fwrite($file , '/* You can modify this file */'); + @fclose($file); + } + } +} + +?> diff --git a/BSF/admin/include/functions_waiting.inc.php b/BSF/admin/include/functions_waiting.inc.php new file mode 100644 index 000000000..3e7c3d8b6 --- /dev/null +++ b/BSF/admin/include/functions_waiting.inc.php @@ -0,0 +1,41 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php'); + +function waiting_tabsheet() +{ + global $page, $link_start; + + // TabSheet + $tabsheet = new tabsheet(); + // TabSheet initialization + $tabsheet->add('comments', l10n('comments'), $link_start.'comments'); + $tabsheet->add('upload', l10n('Pictures'), $link_start.'upload'); + // TabSheet selection + $tabsheet->select($page['page']); + // Assign tabsheet to template + $tabsheet->assign(); +} + +?> diff --git a/BSF/admin/include/index.php b/BSF/admin/include/index.php new file mode 100644 index 000000000..c15b15795 --- /dev/null +++ b/BSF/admin/include/index.php @@ -0,0 +1,30 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// Recursive call +$url = '../'; +header( 'Request-URI: '.$url ); +header( 'Content-Location: '.$url ); +header( 'Location: '.$url ); +exit(); +?> diff --git a/BSF/admin/include/pclzip.lib.php b/BSF/admin/include/pclzip.lib.php new file mode 100644 index 000000000..8b3c62d38 --- /dev/null +++ b/BSF/admin/include/pclzip.lib.php @@ -0,0 +1,5872 @@ +<?php +// -------------------------------------------------------------------------------- +// PhpConcept Library - Zip Module 2.6 +// -------------------------------------------------------------------------------- +// License GNU/LGPL - Vincent Blavet - March 2006 +// http://www.phpconcept.net +// -------------------------------------------------------------------------------- +// +// Presentation : +// PclZip is a PHP library that manage ZIP archives. +// So far tests show that archives generated by PclZip are readable by +// WinZip application and other tools. +// +// Description : +// See readme.txt and http://www.phpconcept.net +// +// Warning : +// This library and the associated files are non commercial, non professional +// work. +// It should not have unexpected results. However if any damage is caused by +// this software the author can not be responsible. +// The use of this software is at the risk of the user. +// +// -------------------------------------------------------------------------------- +// $Id$ +// -------------------------------------------------------------------------------- + + // ----- Constants + if (!defined('PCLZIP_READ_BLOCK_SIZE')) { + define( 'PCLZIP_READ_BLOCK_SIZE', 2048 ); + } + + // ----- File list separator + // In version 1.x of PclZip, the separator for file list is a space + // (which is not a very smart choice, specifically for windows paths !). + // A better separator should be a comma (,). This constant gives you the + // abilty to change that. + // However notice that changing this value, may have impact on existing + // scripts, using space separated filenames. + // Recommanded values for compatibility with older versions : + //define( 'PCLZIP_SEPARATOR', ' ' ); + // Recommanded values for smart separation of filenames. + if (!defined('PCLZIP_SEPARATOR')) { + define( 'PCLZIP_SEPARATOR', ',' ); + } + + // ----- Error configuration + // 0 : PclZip Class integrated error handling + // 1 : PclError external library error handling. By enabling this + // you must ensure that you have included PclError library. + // [2,...] : reserved for futur use + if (!defined('PCLZIP_ERROR_EXTERNAL')) { + define( 'PCLZIP_ERROR_EXTERNAL', 0 ); + } + + // ----- Optional static temporary directory + // By default temporary files are generated in the script current + // path. + // If defined : + // - MUST BE terminated by a '/'. + // - MUST be a valid, already created directory + // Samples : + // define( 'PCLZIP_TEMPORARY_DIR', '/temp/' ); + // define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' ); + if (!defined('PCLZIP_TEMPORARY_DIR')) { + define( 'PCLZIP_TEMPORARY_DIR', '' ); + } + +// -------------------------------------------------------------------------------- +// ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED ***** +// -------------------------------------------------------------------------------- + + // ----- Global variables + $g_pclzip_version = "2.6"; + + // ----- Error codes + // -1 : Unable to open file in binary write mode + // -2 : Unable to open file in binary read mode + // -3 : Invalid parameters + // -4 : File does not exist + // -5 : Filename is too long (max. 255) + // -6 : Not a valid zip file + // -7 : Invalid extracted file size + // -8 : Unable to create directory + // -9 : Invalid archive extension + // -10 : Invalid archive format + // -11 : Unable to delete file (unlink) + // -12 : Unable to rename file (rename) + // -13 : Invalid header checksum + // -14 : Invalid archive size + define( 'PCLZIP_ERR_USER_ABORTED', 2 ); + define( 'PCLZIP_ERR_NO_ERROR', 0 ); + define( 'PCLZIP_ERR_WRITE_OPEN_FAIL', -1 ); + define( 'PCLZIP_ERR_READ_OPEN_FAIL', -2 ); + define( 'PCLZIP_ERR_INVALID_PARAMETER', -3 ); + define( 'PCLZIP_ERR_MISSING_FILE', -4 ); + define( 'PCLZIP_ERR_FILENAME_TOO_LONG', -5 ); + define( 'PCLZIP_ERR_INVALID_ZIP', -6 ); + define( 'PCLZIP_ERR_BAD_EXTRACTED_FILE', -7 ); + define( 'PCLZIP_ERR_DIR_CREATE_FAIL', -8 ); + define( 'PCLZIP_ERR_BAD_EXTENSION', -9 ); + define( 'PCLZIP_ERR_BAD_FORMAT', -10 ); + define( 'PCLZIP_ERR_DELETE_FILE_FAIL', -11 ); + define( 'PCLZIP_ERR_RENAME_FILE_FAIL', -12 ); + define( 'PCLZIP_ERR_BAD_CHECKSUM', -13 ); + define( 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14 ); + define( 'PCLZIP_ERR_MISSING_OPTION_VALUE', -15 ); + define( 'PCLZIP_ERR_INVALID_OPTION_VALUE', -16 ); + define( 'PCLZIP_ERR_ALREADY_A_DIRECTORY', -17 ); + define( 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18 ); + define( 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19 ); + define( 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20 ); + define( 'PCLZIP_ERR_DIRECTORY_RESTRICTION', -21 ); + + // ----- Options values + define( 'PCLZIP_OPT_PATH', 77001 ); + define( 'PCLZIP_OPT_ADD_PATH', 77002 ); + define( 'PCLZIP_OPT_REMOVE_PATH', 77003 ); + define( 'PCLZIP_OPT_REMOVE_ALL_PATH', 77004 ); + define( 'PCLZIP_OPT_SET_CHMOD', 77005 ); + define( 'PCLZIP_OPT_EXTRACT_AS_STRING', 77006 ); + define( 'PCLZIP_OPT_NO_COMPRESSION', 77007 ); + define( 'PCLZIP_OPT_BY_NAME', 77008 ); + define( 'PCLZIP_OPT_BY_INDEX', 77009 ); + define( 'PCLZIP_OPT_BY_EREG', 77010 ); + define( 'PCLZIP_OPT_BY_PREG', 77011 ); + define( 'PCLZIP_OPT_COMMENT', 77012 ); + define( 'PCLZIP_OPT_ADD_COMMENT', 77013 ); + define( 'PCLZIP_OPT_PREPEND_COMMENT', 77014 ); + define( 'PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015 ); + define( 'PCLZIP_OPT_REPLACE_NEWER', 77016 ); + define( 'PCLZIP_OPT_STOP_ON_ERROR', 77017 ); + // Having big trouble with crypt. Need to multiply 2 long int + // which is not correctly supported by PHP ... + //define( 'PCLZIP_OPT_CRYPT', 77018 ); + define( 'PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019 ); + + // ----- File description attributes + define( 'PCLZIP_ATT_FILE_NAME', 79001 ); + define( 'PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002 ); + define( 'PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003 ); + define( 'PCLZIP_ATT_FILE_MTIME', 79004 ); + define( 'PCLZIP_ATT_FILE_CONTENT', 79005 ); + define( 'PCLZIP_ATT_FILE_COMMENT', 79006 ); + + // ----- Call backs values + define( 'PCLZIP_CB_PRE_EXTRACT', 78001 ); + define( 'PCLZIP_CB_POST_EXTRACT', 78002 ); + define( 'PCLZIP_CB_PRE_ADD', 78003 ); + define( 'PCLZIP_CB_POST_ADD', 78004 ); + /* For futur use + define( 'PCLZIP_CB_PRE_LIST', 78005 ); + define( 'PCLZIP_CB_POST_LIST', 78006 ); + define( 'PCLZIP_CB_PRE_DELETE', 78007 ); + define( 'PCLZIP_CB_POST_DELETE', 78008 ); + */ + + // -------------------------------------------------------------------------------- + // Class : PclZip + // Description : + // PclZip is the class that represent a Zip archive. + // The public methods allow the manipulation of the archive. + // Attributes : + // Attributes must not be accessed directly. + // Methods : + // PclZip() : Object creator + // create() : Creates the Zip archive + // listContent() : List the content of the Zip archive + // extract() : Extract the content of the archive + // properties() : List the properties of the archive + // -------------------------------------------------------------------------------- + class PclZip + { + // ----- Filename of the zip file + var $zipname = ''; + + // ----- File descriptor of the zip file + var $zip_fd = 0; + + // ----- Internal error handling + var $error_code = 1; + var $error_string = ''; + + // ----- Current status of the magic_quotes_runtime + // This value store the php configuration for magic_quotes + // The class can then disable the magic_quotes and reset it after + var $magic_quotes_status; + + // -------------------------------------------------------------------------------- + // Function : PclZip() + // Description : + // Creates a PclZip object and set the name of the associated Zip archive + // filename. + // Note that no real action is taken, if the archive does not exist it is not + // created. Use create() for that. + // -------------------------------------------------------------------------------- + function PclZip($p_zipname) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::PclZip', "zipname=$p_zipname"); + + // ----- Tests the zlib + if (!function_exists('gzopen')) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 1, "zlib extension seems to be missing"); + die('Abort '.basename(__FILE__).' : Missing zlib extensions'); + } + + // ----- Set the attributes + $this->zipname = $p_zipname; + $this->zip_fd = 0; + $this->magic_quotes_status = -1; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 1); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::create', "filelist='$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(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "$v_size arguments passed to the method"); + + // ----- 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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Variable list of options detected"); + + // ----- 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_CRYPT => 'optional' + )); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Static synopsis"); + + // ----- 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"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return 0; + } + } + } + + // ----- 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"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + 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 { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Ignore an empty filename"); + } + } + } + + // ----- 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) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + } + + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + + // ----- Call the create fct + $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $p_result_list); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::add', "filelist='$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(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "$v_size arguments passed to the method"); + + // ----- 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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Variable list of options detected"); + + // ----- 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_CRYPT => 'optional' + )); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Static synopsis"); + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return 0; + } + } + } + + // ----- 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"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + 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) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + } + + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + + // ----- Call the create fct + $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $p_result_list); + 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 exists 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() + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::listContent', ""); + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return(0); + } + + // ----- Call the extracting fct + $p_list = array(); + if (($v_result = $this->privList($p_list)) != 1) + { + unset($p_list); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0, PclZip::errorInfo()); + return(0); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $p_list); + 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() + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::extract", ""); + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + 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(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "$v_size arguments passed to the method"); + + // ----- 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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Variable list of options"); + + // ----- 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' + )); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + 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 { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Static synopsis"); + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0, PclZip::errorInfo()); + return 0; + } + } + } + + // ----- Trace + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "path='$v_path', remove_path='$v_remove_path', remove_all_path='".($v_remove_path?'true':'false')."'"); + + // ----- 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); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0, PclZip::errorInfo()); + return(0); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $p_list); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::extractByIndex", "index='$p_index', ..."); + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + 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(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "$v_size arguments passed to the method"); + + // ----- 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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Variable list of options"); + + // ----- 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' + )); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + 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; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Option PCLZIP_OPT_EXTRACT_AS_STRING not set."); + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Option PCLZIP_OPT_EXTRACT_AS_STRING set."); + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Static synopsis"); + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return 0; + } + } + } + + // ----- Trace + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "index='$p_index', path='$v_path', remove_path='$v_remove_path', remove_all_path='".($v_remove_path?'true':'false')."'"); + + // ----- 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) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; + + // ----- Call the extracting fct + if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0, PclZip::errorInfo()); + return(0); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $p_list); + 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() + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::delete", ""); + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return(0); + } + + // ----- Set default values + $v_options = array(); + + // ----- Look for variable options arguments + $v_size = func_num_args(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "$v_size arguments passed to the method"); + + // ----- 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) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + 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); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0, PclZip::errorInfo()); + return(0); + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_list); + return $v_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : deleteByIndex() + // Description : + // ***** Deprecated ***** + // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. + // -------------------------------------------------------------------------------- + function deleteByIndex($p_index) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::deleteByIndex", "index='$p_index'"); + + $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $p_list); + 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() + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::properties", ""); + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), 0); + return 0; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_prop); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::duplicate", ""); + $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')) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "The parameter is valid PclZip object '".$p_archive->zipname."'"); + + // ----- 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)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "The parameter is a filename '$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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::merge", ""); + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + 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')) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The parameter is valid PclZip object"); + + // ----- 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)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The parameter is a filename"); + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privCheckFormat", ""); + $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."'"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, false, PclZip::errorInfo()); + 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."'"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, false, PclZip::errorInfo()); + return(false); + } + + // ----- Check the magic code + // TBC + + // ----- Check the central header + // TBC + + // ----- Check each file header + // TBC + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privParseOptions", ""); + $v_result=1; + + // ----- Read the options + $i=0; + while ($i<$p_size) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Looking for table index $i, option = '".PclZipUtilOptionText($p_options_list[$i])."(".$p_options_list[$i].")'"); + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." = '".$v_result_list[$p_options_list[$i]]."'"); + $i++; + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." = '".$v_result_list[$p_options_list[$i]]."'"); + $i++; + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." set with an empty value is ignored."); + } + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + ////--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." = '".$v_result_list[$p_options_list[$i]]."'"); + $i++; + break; + + // ----- Look for options that request an EREG or PREG expression + case PCLZIP_OPT_BY_EREG : + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." = '".$v_result_list[$p_options_list[$i]]."'"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." = '".$v_result_list[$p_options_list[$i]]."'"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Get the value + $v_work_list = array(); + if (is_string($p_options_list[$i+1])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Index value is a 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])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Index value is an 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])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Index value is an array"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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<sizeof($v_work_list); $j++) { + // ----- Explode the item + $v_item_list = explode("-", $v_work_list[$j]); + $v_size_item_list = sizeof($v_item_list); + + // ----- TBC : Here we might check that each item is a + // real integer ... + + // ----- Look for single value + if ($v_size_item_list == 1) { + // ----- Set the option value + $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0]; + $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0]; + } + elseif ($v_size_item_list == 2) { + // ----- Set the option value + $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0]; + $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extracted index item = [".$v_result_list[$p_options_list[$i]][$j]['start'].",".$v_result_list[$p_options_list[$i]][$j]['end']."]"); + + // ----- Look for list sort + if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The list should be sorted ..."); + $v_sort_flag=true; + + // ----- TBC : An automatic sort should be writen ... + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start']; + } + + // ----- Sort the items + if ($v_sort_flag) { + // TBC : To Be Completed + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "List sorting is not yet write ..."); + } + + // ----- Next option + $i++; + break; + + // ----- Look for options that request no value + case PCLZIP_OPT_REMOVE_ALL_PATH : + case PCLZIP_OPT_EXTRACT_AS_STRING : + case PCLZIP_OPT_NO_COMPRESSION : + case PCLZIP_OPT_EXTRACT_IN_OUTPUT : + case PCLZIP_OPT_REPLACE_NEWER : + case PCLZIP_OPT_STOP_ON_ERROR : + $v_result_list[$p_options_list[$i]] = true; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." = '".$v_result_list[$p_options_list[$i]]."'"); + break; + + // ----- Look for options that request an octal value + case PCLZIP_OPT_SET_CHMOD : + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." = '".$v_result_list[$p_options_list[$i]]."'"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Get the value + $v_function_name = $p_options_list[$i+1]; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "call-back ".PclZipUtilOptionText($p_options_list[$i])." = '".$v_function_name."'"); + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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') { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Detect a mandatory option : ".PclZipUtilOptionText($key)."(".$key.")"); + // ----- Look if present + if (!isset($v_result_list[$key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + } + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privFileDescrParseAtt", ""); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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)."'"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($v_key)." = '".$v_value."'"); + + if ($p_filedescr['filename'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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)."'"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($v_key)." = '".$v_value."'"); + + if ($p_filedescr['new_short_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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)."'"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($v_key)." = '".$v_value."'"); + + if ($p_filedescr['new_full_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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)."'"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + $p_filedescr['comment'] = $v_value; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($v_key)." = '".$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)."'"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + $p_filedescr['mtime'] = $v_value; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($v_key)." = '".$v_value."'"); + break; + + case PCLZIP_ATT_FILE_CONTENT : + $p_filedescr['content'] = $v_value; + ////--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($v_key)." = '".$v_value."'"); + break; + + default : + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Unknown parameter '".$v_key."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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') { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Detect a mandatory option : ".PclZipUtilOptionText($key)."(".$key.")"); + // ----- Look if present + if (!isset($p_file_list[$key])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + } + } + + // end foreach + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrExpand() + // Description : + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privFileDescrExpand(&$p_filedescr_list, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privFileDescrExpand", ""); + $v_result=1; + + // ----- Create a result list + $v_result_list = array(); + + // ----- Look each entry + for ($i=0; $i<sizeof($p_filedescr_list); $i++) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Looking for file ".$i."."); + + // ----- Get filedescr + $v_descr = $p_filedescr_list[$i]; + + // ----- Reduce the filename + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Filedescr before reduction :'".$v_descr['filename']."'"); + $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename']); + $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Filedescr after reduction :'".$v_descr['filename']."'"); + + // ----- Look for real file or folder + if (file_exists($v_descr['filename'])) { + if (@is_file($v_descr['filename'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "This is a file"); + $v_descr['type'] = 'file'; + } + else if (@is_dir($v_descr['filename'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "This is a folder"); + $v_descr['type'] = 'folder'; + } + else if (@is_link($v_descr['filename'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Unsupported file type : link"); + // skip + continue; + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Unsupported file type : unknown type"); + // skip + continue; + } + } + + // ----- Look for string added as file + else if (isset($v_descr['content'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "This is a string added as a file"); + $v_descr['type'] = 'virtual_file'; + } + + // ----- Missing file + else { + // ----- Error log + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File '".$v_descr['filename']."' does not exists"); + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$v_descr['filename']."' does not exists"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Calculate the stored filename + $this->privCalculateStoredFilename($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) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Looking for '".$v_item_handler."' in the directory"); + + // ----- 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']) { + 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 { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Unable to open dir '".$v_descr['filename']."' in read mode. Skipped."); + // 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) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Concat the resulting list + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Merging result list (size '".sizeof($v_result_list)."') with dirlist (size '".sizeof($v_dirlist_descr)."')"); + $v_result_list = array_merge($v_result_list, $v_dirlist_descr); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "merged result list is size '".sizeof($v_result_list)."'"); + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Nothing in this folder to expand."); + } + + // ----- Free local array + unset($v_dirlist_descr); + } + } + + // ----- Get the result list + $p_filedescr_list = $v_result_list; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCreate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privCreate($p_filedescr_list, &$p_result_list, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privCreate", "list"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAdd() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAdd($p_filedescr_list, &$p_result_list, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privAdd", "list"); + $v_result=1; + $v_list_detail = array(); + + // ----- Look if the archive exists or is empty + if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Archive does not exist, or is empty, create it."); + + // ----- Do a create + $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Go to beginning of File + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in file : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in file : ".ftell($this->zip_fd)."'"); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Open the temporary file in write mode + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "New offset of central dir : $v_offset"); + + // ----- 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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $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; $i<sizeof($v_header_list); $i++) + { + // ----- Create the file header + if ($v_header_list[$i]['status'] == 'ok') { + if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOpenFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privOpenFd($p_mode) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privOpenFd", 'mode='.$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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Open file in '.$p_mode.' mode'); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCloseFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privCloseFd() + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privCloseFd", ""); + $v_result=1; + + if ($this->zip_fd != 0) + @fclose($this->zip_fd); + $this->zip_fd = 0; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privAddList", "list"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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; $i<sizeof($v_header_list); $i++) + { + // ----- Create the file header + if ($v_header_list[$i]['status'] == 'ok') { + if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privAddFileList", "filedescr_list"); + $v_result=1; + $v_header = array(); + + // ----- Recuperate the current number of elt in list + $v_nb = sizeof($p_result_list); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Before add, list have ".$v_nb." elements"); + + // ----- Loop on the files + for ($j=0; ($j<sizeof($p_filedescr_list)) && ($v_result==1); $j++) { + // ----- Format the filename + $p_filedescr_list[$j]['filename'] + = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false); + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Looking for file '".$p_filedescr_list[$j]['filename']."'"); + + // ----- Skip empty file names + // TBC : Can this be possible ? not checked in DescrParseAtt ? + if ($p_filedescr_list[$j]['filename'] == "") { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Skip empty filename"); + continue; + } + + // ----- Check the filename + if ( ($p_filedescr_list[$j]['type'] != 'virtual_file') + && (!file_exists($p_filedescr_list[$j]['filename']))) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File '".$p_filedescr_list[$j]['filename']."' does not exists"); + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$p_filedescr_list[$j]['filename']."' does not exists"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Look if it is a file or a dir with no all path remove option + // or a dir with all its path removed +// if ( (is_file($p_filedescr_list[$j]['filename'])) +// || ( is_dir($p_filedescr_list[$j]['filename']) + if ( ($p_filedescr_list[$j]['type'] == 'file') + || ($p_filedescr_list[$j]['type'] == 'virtual_file') + || ( ($p_filedescr_list[$j]['type'] == 'folder') + && ( !isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]) + || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) + ) { + + // ----- Add the file + $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header, + $p_options); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Store the file infos + $p_result_list[$v_nb++] = $v_header; + } + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "After add, list have ".$v_nb." elements"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFile($p_filedescr, &$p_header, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privAddFile", "filename='".$p_filedescr['filename']."'"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Look for a stored different filename + /* TBC : Removed + if (isset($p_filedescr['stored_filename'])) { + $v_stored_filename = $p_filedescr['stored_filename']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, 'Stored filename is NOT the same "'.$v_stored_filename.'"'); + } + else { + $v_stored_filename = $p_filedescr['stored_filename']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, 'Stored filename is the same'); + } + */ + + // ----- 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']); + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Header external extension '".sprintf("0x%X",$p_header['external'])."'"); + + // ----- Look for filetime + if (isset($p_filedescr['mtime'])) { + $p_header['mtime'] = $p_filedescr['mtime']; + } + else if ($p_filedescr['type'] == 'virtual_file') { + $p_header['mtime'] = mktime(); + } + 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])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "A pre-callback '".$p_options[PCLZIP_CB_PRE_ADD]."()') is defined for the extraction"); + + // ----- 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);'); + 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']); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "New stored filename is '".$p_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 (is_file($p_filename)) + if ( ($p_filedescr['type'] == 'file') + || ($p_filedescr['type'] == 'virtual_file')) { + + // ----- Get content from real file + if ($p_filedescr['type'] == 'file') { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "'".$p_filename."' is a file"); + + // ----- 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"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Read the file content + $v_content = @fread($v_file, $p_header['size']); + + // ----- Close the file + @fclose($v_file); + } + else if ($p_filedescr['type'] == 'virtual_file') { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Add by string"); + $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]) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File will not be compressed"); + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + } + + // ----- Look for normal compression + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File will be compressed"); + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Look for encryption + /* + if ((isset($p_options[PCLZIP_OPT_CRYPT])) + && ($p_options[PCLZIP_OPT_CRYPT] != "")) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File need to be crypted ...."); + + // Should be a random header + $v_header = 'xxxxxxxxxxxx'; + $v_content_compressed = PclZipUtilZipEncrypt($v_content_compressed, + $p_header['compressed_size'], + $v_header, + $p_header['crc'], + "test"); + + $p_header['compressed_size'] += 12; + $p_header['flag'] = 1; + + // ----- Add the header to the data + $v_content_compressed = $v_header.$v_content_compressed; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Size after header : ".strlen($v_content_compressed).""); + } + */ + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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') { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "'".$p_filename."' is a 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + } + } + + // ----- Look for post-add callback + if (isset($p_options[PCLZIP_CB_POST_ADD])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "A post-callback '".$p_options[PCLZIP_CB_POST_ADD]."()') is defined for the extraction"); + + // ----- 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);'); + if ($v_result == 0) { + // ----- Ignored + $v_result = 1; + } + + // ----- Update the informations + // Nothing can be modified + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privCalculateStoredFilename", "filename='".$p_filedescr['filename']."'"); + $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 = ''; + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Remove path ='".$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'])) { + $v_stored_filename = $p_filedescr['new_full_name']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Changing full name of '".$p_filename."' for '".$v_stored_filename."'"); + } + + // ----- Look for path and/or short name change + else { + + // ----- Look for short name change + 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']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Changing short name of '".$p_filename."' for '".$v_stored_filename."'"); + } + 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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Remove all path selected change '".$p_filename."' for '".$v_stored_filename."'"); + } + // ----- Look for partial path remove + else if ($p_remove_dir != "") { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Partial path to remove"); + 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 = ""; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Path to remove is the current folder"); + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Remove path '$p_remove_dir' in file '$v_stored_filename'"); + $v_stored_filename = substr($v_stored_filename, + strlen($p_remove_dir)); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Result is '$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; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Add path '$p_add_dir' in file '$p_filename' = '$v_stored_filename'"); + } + } + + // ----- Filename (reduce the path of stored name) + $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); + $p_filedescr['stored_filename'] = $v_stored_filename; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Stored filename will be '".$p_filedescr['stored_filename']."', strlen ".strlen($p_filedescr['stored_filename'])); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteFileHeader(&$p_header) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privWriteFileHeader", 'file="'.$p_header['filename'].'", stored as "'.$p_header['stored_filename'].'"'); + $v_result=1; + + // ----- Store the offset position of the file + $p_header['offset'] = ftell($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, 'File offset of the header :'.$p_header['offset']); + + // ----- Transform UNIX mtime to DOS format mdate/mtime + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Date : \''.date("d/m/y H:i:s", $p_header['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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteCentralFileHeader(&$p_header) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privWriteCentralFileHeader", 'file="'.$p_header['filename'].'", stored as "'.$p_header['stored_filename'].'"'); + $v_result=1; + + // TBC + //for(reset($p_header); $key = key($p_header); next($p_header)) { + // //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "header[$key] = ".$p_header[$key]); + //} + + // ----- Transform UNIX mtime to DOS format mdate/mtime + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Date : \''.date("d/m/y H:i:s", $p_header['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']; + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Comment size : \''.$p_header['comment_len'].'\''); + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privWriteCentralHeader", 'nb_entries='.$p_nb_entries.', size='.$p_size.', offset='.$p_offset.', comment="'.$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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privList() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privList(&$p_list) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privList", "list"); + $v_result=1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Go to beginning of Central Dir + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Offset : ".$v_central_dir['offset']."'"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Position in file : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Position in file : ".ftell($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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Position in file : ".ftell($this->zip_fd)."'"); + + // ----- 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(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privConvertHeader2FileInfo", "Filename='".$p_header['filename']."'"); + $v_result=1; + + // ----- Get the interesting attributes + $p_info['filename'] = $p_header['filename']; + $p_info['stored_filename'] = $p_header['stored_filename']; + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privExtractByRule", "path='$p_path', remove_path='$p_remove_path', remove_all_path='".($p_remove_all_path?'true':'false')."'"); + $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) == "/") + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Destination path [$p_path] ends by '/'"); + $p_path = substr($p_path, 0, strlen($p_path)-1); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Modified to [$p_path]"); + } + } + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_result = $this->privOpenFd('rb')) != 1) + { + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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(); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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++) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Read next file header entry : '$i'"); + + // ----- Read next Central dir entry + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Position before rewind : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Position after rewind : ".ftell($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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Position after fseek : ".ftell($this->zip_fd)."'"); + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with rule 'ByName'"); + + // ----- Look if the filename is in the list + for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Compare with file '".$p_options[PCLZIP_OPT_BY_NAME][$j]."'"); + + // ----- Look for a directory + if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The searched item is a directory"); + + // ----- Look if the directory is in the filename path + if ( (strlen($v_header['stored_filename']) > 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])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The directory is in the file path"); + $v_extract = true; + } + } + // ----- Look for a filename + elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The file is the right one."); + $v_extract = true; + } + } + } + + // ----- Look for extract by ereg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract by ereg '".$p_options[PCLZIP_OPT_BY_EREG]."'"); + + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Filename match the regular expression"); + $v_extract = true; + } + } + + // ----- Look for extract by preg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) + && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with rule 'ByEreg'"); + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Filename match the regular expression"); + $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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with rule 'ByIndex'"); + + // ----- Look if the index is in the list + for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Look if index '$i' is in [".$p_options[PCLZIP_OPT_BY_INDEX][$j]['start'].",".$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']."]"); + + if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Found as part of an index range"); + $v_extract = true; + } + if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Do not look this index range for next loop"); + $j_start = $j+1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Index range is greater than index, stop loop"); + break; + } + } + } + + // ----- Look for no rule, which means extract all the archive + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with no rule (extract all)"); + $v_extract = true; + } + + // ----- Check compression method + if ( ($v_extract) + && ( ($v_header['compression'] != 8) + && ($v_header['compression'] != 0))) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Unsupported compression method (".$v_header['compression'].")"); + $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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_STOP_ON_ERROR is selected, extraction will be stopped"); + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, + "Filename '".$v_header['stored_filename']."' is " + ."compressed by an unsupported compression " + ."method (".$v_header['compression'].") "); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + + // ----- Check encrypted files + if (($v_extract) && (($v_header['flag'] & 1) == 1)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Unsupported file encryption"); + $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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_STOP_ON_ERROR is selected, extraction will be stopped"); + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, + "Unsupported encryption for " + ." filename '".$v_header['stored_filename'] + ."'"); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + + // ----- Look for real extraction + if (($v_extract) && ($v_header['status'] != 'ok')) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "No need for extract"); + $v_result = $this->privConvertHeader2FileInfo($v_header, + $p_file_list[$v_nb_extracted++]); + if ($v_result != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + $v_extract = false; + } + + // ----- Look for real extraction + if ($v_extract) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting file '".$v_header['filename']."', index '$i'"); + + // ----- Go to the file position + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position before rewind : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position after rewind : ".ftell($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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position after fseek : ".ftell($this->zip_fd)."'"); + + // ----- Look for extraction as string + if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { + + // ----- Extracting the file + $v_result1 = $this->privExtractFileAsString($v_header, $v_string); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result1); + 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(); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result1); + 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(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result1); + 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(); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + } + } + + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::privExtractFile', "path='$p_path', remove_path='$p_remove_path', remove_all_path='".($p_remove_all_path?'true':'false')."'"); + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Found file '".$v_header['filename']."', size '".$v_header['size']."'"); + + // ----- 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) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "The entry is a folder : need to be filtered"); + + $p_entry['status'] = "filtered"; + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "All path is removed"); + // ----- Get the basename of the path + $p_entry['filename'] = basename($p_entry['filename']); + } + + // ----- Look for path to remove + else if ($p_remove_path != "") + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Look for some path to remove"); + if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "The folder is the same as the removed path '".$p_entry['filename']."'"); + + // ----- Change the file status + $p_entry['status'] = "filtered"; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + $p_remove_path_size = strlen($p_remove_path); + if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Found path '$p_remove_path' to remove in file '".$p_entry['filename']."'"); + + // ----- Remove the path + $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Resulting file is '".$p_entry['filename']."'"); + } + } + + // ----- 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])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Check the extract directory restriction"); + $v_inclusion + = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], + $p_entry['filename']); + if ($v_inclusion == 0) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_EXTRACT_DIR_RESTRICTION is selected, file is outside restriction"); + + PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, + "Filename '".$p_entry['filename']."' is " + ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "A pre-callback '".$p_options[PCLZIP_CB_PRE_EXTRACT]."()') is defined for the extraction"); + + // ----- 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);'); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "User callback abort the extraction"); + // ----- 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']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "New filename is '".$p_entry['filename']."'"); + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting file (with path) '".$p_entry['filename']."', size '$v_header[size]'"); + + // ----- 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'])) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File '".$p_entry['filename']."' already exists"); + + // ----- Look if file is a directory + if (is_dir($p_entry['filename'])) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Existing file '".$p_entry['filename']."' is a directory"); + + // ----- 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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_STOP_ON_ERROR is selected, extraction will be stopped"); + + PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, + "Filename '".$p_entry['filename']."' is " + ."already used by an existing directory"); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + // ----- Look if file is write protected + else if (!is_writeable($p_entry['filename'])) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Existing file '".$p_entry['filename']."' is write protected"); + + // ----- 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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_STOP_ON_ERROR is selected, extraction will be stopped"); + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, + "Filename '".$p_entry['filename']."' exists " + ."and is write protected"); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + + // ----- Look if the extracted file is older + else if (filemtime($p_entry['filename']) > $p_entry['mtime']) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Existing file '".$p_entry['filename']."' is newer (".date("l dS of F Y h:i:s A", filemtime($p_entry['filename'])).") than the extracted file (".date("l dS of F Y h:i:s A", $p_entry['mtime']).")"); + // ----- Change the file status + if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) + && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_REPLACE_NEWER is selected, file will be replaced"); + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File will not be replaced"); + $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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_STOP_ON_ERROR is selected, extraction will be stopped"); + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, + "Newer version of '".$p_entry['filename']."' exists " + ."and option PCLZIP_OPT_REPLACE_NEWER is not selected"); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Existing file '".$p_entry['filename']."' is older than the extrated one - will be replaced by the extracted one (".date("l dS of F Y h:i:s A", filemtime($p_entry['filename'])).") than the extracted file (".date("l dS of F Y h:i:s A", $p_entry['mtime']).")"); + } + } + + // ----- 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) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Unable to create path for '".$p_entry['filename']."'"); + + // ----- Change the file status + $p_entry['status'] = "path_creation_fail"; + + // ----- Return + ////--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + //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) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting an un-compressed file"); + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Error while opening '".$p_entry['filename']."' in write binary mode"); + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Read '".$p_entry['size']."' bytes"); + + // ----- 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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Read $v_read_size bytes"); + $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 { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting a compressed file (Compression method ".$p_entry['compression'].")"); + // ----- TBC + // Need to be finished + if (($p_entry['flag'] & 1) == 1) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File is encrypted"); + /* + // ----- Read the encryption header + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Read 12 encryption header bytes"); + $v_encryption_header = @fread($this->zip_fd, 12); + + // ----- Read the encrypted & compressed file in a buffer + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Read '".($p_entry['compressed_size']-12)."' compressed & encrypted bytes"); + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']-12); + + // ----- Decrypt the buffer + $this->privDecrypt($v_encryption_header, $v_buffer, + $p_entry['compressed_size']-12, $p_entry['crc']); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Buffer is '".$v_buffer."'"); + */ + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Read '".$p_entry['compressed_size']."' compressed bytes"); + // ----- 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) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Unable to inflate compressed file"); + + // ----- Change the file status + // TBC + $p_entry['status'] = "error"; + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Error while opening '".$p_entry['filename']."' in write binary mode"); + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "chmod option activated '".$p_options[PCLZIP_OPT_SET_CHMOD]."'"); + + // ----- Change the mode of the file + @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extraction done"); + } + } + + // ----- 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])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "A post-callback '".$p_options[PCLZIP_CB_POST_EXTRACT]."()') is defined for the extraction"); + + // ----- 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);'); + + // ----- Look for abort result + if ($v_result == 2) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "User callback abort the extraction"); + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileInOutput() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileInOutput(&$p_entry, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::privExtractFileInOutput', ""); + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Found file '".$v_header['filename']."', size '".$v_header['size']."'"); + + // ----- 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])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "A pre-callback '".$p_options[PCLZIP_CB_PRE_EXTRACT]."()') is defined for the extraction"); + + // ----- 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);'); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "User callback abort the extraction"); + // ----- 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']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "New filename is '".$p_entry['filename']."'"); + } + + // ----- Trace + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting file (with path) '".$p_entry['filename']."', size '$v_header[size]'"); + + // ----- 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']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting an un-compressed file"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Reading '".$p_entry['size']."' bytes"); + + // ----- 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 { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting a compressed file"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Reading '".$p_entry['size']."' bytes"); + + // ----- 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); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extraction done"); + } + } + + // ----- 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])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "A post-callback '".$p_options[PCLZIP_CB_POST_EXTRACT]."()') is defined for the extraction"); + + // ----- 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);'); + + // ----- Look for abort result + if ($v_result == 2) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "User callback abort the extraction"); + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileAsString() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileAsString(&$p_entry, &$p_string) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::privExtractFileAsString', "p_entry['filename']='".$p_entry['filename']."'"); + $v_result=1; + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadFileHeader($v_header)) != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Found file '".$v_header['filename']."', size '".$v_header['size']."'"); + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting file in string (with path) '".$p_entry['filename']."', size '$v_header[size]'"); + + // ----- 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) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting an un-compressed file"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Reading '".$p_entry['size']."' bytes"); + + // ----- Reading the file + $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting a compressed file (compression method '".$p_entry['compression']."')"); + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extraction done"); + } + else { + // TBC : error : can not extract a folder in a string + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadFileHeader(&$p_header) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privReadFileHeader", ""); + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Binary data is : '".sprintf("%08x", $v_binary_data)."'"); + $v_data = unpack('Vid', $v_binary_data); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Binary signature is : '".sprintf("0x%08x", $v_data['id'])."'"); + + // ----- Check signature + if ($v_data['id'] != 0x04034b50) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Invalid File header"); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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"; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Extract the values + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Header : '".$v_binary_data."'"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Header (Hex) : '".bin2hex($v_binary_data)."'"); + $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); + + // ----- Get filename + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "File name length : ".$v_data['filename_len']); + $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Filename : \''.$p_header['filename'].'\''); + + // ----- Get extra_fields + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extra field length : ".$v_data['extra_len']); + if ($v_data['extra_len'] != 0) { + $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); + } + else { + $p_header['extra'] = ''; + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Extra field : \''.bin2hex($p_header['extra']).'\''); + + // ----- Extract properties + $p_header['version_extracted'] = $v_data['version']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Version need to extract : ('.$p_header['version_extracted'].') \''.($p_header['version_extracted']/10).'.'.($p_header['version_extracted']%10).'\''); + $p_header['compression'] = $v_data['compression']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Compression method : \''.$p_header['compression'].'\''); + $p_header['size'] = $v_data['size']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Size : \''.$p_header['size'].'\''); + $p_header['compressed_size'] = $v_data['compressed_size']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Compressed Size : \''.$p_header['compressed_size'].'\''); + $p_header['crc'] = $v_data['crc']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'CRC : \''.sprintf("0x%X", $p_header['crc']).'\''); + $p_header['flag'] = $v_data['flag']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Flag : \''.$p_header['flag'].'\''); + $p_header['filename_len'] = $v_data['filename_len']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Filename_len : \''.$p_header['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); + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Date : \''.date("d/m/y H:i:s", $p_header['mtime']).'\''); + } + else + { + $p_header['mtime'] = time(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Date is actual : \''.date("d/m/y H:i:s", $p_header['mtime']).'\''); + } + + // TBC + //for(reset($v_data); $key = key($v_data); next($v_data)) { + // //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Attribut[$key] = ".$v_data[$key]); + //} + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set the status field + $p_header['status'] = "ok"; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadCentralFileHeader(&$p_header) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privReadCentralFileHeader", ""); + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Binary data is : '".sprintf("%08x", $v_binary_data)."'"); + $v_data = unpack('Vid', $v_binary_data); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Binary signature is : '".sprintf("0x%08x", $v_data['id'])."'"); + + // ----- Check signature + if ($v_data['id'] != 0x02014b50) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Invalid Central Dir File signature"); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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"; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Extract the values + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Header : '".$v_binary_data."'"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Header (Hex) : '".bin2hex($v_binary_data)."'"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "File name length : ".$p_header['filename_len']); + if ($p_header['filename_len'] != 0) + $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); + else + $p_header['filename'] = ''; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Filename : \''.$p_header['filename'].'\''); + + // ----- Get extra + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Extra length : ".$p_header['extra_len']); + if ($p_header['extra_len'] != 0) + $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); + else + $p_header['extra'] = ''; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Extra : \''.$p_header['extra'].'\''); + + // ----- Get comment + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Comment length : ".$p_header['comment_len']); + if ($p_header['comment_len'] != 0) + $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); + else + $p_header['comment'] = ''; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Comment : \''.$p_header['comment'].'\''); + + // ----- Extract properties + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Version : \''.($p_header['version']/10).'.'.($p_header['version']%10).'\''); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Version need to extract : \''.($p_header['version_extracted']/10).'.'.($p_header['version_extracted']%10).'\''); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Size : \''.$p_header['size'].'\''); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Compressed Size : \''.$p_header['compressed_size'].'\''); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'CRC : \''.sprintf("0x%X", $p_header['crc']).'\''); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Flag : \''.$p_header['flag'].'\''); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Offset : \''.$p_header['offset'].'\''); + + // ----- 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); + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Date : \''.date("d/m/y H:i:s", $p_header['mtime']).'\''); + } + else + { + $p_header['mtime'] = time(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Date is actual : \''.date("d/m/y H:i:s", $p_header['mtime']).'\''); + } + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Internal (Hex) : '".sprintf("Ox%04X", $p_header['internal'])."'"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "External (Hex) : '".sprintf("Ox%04X", $p_header['external'])."' (".(($p_header['external']&0x00000010)==0x00000010?'is a folder':'is a file').')'); + if (substr($p_header['filename'], -1) == '/') { + //$p_header['external'] = 0x41FF0010; + $p_header['external'] = 0x00000010; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Force folder external : \''.sprintf("Ox%04X", $p_header['external']).'\''); + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Header of filename : \''.$p_header['filename'].'\''); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCheckFileHeaders() + // Description : + // Parameters : + // Return Values : + // 1 on success, + // 0 on error; + // -------------------------------------------------------------------------------- + function privCheckFileHeaders(&$p_local_header, &$p_central_header) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privCheckFileHeaders", ""); + $v_result=1; + + // ----- Check the static values + // TBC + if ($p_local_header['filename'] != $p_central_header['filename']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Bad check "filename" : TBC To Be Completed'); + } + if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Bad check "version_extracted" : TBC To Be Completed'); + } + if ($p_local_header['flag'] != $p_central_header['flag']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Bad check "flag" : TBC To Be Completed'); + } + if ($p_local_header['compression'] != $p_central_header['compression']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Bad check "compression" : TBC To Be Completed'); + } + if ($p_local_header['mtime'] != $p_central_header['mtime']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Bad check "mtime" : TBC To Be Completed'); + } + if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Bad check "filename_len" : TBC To Be Completed'); + } + + // ----- Look for flag bit 3 + if (($p_local_header['flag'] & 8) == 8) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Purpose bit flag bit 3 set !'); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'File size, compression size and crc found in central header'); + $p_local_header['size'] = $p_central_header['size']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Size : \''.$p_local_header['size'].'\''); + $p_local_header['compressed_size'] = $p_central_header['compressed_size']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Compressed Size : \''.$p_local_header['compressed_size'].'\''); + $p_local_header['crc'] = $p_central_header['crc']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'CRC : \''.sprintf("0x%X", $p_local_header['crc']).'\''); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadEndCentralDir() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadEndCentralDir(&$p_central_dir) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privReadEndCentralDir", ""); + $v_result=1; + + // ----- Go to the end of the zip file + $v_size = filesize($this->zipname); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Size of the file :$v_size"); + @fseek($this->zip_fd, $v_size); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Position at end of zip file : \''.ftell($this->zip_fd).'\''); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Look for central dir with no comment'); + @fseek($this->zip_fd, $v_size-22); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Position after min central position : \''.ftell($this->zip_fd).'\''); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Read for bytes + $v_binary_data = @fread($this->zip_fd, 4); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Binary data is : '".sprintf("%08x", $v_binary_data)."'"); + $v_data = @unpack('Vid', $v_binary_data); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Binary signature is : '".sprintf("0x%08x", $v_data['id'])."'"); + + // ----- Check signature + if ($v_data['id'] == 0x06054b50) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Found central dir at the default position."); + $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) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Start extended search of end central dir'); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Position after max central position : \''.ftell($this->zip_fd).'\''); + + // ----- 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); + + // ----- Compare the bytes + if ($v_bytes == 0x504b0506) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Found End Central Dir signature at position : \''.ftell($this->zip_fd).'\''); + $v_pos++; + break; + } + + $v_pos++; + } + + // ----- Look if not found end of central dir + if ($v_pos == $v_size) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Unable to find End of Central Dir Record signature"); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Invalid End of Central Dir Record size : ".strlen($v_binary_data)); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data)); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Extract the values + ////--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Central Dir Record : '".$v_binary_data."'"); + ////--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Central Dir Record (Hex) : '".bin2hex($v_binary_data)."'"); + $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); + + // ----- Check the global size + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Comment length : ".$v_data['comment_size']); + if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "The central dir is not at the end of the archive. Some trailing bytes exists after the archive."); + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + + // ----- Get comment + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Comment size : \''.$v_data['comment_size'].'\''); + if ($v_data['comment_size'] != 0) { + $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); + } + else + $p_central_dir['comment'] = ''; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Comment : \''.$p_central_dir['comment'].'\''); + + $p_central_dir['entries'] = $v_data['entries']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Nb of entries : \''.$p_central_dir['entries'].'\''); + $p_central_dir['disk_entries'] = $v_data['disk_entries']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Nb of entries for this disk : \''.$p_central_dir['disk_entries'].'\''); + $p_central_dir['offset'] = $v_data['offset']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Offset of Central Dir : \''.$p_central_dir['offset'].'\''); + $p_central_dir['size'] = $v_data['size']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Size of Central Dir : \''.$p_central_dir['size'].'\''); + $p_central_dir['disk'] = $v_data['disk']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Disk number : \''.$p_central_dir['disk'].'\''); + $p_central_dir['disk_start'] = $v_data['disk_start']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Start disk number : \''.$p_central_dir['disk_start'].'\''); + + // TBC + //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { + // //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "central_dir[$key] = ".$p_central_dir[$key]); + //} + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDeleteByRule() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDeleteByRule(&$p_result_list, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privDeleteByRule", ""); + $v_result=1; + $v_list_detail = array(); + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Go to beginning of File + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in file : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in file : ".ftell($this->zip_fd)."'"); + + // ----- Scan all the files + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position before rewind : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position after rewind : ".ftell($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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position after fseek : ".ftell($this->zip_fd)."'"); + + // ----- Read each entry + $v_header_list = array(); + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Read next file header entry (index '$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(); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Filename (index '$i') : '".$v_header_list[$v_nb_extracted]['stored_filename']."'"); + + // ----- 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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with rule 'ByName'"); + + // ----- Look if the filename is in the list + for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Compare with file '".$p_options[PCLZIP_OPT_BY_NAME][$j]."'"); + + // ----- Look for a directory + if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The searched item is a directory"); + + // ----- Look if the directory is in the filename path + if ( (strlen($v_header_list[$v_nb_extracted]['stored_filename']) > 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])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The directory is in the file path"); + $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])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The entry is the searched directory"); + $v_found = true; + } + } + // ----- Look for a filename + elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The file is the right one."); + $v_found = true; + } + } + } + + // ----- Look for extract by ereg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract by ereg '".$p_options[PCLZIP_OPT_BY_EREG]."'"); + + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Filename match the regular expression"); + $v_found = true; + } + } + + // ----- Look for extract by preg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) + && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with rule 'ByEreg'"); + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Filename match the regular expression"); + $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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with rule 'ByIndex'"); + + // ----- Look if the index is in the list + for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Look if index '$i' is in [".$p_options[PCLZIP_OPT_BY_INDEX][$j]['start'].",".$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']."]"); + + if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Found as part of an index range"); + $v_found = true; + } + if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Do not look this index range for next loop"); + $j_start = $j+1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Index range is greater than index, stop loop"); + break; + } + } + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "No argument mean remove all file"); + $v_found = true; + } + + // ----- Look for deletion + if ($v_found) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File '".$v_header_list[$v_nb_extracted]['stored_filename']."', index '$i' need to be deleted"); + unset($v_header_list[$v_nb_extracted]); + } + else + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File '".$v_header_list[$v_nb_extracted]['stored_filename']."', index '$i' will not be deleted"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary write mode"); + if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { + $this->privCloseFd(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Look which file need to be kept + for ($i=0; $i<sizeof($v_header_list); $i++) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Keep entry index '$i' : '".$v_header_list[$i]['filename']."'"); + + // ----- Calculate the position of the header + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Offset='". $v_header_list[$i]['offset']."'"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position before rewind : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position after rewind : ".ftell($this->zip_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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position after fseek : ".ftell($this->zip_fd)."'"); + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Offset for this file is '".$v_header_list[$i]['offset']."'"); + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_temp_zip->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "New offset of central dir : $v_offset"); + + // ----- Re-Create the Central Dir files header + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Creates the new central directory"); + for ($i=0; $i<sizeof($v_header_list); $i++) { + // ----- Create the file header + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Offset of file : ".$v_header_list[$i]['offset']); + if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) { + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Transform the header to a 'usable' info + $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Creates the central directory footer"); + + // ----- 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + $this->privCloseFd(); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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; + + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privDirCheck", "entry='$p_dir', is_dir='".($p_is_dir?"true":"false")."'"); + + // ----- Remove the final '/' + if (($p_is_dir) && (substr($p_dir, -1)=='/')) + { + $p_dir = substr($p_dir, 0, strlen($p_dir)-1); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Looking for entry '$p_dir'"); + + // ----- Check the directory availability + if ((is_dir($p_dir)) || ($p_dir == "")) + { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, "'$p_dir' is a directory"); + return 1; + } + + // ----- Extract parent directory + $p_parent_dir = dirname($p_dir); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Parent directory is '$p_parent_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) + { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + } + } + + // ----- Create the directory + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Create directory '$p_dir'"); + if (!@mkdir($p_dir, 0777)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result, "Directory '$p_dir' created"); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privMerge", "archive='".$p_archive_to_add->zipname."'"); + $v_result=1; + + // ----- Look if the archive_to_add exists + if (!is_file($p_archive_to_add->zipname)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Archive to add does not exist. End of merge."); + + // ----- Nothing to merge, so merge is a success + $v_result = 1; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Look if the archive exists + if (!is_file($this->zipname)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Archive does not exist, duplicate the archive_to_add."); + + // ----- Do a duplicate + $v_result = $this->privDuplicate($p_archive_to_add->zipname); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Go to beginning of File + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in zip : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in zip : ".ftell($this->zip_fd)."'"); + + // ----- Open the archive_to_add file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open archive_to_add in binary read mode"); + if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1) + { + $this->privCloseFd(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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(); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Go to beginning of File + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in archive_to_add : ".ftell($p_archive_to_add->zip_fd)."'"); + @rewind($p_archive_to_add->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in archive_to_add : ".ftell($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 + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "New offset of central dir : $v_offset"); + + // ----- 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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDuplicate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDuplicate($p_archive_filename) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privDuplicate", "archive_filename='$p_archive_filename'"); + $v_result=1; + + // ----- Look if the $p_archive_filename exists + if (!is_file($p_archive_filename)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Archive to duplicate does not exist. End of duplicate."); + + // ----- Nothing to duplicate, so duplicate is a success. + $v_result = 1; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_result=$this->privOpenFd('wb')) != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Open the temporary file in write mode + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + 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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Read $v_read_size bytes"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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 : privDecrypt() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDecrypt($p_encryption_header, &$p_buffer, $p_size, $p_crc) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::privDecrypt', "size=".$p_size.""); + $v_result=1; + + // ----- To Be Modified ;-) + $v_pwd = "test"; + + $p_buffer = PclZipUtilZipDecrypt($p_buffer, $p_size, $p_encryption_header, + $p_crc, $v_pwd); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDisableMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDisableMagicQuotes() + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::privDisableMagicQuotes', ""); + $v_result=1; + + // ----- Look if function exists + if ( (!function_exists("get_magic_quotes_runtime")) + || (!function_exists("set_magic_quotes_runtime"))) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Functions *et_magic_quotes_runtime are not supported"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Look if already done + if ($this->magic_quotes_status != -1) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "magic_quote already disabled"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Get and memorize the magic_quote value + $this->magic_quotes_status = @get_magic_quotes_runtime(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Current magic_quotes_runtime status is '".($this->magic_quotes_status==0?'disable':'enable')."'"); + + // ----- Disable magic_quotes + if ($this->magic_quotes_status == 1) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Disable magic_quotes"); + @set_magic_quotes_runtime(0); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privSwapBackMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privSwapBackMagicQuotes() + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::privSwapBackMagicQuotes', ""); + $v_result=1; + + // ----- Look if function exists + if ( (!function_exists("get_magic_quotes_runtime")) + || (!function_exists("set_magic_quotes_runtime"))) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Functions *et_magic_quotes_runtime are not supported"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Look if something to do + if ($this->magic_quotes_status != -1) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "magic_quote not modified"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Swap back magic_quotes + if ($this->magic_quotes_status == 1) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Enable back magic_quotes"); + @set_magic_quotes_runtime($this->magic_quotes_status); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + } + // End of class + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilPathReduction() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function PclZipUtilPathReduction($p_dir) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZipUtilPathReduction", "dir='$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; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Invalid path is unchanged"); + $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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZipUtilPathInclusion", "dir='$p_dir', path='$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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Replacing ./ by full path in p_dir '".$p_dir."'"); + } + if ( ($p_path == '.') + || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) { + $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Replacing ./ by full path in p_path '".$p_path."'"); + } + + // ----- 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)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Working on dir($i)='".$v_list_dir[$i]."' and path($j)='".$v_list_path[$j]."'"); + + // ----- 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] != '')) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Items ($i,$j) are different"); + $v_result = 0; + } + + // ----- Next items + $i++; + $j++; + } + + // ----- Look if everything seems to be the same + if ($v_result) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Look for tie break"); + // ----- 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++; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Looking on dir($i)='".($i < $v_list_dir_size?$v_list_dir[$i]:'')."' and path($j)='".($j < $v_list_path_size?$v_list_path[$j]:'')."'"); + + 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 + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZipUtilCopyBlock", "size=$p_size, mode=$p_mode"); + $v_result = 1; + + if ($p_mode==0) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Src offset before read :".(@ftell($p_src))); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Dest offset before write :".(@ftell($p_dest))); + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $v_buffer = @fread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Src offset after read :".(@ftell($p_src))); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Dest offset after write :".(@ftell($p_dest))); + } + else if ($p_mode==1) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $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); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $v_buffer = @gzread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZipUtilRename", "source=$p_src, destination=$p_dest"); + $v_result = 1; + + // ----- Try to rename the files + if (!@rename($p_src, $p_dest)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Fail to rename file, try copy+unlink"); + + // ----- Try to copy & unlink the src + if (!@copy($p_src, $p_dest)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Fail to copy file"); + $v_result = 0; + } + else if (!@unlink($p_src)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Fail to unlink old filename"); + $v_result = 0; + } + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZipUtilOptionText", "option='".$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)) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_key); + return $v_key; + } + } + + $v_result = 'Unknown'; + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + 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; + } + // -------------------------------------------------------------------------------- + + +?> diff --git a/BSF/admin/include/plugins.class.php b/BSF/admin/include/plugins.class.php new file mode 100644 index 000000000..de189ffc9 --- /dev/null +++ b/BSF/admin/include/plugins.class.php @@ -0,0 +1,484 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +class plugins +{ + var $fs_plugins = array(); + var $db_plugins_by_id = array(); + var $server_plugins; + + /** + * Initialize $fs_plugins and $db_plugins_by_id + */ + function plugins() + { + $this->get_fs_plugins(); + + foreach (get_db_plugins() as $db_plugin) + { + $this->db_plugins_by_id[$db_plugin['id']] = $db_plugin; + } + } + + /** + * 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" 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 ( 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) + { + foreach($this->fs_plugins as $fs_plugin) + { + if (isset($fs_plugin['extension'])) + { + $plugins_to_check[] = $fs_plugin['extension']; + } + } + $url = PEM_URL . '/uptodate.php?version=' . rawurlencode(PHPWG_VERSION) . '&extensions=' . implode(',', $plugins_to_check); + $url .= $new ? '&newext=Plugin' : ''; + + if (!empty($plugins_to_check) and $source = @file_get_contents($url)) + { + $this->server_plugins = @unserialize($source); + } + } + + /** + * 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; + } + } + + /** + * Extract plugin files from archive + * @param string - install or upgrade + * @param string - archive URL + * @param string - destination path + */ + function extract_plugin_files($action, $source, $dest) + { + if ($archive = tempnam( PHPWG_PLUGINS_PATH, 'zip')) + { + if (@copy(PEM_URL . str_replace(' ', '%20', $source), $archive)) + { + 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; + } + } + } + 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['version'], $b['version'])); + + return version_compare($array[0], $array[1], '>='); + } + + function extension_revision_compare($a, $b) + { + if ($a['date'] < $b['date']) return 1; + else return -1; + } + + function extension_name_compare($a, $b) + { + return strcmp(strtolower($a['ext_name']), strtolower($b['ext_name'])); + } + + function extension_author_compare($a, $b) + { + $r = strcasecmp($a['author'], $b['author']); + 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 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; + } +} +?>
\ No newline at end of file diff --git a/BSF/admin/include/tabsheet.class.php b/BSF/admin/include/tabsheet.class.php new file mode 100644 index 000000000..c295f0ae0 --- /dev/null +++ b/BSF/admin/include/tabsheet.class.php @@ -0,0 +1,146 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +class tabsheet +{ + var $sheets; + var $name; + var $titlename; + var $selected; + + /* + $name is the tabsheet's name inside the template .tpl file + $titlename in the template is affected by $titlename value + */ + function tabsheet($name = 'TABSHEET', $titlename = 'TABSHEET_TITLE') + { + $this->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', 'admin/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'); + } +} + +?> diff --git a/BSF/admin/index.php b/BSF/admin/index.php new file mode 100644 index 000000000..c15b15795 --- /dev/null +++ b/BSF/admin/index.php @@ -0,0 +1,30 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// Recursive call +$url = '../'; +header( 'Request-URI: '.$url ); +header( 'Content-Location: '.$url ); +header( 'Location: '.$url ); +exit(); +?> diff --git a/BSF/admin/intro.php b/BSF/admin/intro.php new file mode 100644 index 000000000..ed378d2d5 --- /dev/null +++ b/BSF/admin/intro.php @@ -0,0 +1,285 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); +include_once(PHPWG_ROOT_PATH.'admin/include/check_integrity.class.php'); +include_once(PHPWG_ROOT_PATH.'admin/include/c13y_internal.class.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | actions | +// +-----------------------------------------------------------------------+ + +// Check for upgrade : code inspired from punbb +if (isset($_GET['action']) and 'check_upgrade' == $_GET['action']) +{ + if (!ini_get('allow_url_fopen')) + { + array_push( + $page['errors'], + l10n('Unable to check for upgrade since allow_url_fopen is disabled.') + ); + } + else + { + $versions = array('current' => PHPWG_VERSION); + $lines = @file(PHPWG_URL.'/latest_version'); + + // 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' => 'admin/intro.tpl')); + +$php_current_timestamp = date("Y-m-d H:i:s"); +list($mysql_version, $db_current_timestamp) = mysql_fetch_row(pwg_query('SELECT VERSION(), CURRENT_TIMESTAMP;')); + +$query = ' +SELECT COUNT(*) + FROM '.IMAGES_TABLE.' +;'; +list($nb_elements) = mysql_fetch_row(pwg_query($query)); + +$query = ' +SELECT COUNT(*) + FROM '.CATEGORIES_TABLE.' +;'; +list($nb_categories) = mysql_fetch_row(pwg_query($query)); + +$query = ' +SELECT COUNT(*) + FROM '.CATEGORIES_TABLE.' + WHERE dir IS NULL +;'; +list($nb_virtual) = mysql_fetch_row(pwg_query($query)); + +$query = ' +SELECT COUNT(*) + FROM '.CATEGORIES_TABLE.' + WHERE dir IS NOT NULL +;'; +list($nb_physical) = mysql_fetch_row(pwg_query($query)); + +$query = ' +SELECT COUNT(*) + FROM '.IMAGE_CATEGORY_TABLE.' +;'; +list($nb_image_category) = mysql_fetch_row(pwg_query($query)); + +$query = ' +SELECT COUNT(*) + FROM '.TAGS_TABLE.' +;'; +list($nb_tags) = mysql_fetch_row(pwg_query($query)); + +$query = ' +SELECT COUNT(*) + FROM '.IMAGE_TAG_TABLE.' +;'; +list($nb_image_tag) = mysql_fetch_row(pwg_query($query)); + +$query = ' +SELECT COUNT(*) + FROM '.USERS_TABLE.' +;'; +list($nb_users) = mysql_fetch_row(pwg_query($query)); + +$query = ' +SELECT COUNT(*) + FROM '.GROUPS_TABLE.' +;'; +list($nb_groups) = mysql_fetch_row(pwg_query($query)); + +$query = ' +SELECT COUNT(*) + FROM '.COMMENTS_TABLE.' +;'; +list($nb_comments) = mysql_fetch_row(pwg_query($query)); + +$template->assign( + array( + 'PWG_VERSION' => PHPWG_VERSION, + 'OS' => PHP_OS, + 'PHP_VERSION' => phpversion(), + 'MYSQL_VERSION' => $mysql_version, + 'DB_ELEMENTS' => l10n_dec('%d element', '%d elements', $nb_elements), + 'DB_CATEGORIES' => + l10n_dec('cat_inclu_part1_S', 'cat_inclu_part1_P', + $nb_categories). + l10n_dec('cat_inclu_part2_S', 'cat_inclu_part2_P', + $nb_physical). + l10n_dec('cat_inclu_part3_S', 'cat_inclu_part3_P', + $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) = mysql_fetch_row(pwg_query($query)); + + $template->assign( + 'first_added', + array( + 'DB_DATE' => + sprintf( + l10n('first element added on %s'), + format_date($first_date, 'mysql_datetime') + ) + ) + ); +} + +// waiting elements +$query = ' +SELECT COUNT(*) + FROM '.WAITING_TABLE.' + WHERE validated=\'false\' +;'; +list($nb_waiting) = mysql_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) = mysql_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(); + +?> diff --git a/BSF/admin/maintenance.php b/BSF/admin/maintenance.php new file mode 100644 index 000000000..69268cf2c --- /dev/null +++ b/BSF/admin/maintenance.php @@ -0,0 +1,142 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | actions | +// +-----------------------------------------------------------------------+ + +$action = (isset($_GET['action']) and !is_adviser()) ? $_GET['action'] : ''; + +switch ($action) +{ + case 'categories' : + { + update_uppercats(); + update_category('all'); + update_global_rank(); + invalidate_user_cache(); + break; + } + case 'images' : + { + update_path(); + update_average_rate(); + break; + } + case 'history_detail' : + { + $query = ' +DELETE + FROM '.HISTORY_TABLE.' +;'; + pwg_query($query); + break; + } + case 'history_summary' : + { + $query = ' +DELETE + FROM '.HISTORY_SUMMARY_TABLE.' +;'; + pwg_query($query); + break; + } + case 'sessions' : + { + pwg_session_gc(); + break; + } + case 'feeds' : + { + $query = ' +DELETE + FROM '.USER_FEED_TABLE.' + WHERE last_check IS NULL +;'; + pwg_query($query); + break; + } + case 'database' : + { + do_maintenance_all_tables(); + break; + } + case 'c13y' : + { + include_once(PHPWG_ROOT_PATH.'admin/include/check_integrity.class.php'); + $c13y = new check_integrity(); + $c13y->maintenance(); + break; + } + case 'compiled-templates' : + { + $template->delete_compiled_templates(); + break; + } + default : + { + break; + } +} + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filenames(array('maintenance'=>'admin/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_COMPILED_TEMPLATES' => $start_url.'compiled-templates', + 'U_HELP' => PHPWG_ROOT_PATH.'popuphelp.php?page=maintenance', + ) + ); + +// +-----------------------------------------------------------------------+ +// | sending html code | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('ADMIN_CONTENT', 'maintenance'); +?>
\ No newline at end of file diff --git a/BSF/admin/notification_by_mail.php b/BSF/admin/notification_by_mail.php new file mode 100644 index 000000000..fc0a2d637 --- /dev/null +++ b/BSF/admin/notification_by_mail.php @@ -0,0 +1,738 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// +-----------------------------------------------------------------------+ +// | include | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); +include_once(PHPWG_ROOT_PATH.'admin/include/functions_notification_by_mail.inc.php'); +include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php'); +include_once(PHPWG_ROOT_PATH.'include/common.inc.php'); +include_once(PHPWG_ROOT_PATH.'include/functions_notification.inc.php'); +include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | Initialization | +// +-----------------------------------------------------------------------+ +$base_url = get_root_url().'admin.php'; +$must_repost = false; + +// +-----------------------------------------------------------------------+ +// | functions | +// +-----------------------------------------------------------------------+ + +/* + * Do timeout treatment in order to finish to send mails + * + * @param $post_keyname: key of check_key post array + * @param check_key_treated: array of check_key treated + * @return none + */ +function do_timeout_treatment($post_keyname, $check_key_treated = array()) +{ + global $env_nbm, $base_url, $page, $must_repost; + + if ($env_nbm['is_sendmail_timeout']) + { + if (isset($_POST[$post_keyname])) + { + $post_count = count($_POST[$post_keyname]); + $treated_count = count($check_key_treated); + if ($treated_count != 0) + { + $time_refresh = ceil((get_moment() - $env_nbm['start_time']) * $post_count / $treated_count); + } + else + { + $time_refresh = 0; + } + $_POST[$post_keyname] = array_diff($_POST[$post_keyname], $check_key_treated); + + $must_repost = true; + array_push($page['errors'], + l10n_dec('nbm_background_treatment_redirect_second', + 'nbm_background_treatment_redirect_seconds', + $time_refresh)); + } + } + +} + +/* + * Get the authorized_status for each tab + * return corresponding status + */ +function get_tab_status($mode) +{ + $result = ACCESS_WEBMASTER; + switch ($mode) + { + case 'param': + case 'subscribe': + $result = ACCESS_WEBMASTER; + break; + case 'send': + $result = ACCESS_ADMINISTRATOR; + break; + default: + $result = ACCESS_WEBMASTER; + break; + } + return $result; +} + +/* + * Inserting News users + */ +function insert_new_data_user_mail_notification() +{ + global $conf, $page, $env_nbm; + + // Set null mail_address empty + $query = ' +update + '.USERS_TABLE.' +set + '.$conf['user_fields']['email'].' = null +where + trim('.$conf['user_fields']['email'].') = \'\';'; + pwg_query($query); + + // null mail_address are not selected in the list + $query = ' +select + u.'.$conf['user_fields']['id'].' as user_id, + u.'.$conf['user_fields']['username'].' as username, + u.'.$conf['user_fields']['email'].' as mail_address +from + '.USERS_TABLE.' as u left join '.USER_MAIL_NOTIFICATION_TABLE.' as m on u.'.$conf['user_fields']['id'].' = m.user_id +where + u.'.$conf['user_fields']['email'].' is not null and + m.user_id is null +order by + user_id;'; + + $result = pwg_query($query); + + if (mysql_num_rows($result) > 0) + { + $inserts = array(); + $check_key_list = array(); + + while ($nbm_user = mysql_fetch_array($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('nbm_user_x_added'), + $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('nbm_redirect_msg')); + } + } + } +} + +/* + * 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) = mysql_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('nbm_break_timeout_send_mail'); + } + else + { + $msg_break_timeout = l10n('nbm_break_timeout_list_user'); + } + + // 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('nbm_object_news'); + + // 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($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'], + 'template' => $nbm_user['template'], + '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('nbm_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 = mysql_fetch_array($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('nbm_updated_param_count', 'nbm_updated_params_count', + $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' => 'admin/double_select.tpl', + 'notification_by_mail'=>'admin/notification_by_mail.tpl' + ) +); + +$template->assign +( + array + ( + 'U_HELP' => add_url_params(get_root_url().'popuphelp.php', array('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('nbm_param_mode'), + add_url_params($base_url.get_query_string_diff(array('mode', 'select')), + array('mode' => 'param'))); + $tabsheet->add('subscribe', l10n('nbm_subscribe_mode'), + add_url_params($base_url.get_query_string_diff(array('mode', 'select')), + array('mode' => 'subscribe'))); + $tabsheet->add('send', l10n('nbm_send_mode'), + 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('nbm_subscribe_col'), + 'L_CAT_OPTIONS_FALSE' => l10n('nbm_unsubscribe_col') + ) + ); + + $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'] ] = $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'] ] = $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<all + isset($_POST['send_selection']) and // not init + !in_array($nbm_user['check_key'], $_POST['send_selection']) // not selected + ) ? '' : 'checked="checked"', + 'USERNAME'=> $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'); + +?>
\ No newline at end of file diff --git a/BSF/admin/permalinks.php b/BSF/admin/permalinks.php new file mode 100644 index 000000000..ecae18965 --- /dev/null +++ b/BSF/admin/permalinks.php @@ -0,0 +1,179 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +function parse_sort_variables( + $sortable_by, $default_field, + $get_param, $get_rejects, + $template_var, + $anchor = '' ) +{ + global $template; + + $url_components = parse_url( $_SERVER['REQUEST_URI'] ); + + $base_url = $url_components['path']; + + parse_str($url_components['query'], $vars); + $is_first = true; + foreach ($vars as $key => $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 = '<em>'.$disp.'</em>'; + } + } + else + { + array_push($ret, $field); + $disp = '<em>'.$disp.'</em>'; + } + if ( isset($template_var) ) + { + $template->assign( $template_var.strtoupper($field), + '<a href="'.$url.$anchor.'" title="'.l10n('Sort order').'">'.$disp.'</a>' + ); + } + } + 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'; + pwg_query($query); + if (mysql_affected_rows()==0) + array_push($page['errors'], 'Cannot delete the old permalink !'); +} + + +$template->set_filename('permalinks', 'admin/permalinks.tpl' ); + +$query = ' +SELECT + id, + CONCAT(id, " - ", name, IF(permalink IS NULL, "", " √") ) 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=mysql_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=mysql_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().'popuphelp.php?page=permalinks'); + +$template->assign_var_from_handle('ADMIN_CONTENT', 'permalinks'); +?> diff --git a/BSF/admin/picture_modify.php b/BSF/admin/picture_modify.php new file mode 100644 index 000000000..2fbaf901b --- /dev/null +++ b/BSF/admin/picture_modify.php @@ -0,0 +1,437 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if(!defined("PHPWG_ROOT_PATH")) +{ + die('Hacking attempt!'); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | synchronize metadata | +// +-----------------------------------------------------------------------+ + +if (isset($_GET['sync_metadata']) and !is_adviser()) +{ + $query = ' +SELECT path + FROM '.IMAGES_TABLE.' + WHERE id = '.$_GET['image_id'].' +;'; + list($path) = mysql_fetch_row(pwg_query($query)); + update_metadata(array($_GET['image_id'] => $path)); + + array_push($page['infos'], l10n('Metadata synchronized from file')); +} + +//--------------------------------------------------------- update informations + +// first, we verify whether there is a mistake on the given creation date +if (isset($_POST['date_creation_action']) + and 'set' == $_POST['date_creation_action']) +{ + if (!checkdate( + $_POST['date_creation_month'], + $_POST['date_creation_day'], + $_POST['date_creation_year']) + ) + { + array_push($page['errors'], l10n('err_date')); + } +} + +if (isset($_POST['submit']) and count($page['errors']) == 0 and !is_adviser()) +{ + $data = array(); + $data{'id'} = $_GET['image_id']; + $data{'name'} = $_POST['name']; + $data{'author'} = $_POST['author']; + $data['level'] = $_POST['level']; + + if ($conf['allow_html_descriptions']) + { + $data{'comment'} = @$_POST['description']; + } + else + { + $data{'comment'} = strip_tags(@$_POST['description']); + } + + if (isset($_POST['date_creation_action'])) + { + if ('set' == $_POST['date_creation_action']) + { + $data{'date_creation'} = $_POST['date_creation_year'] + .'-'.$_POST['date_creation_month'] + .'-'.$_POST['date_creation_day']; + } + else if ('unset' == $_POST['date_creation_action']) + { + $data{'date_creation'} = ''; + } + } + + mass_updates( + IMAGES_TABLE, + array( + 'primary' => array('id'), + 'update' => array_diff(array_keys($data), array('id')) + ), + array($data) + ); + + set_tags( + isset($_POST['tags']) ? $_POST['tags'] : array(), + $_GET['image_id'] + ); + + array_push($page['infos'], l10n('Picture informations updated')); +} +// associate the element to other categories than its storage category +if (isset($_POST['associate']) + and isset($_POST['cat_dissociated']) + and count($_POST['cat_dissociated']) > 0 + and !is_adviser() + ) +{ + associate_images_to_categories( + array($_GET['image_id']), + $_POST['cat_dissociated'] + ); +} +// dissociate the element from categories (but not from its storage category) +if (isset($_POST['dissociate']) + and isset($_POST['cat_associated']) + and count($_POST['cat_associated']) > 0 + and !is_adviser() + ) +{ + $query = ' +DELETE FROM '.IMAGE_CATEGORY_TABLE.' + WHERE image_id = '.$_GET['image_id'].' + AND category_id IN ('.implode(',', $_POST['cat_associated']).') +'; + pwg_query($query); + + update_category($_POST['cat_associated']); +} +// elect the element to represent the given categories +if (isset($_POST['elect']) + and isset($_POST['cat_dismissed']) + and count($_POST['cat_dismissed']) > 0 + and !is_adviser() + ) +{ + $datas = array(); + foreach ($_POST['cat_dismissed'] as $category_id) + { + array_push($datas, + array('id' => $category_id, + 'representative_picture_id' => $_GET['image_id'])); + } + $fields = array('primary' => array('id'), + 'update' => array('representative_picture_id')); + mass_updates(CATEGORIES_TABLE, $fields, $datas); +} +// dismiss the element as representant of the given categories +if (isset($_POST['dismiss']) + and isset($_POST['cat_elected']) + and count($_POST['cat_elected']) > 0 + and !is_adviser() + ) +{ + set_random_representant($_POST['cat_elected']); +} + +// retrieving direct information about picture +$query = ' +SELECT * + FROM '.IMAGES_TABLE.' + WHERE id = '.$_GET['image_id'].' +;'; +$row = mysql_fetch_array(pwg_query($query)); + +$storage_category_id = $row['storage_category_id']; +$image_file = $row['file']; + +// tags +$query = ' +SELECT tag_id + FROM '.IMAGE_TAG_TABLE.' + WHERE image_id = '.$_GET['image_id'].' +;'; +$selected_tags = array_from_query($query, 'tag_id'); + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filenames( + array( + 'picture_modify' => 'admin/picture_modify.tpl' + ) + ); + +$all_tags = get_all_tags(); + +if (count($all_tags) > 0) +{ + $tag_selection = get_html_tag_selection( + $all_tags, + 'tags', + $selected_tags + ); +} +else +{ + $tag_selection = + '<p>'. + l10n('No tag defined. Use Administration>Pictures>Tags'). + '</p>'; +} + +$template->assign( + array( + 'U_SYNC' => + get_root_url().'admin.php?page=picture_modify'. + '&image_id='.$_GET['image_id']. + (isset($_GET['cat_id']) ? '&cat_id='.$_GET['cat_id'] : ''). + '&sync_metadata=1', + + 'PATH'=>$row['path'], + + 'TN_SRC' => get_thumbnail_url($row), + + 'NAME' => + isset($_POST['name']) ? + stripslashes($_POST['name']) : @$row['name'], + + 'DIMENSIONS' => @$row['width'].' * '.@$row['height'], + + 'FILESIZE' => @$row['filesize'].' KB', + + 'REGISTRATION_DATE' => + format_date($row['date_available'], 'mysql_datetime', false), + + 'AUTHOR' => isset($_POST['author']) ? $_POST['author'] : @$row['author'], + + 'TAG_SELECTION' => $tag_selection, + + 'DESCRIPTION' => + htmlspecialchars( isset($_POST['description']) ? + stripslashes($_POST['description']) : @$row['comment'] ), + + 'F_ACTION' => + get_root_url().'admin.php' + .get_query_string_diff(array('sync_metadata')) + ) + ); + +if ($row['has_high'] == 'true') +{ + $template->assign( + 'HIGH_FILESIZE', + isset($row['high_filesize']) + ? $row['high_filesize'].' KB' + : l10n('unknown') + ); +} + +// image level options +$tpl_options = array(); +foreach ($conf['available_permission_levels'] as $level) +{ + $tpl_options[$level] = l10n( sprintf('Level %d', $level) ).' ('.$level.')'; +} +$selected_level = isset($_POST['level']) ? $_POST['level'] : $row['level']; +$template->assign( + array( + 'level_options'=> $tpl_options, + 'level_options_selected' => array($selected_level) + ) + ); + +// creation date +unset($day, $month, $year); + +if (isset($_POST['date_creation_action']) + and 'set' == $_POST['date_creation_action']) +{ + foreach (array('day', 'month', 'year') as $varname) + { + $$varname = $_POST['date_creation_'.$varname]; + } +} +else if (isset($row['date_creation']) and !empty($row['date_creation'])) +{ + list($year, $month, $day) = explode('-', $row['date_creation']); +} +else +{ + list($year, $month, $day) = array('', 0, 0); +} + + +$month_list = $lang['month']; +$month_list[0]='------------'; +ksort($month_list); + +$template->assign( + array( + 'DATE_CREATION_DAY_VALUE' => $day, + 'DATE_CREATION_MONTH_VALUE' => $month, + 'DATE_CREATION_YEAR_VALUE' => $year, + 'month_list' => $month_list, + ) + ); + +$query = ' +SELECT category_id, uppercats + FROM '.IMAGE_CATEGORY_TABLE.' AS ic + INNER JOIN '.CATEGORIES_TABLE.' AS c + ON c.id = ic.category_id + WHERE image_id = '.$_GET['image_id'].' +;'; +$result = pwg_query($query); + +while ($row = mysql_fetch_array($result)) +{ + $name = + get_cat_display_name_cache( + $row['uppercats'], + get_root_url().'admin.php?page=cat_modify&cat_id=', + false + ); + + if ($row['category_id'] == $storage_category_id) + { + $template->assign('STORAGE_CATEGORY', $name); + } + else + { + $template->append('related_categories', $name); + } +} + +// jump to link +// +// 1. find all linked categories that are reachable for the current user. +// 2. if a category is available in the URL, use it if reachable +// 3. if URL category not available or reachable, use the first reachable +// linked category +// 4. if no category reachable, no jumpto link + +$query = ' +SELECT category_id + FROM '.IMAGE_CATEGORY_TABLE.' + WHERE image_id = '.$_GET['image_id'].' +;'; + +$authorizeds = array_diff( + array_from_query($query, 'category_id'), + explode( + ',', + calculate_permissions($user['id'], $user['status']) + ) + ); + +if (isset($_GET['cat_id']) + and in_array($_GET['cat_id'], $authorizeds)) +{ + $url_img = make_picture_url( + array( + 'image_id' => $_GET['image_id'], + 'image_file' => $image_file, + 'category' => $cache['cat_names'][ $_GET['cat_id'] ], + ) + ); +} +else +{ + foreach ($authorizeds as $category) + { + $url_img = make_picture_url( + array( + 'image_id' => $_GET['image_id'], + 'image_file' => $image_file, + 'category' => $cache['cat_names'][ $category ], + ) + ); + break; + } +} + +if (isset($url_img)) +{ + $template->assign( 'U_JUMPTO', $url_img ); +} + +// associate to another category ? +$query = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = category_id + WHERE image_id = '.$_GET['image_id'].' + AND id != '.$storage_category_id.' +;'; +display_select_cat_wrapper($query, array(), 'associated_options'); + +$result = pwg_query($query); +$associateds = array($storage_category_id); +while ($row = mysql_fetch_array($result)) +{ + array_push($associateds, $row['id']); +} +$query = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE id NOT IN ('.implode(',', $associateds).') +;'; +display_select_cat_wrapper($query, array(), 'dissociated_options'); + +// representing +$query = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE representative_picture_id = '.$_GET['image_id'].' +;'; +display_select_cat_wrapper($query, array(), 'elected_options'); + +$query = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE representative_picture_id != '.$_GET['image_id'].' + OR representative_picture_id IS NULL +;'; +display_select_cat_wrapper($query, array(), 'dismissed_options'); + +//----------------------------------------------------------- sending html code + +$template->assign_var_from_handle('ADMIN_CONTENT', 'picture_modify'); +?> diff --git a/BSF/admin/plugin.php b/BSF/admin/plugin.php new file mode 100644 index 000000000..3b4055230 --- /dev/null +++ b/BSF/admin/plugin.php @@ -0,0 +1,62 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if( !defined("PHPWG_ROOT_PATH") ) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); +check_status(ACCESS_ADMINISTRATOR); + +$sections = explode('/', $_GET['section'] ); +for ($i=0; $i<count($sections); $i++) +{ + if (empty($sections[$i]) or $sections[$i]=='..') + { + unset($sections[$i]); + $i--; + } +} + +if (count($sections)<2) +{ + die('Invalid plugin URL'); +} + +$plugin_id = $sections[0]; +if ( !isset($pwg_loaded_plugins[$plugin_id]) ) +{ + die('Invalid URL - plugin '.$plugin_id.' not active'); +} + +$filename = PHPWG_PLUGINS_PATH.implode('/', $sections); +if (is_file($filename)) +{ + include_once($filename); +} +else +{ + die('Missing file '.$filename); +} +?>
\ No newline at end of file diff --git a/BSF/admin/plugins_list.php b/BSF/admin/plugins_list.php new file mode 100644 index 000000000..ca8033164 --- /dev/null +++ b/BSF/admin/plugins_list.php @@ -0,0 +1,154 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if( !defined("PHPWG_ROOT_PATH") ) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/plugins.class.php'); + +$template->set_filenames(array('plugins' => 'admin/plugins_list.tpl')); + +$order = isset($_GET['order']) ? $_GET['order'] : 'name'; +$base_url = get_root_url().'admin.php?page='.$page['page'].'&order='.$order; + +$plugins = new plugins(); + +//--------------------------------------------------perform requested actions +if (isset($_GET['action']) and isset($_GET['plugin']) and !is_adviser()) +{ + $page['errors'] = + $plugins->perform_action($_GET['action'], $_GET['plugin']); + + if (empty($page['errors'])) redirect($base_url); +} + +//--------------------------------------------------------------------Tabsheet +set_plugins_tabsheet($page['page']); + +//---------------------------------------------------------------Order options +$link = get_root_url().'admin.php?page='.$page['page'].'&order='; +$template->assign('order_options', + array( + $link.'name' => l10n('Name'), + $link.'status' => l10n('Status'), + $link.'author' => l10n('Author'), + $link.'id' => 'Id')); +$template->assign('order_selected', $link.$order); + +// +-----------------------------------------------------------------------+ +// | start template output | +// +-----------------------------------------------------------------------+ +$plugins->sort_fs_plugins($order); + +foreach($plugins->fs_plugins as $plugin_id => $fs_plugin) +{ + $display_name = $fs_plugin['name']; + if (!empty($fs_plugin['uri'])) + { + $display_name = '<a href="' . $fs_plugin['uri'] + . '" onclick="window.open(this.href); return false;">' + . $display_name . '</a>'; + } + $desc = $fs_plugin['description']; + if (!empty($fs_plugin['author'])) + { + $desc .= ' (<em>'; + if (!empty($fs_plugin['author uri'])) + { + $desc .= '<a href="' . $fs_plugin['author uri'] . '">' + . $fs_plugin['author'] . '</a>'; + } + else + { + $desc .= $fs_plugin['author']; + } + $desc .= '</em>)'; + } + $tpl_plugin = + array('NAME' => $display_name, + 'VERSION' => $fs_plugin['version'], + 'DESCRIPTION' => $desc); + + $action_url = $base_url.'&plugin='.$plugin_id; + + if (isset($plugins->db_plugins_by_id[$plugin_id])) + { + $tpl_plugin['STATE'] = $plugins->db_plugins_by_id[$plugin_id]['state']; + switch ($plugins->db_plugins_by_id[$plugin_id]['state']) + { + case 'active': + $tpl_plugin['actions'][] = + array('U_ACTION' => $action_url . '&action=deactivate', + 'L_ACTION' => l10n('Deactivate')); + break; + + case 'inactive': + $tpl_plugin['actions'][] = + array('U_ACTION' => $action_url . '&action=activate', + 'L_ACTION' => l10n('Activate')); + $tpl_plugin['actions'][] = + array('U_ACTION' => $action_url . '&action=uninstall', + 'L_ACTION' => l10n('Uninstall'), + 'CONFIRM' => l10n('Are you sure?')); + break; + } + } + else + { + $tpl_plugin['actions'][] = + array('U_ACTION' => $action_url . '&action=install', + 'L_ACTION' => l10n('Install'), + 'CONFIRM' => l10n('Are you sure?')); + $tpl_plugin['actions'][] = + array('U_ACTION' => $action_url . '&action=delete', + 'L_ACTION' => l10n('plugins_delete'), + 'CONFIRM' => l10n('plugins_confirm_delete')); + } + $template->append('plugins', $tpl_plugin); +} + +$missing_plugin_ids = array_diff( + array_keys($plugins->db_plugins_by_id), array_keys($plugins->fs_plugins) + ); + +foreach($missing_plugin_ids as $plugin_id) +{ + $action_url = $base_url.'&plugin='.$plugin_id; + + $template->append( 'plugins', + array( + 'NAME' => $plugin_id, + 'VERSION' => $plugins->db_plugins_by_id[$plugin_id]['version'], + 'DESCRIPTION' => "ERROR: THIS PLUGIN IS MISSING BUT IT IS INSTALLED! UNINSTALL IT NOW !", + 'actions' => array ( array ( + 'U_ACTION' => $action_url . '&action=uninstall', + 'L_ACTION' => l10n('Uninstall'), + ) ) + ) + ); +} + +$template->assign_var_from_handle('ADMIN_CONTENT', 'plugins'); +?>
\ No newline at end of file diff --git a/BSF/admin/plugins_new.php b/BSF/admin/plugins_new.php new file mode 100644 index 000000000..31171b443 --- /dev/null +++ b/BSF/admin/plugins_new.php @@ -0,0 +1,139 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if( !defined("PHPWG_ROOT_PATH") ) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/plugins.class.php'); + +$template->set_filenames(array('plugins' => 'admin/plugins_new.tpl')); + +$order = isset($_GET['order']) ? $_GET['order'] : 'date'; +$base_url = get_root_url().'admin.php?page='.$page['page'].'&order='.$order; + +$plugins = new plugins(); + +//------------------------------------------------------automatic installation +if (isset($_GET['install']) and isset($_GET['extension']) and !is_adviser()) +{ + $install_status = + $plugins->extract_plugin_files('install', $_GET['install'], $_GET['extension']); + + redirect($base_url.'&installstatus='.$install_status); +} + +//--------------------------------------------------------------install result +if (isset($_GET['installstatus'])) +{ + switch ($_GET['installstatus']) + { + case 'ok': + array_push($page['infos'], + l10n('plugins_install_ok'), + l10n('plugins_install_need_activate')); + break; + + case 'temp_path_error': + array_push($page['errors'], l10n('plugins_temp_path_error')); + break; + + case 'dl_archive_error': + array_push($page['errors'], l10n('plugins_dl_archive_error')); + break; + + case 'archive_error': + array_push($page['errors'], l10n('plugins_archive_error')); + break; + + default: + array_push($page['errors'], + sprintf(l10n('plugins_extract_error'), $_GET['installstatus']), + l10n('plugins_check_chmod')); + } +} + +//--------------------------------------------------------------------Tabsheet +set_plugins_tabsheet($page['page']); + +//---------------------------------------------------------------Order options +$link = get_root_url().'admin.php?page='.$page['page'].'&order='; +$template->assign('order_options', + array( + $link.'date' => l10n('Post date'), + $link.'revision' => l10n('plugins_revisions'), + $link.'name' => l10n('Name'), + $link.'author' => l10n('Author'))); +$template->assign('order_selected', $link.$order); + +// +-----------------------------------------------------------------------+ +// | start template output | +// +-----------------------------------------------------------------------+ +$plugins->get_server_plugins(true); + +if (is_array($plugins->server_plugins)) +{ + $plugins->sort_server_plugins($order); + + foreach($plugins->server_plugins as $plugin) + { + $ext_desc = nl2br(htmlspecialchars(strip_tags( + utf8_encode($plugin['ext_description'])))); + + $ver_desc = sprintf(l10n('plugins_description'), + $plugin['version'], + date('Y-m-d', $plugin['date']), + nl2br(htmlspecialchars(strip_tags( + utf8_encode($plugin['description']))))); + + $url_auto_install = htmlentities($base_url) + . '&extension=' . $plugin['id_extension'] + . '&install=%2Fupload%2Fextension-' . $plugin['id_extension'] + . '%2Frevision-' . $plugin['id_revision'] . '%2F' + . str_replace(' ', '%20',$plugin['url']); + + $url_download = PEM_URL .'/upload/extension-'.$plugin['id_extension'] + . '/revision-' . $plugin['id_revision'] + . '/' . str_replace(' ', '%20',$plugin['url']); + + $template->append('plugins', + array('EXT_NAME' => $plugin['ext_name'], + 'EXT_URL' => PEM_URL.'/extension_view.php?eid='.$plugin['id_extension'], + 'EXT_DESC' => $ext_desc, + 'VERSION' => $plugin['version'], + 'VERSION_URL' => PEM_URL.'/revision_view.php?rid='.$plugin['id_revision'], + 'DATE' => date('Y-m-d', $plugin['date']), + 'VER_DESC' => $ver_desc, + 'AUTHOR' => $plugin['author'], + 'URL_INSTALL' => $url_auto_install, + 'URL_DOWNLOAD' => $url_download)); + } +} +else +{ + array_push($page['errors'], l10n('plugins_server_error')); +} + +$template->assign_var_from_handle('ADMIN_CONTENT', 'plugins'); +?>
\ No newline at end of file diff --git a/BSF/admin/plugins_update.php b/BSF/admin/plugins_update.php new file mode 100644 index 000000000..bdb8c5b9d --- /dev/null +++ b/BSF/admin/plugins_update.php @@ -0,0 +1,169 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if( !defined("PHPWG_ROOT_PATH") ) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/plugins.class.php'); + +$template->set_filenames(array('plugins' => 'admin/plugins_update.tpl')); + +$base_url = get_root_url().'admin.php?page='.$page['page']; + +$plugins = new plugins(); + +//-----------------------------------------------------------automatic upgrade +if (isset($_GET['upgrade']) and isset($_GET['plugin']) and !is_adviser()) +{ + $plugin_id = $_GET['plugin']; + + if (isset($plugins->db_plugins_by_id[$plugin_id]) + and $plugins->db_plugins_by_id[$plugin_id]['state'] == 'active') + { + $plugins->perform_action('deactivate', $plugin_id); + + redirect($base_url + . '&upgrade=' . $_GET['upgrade'] + . '&plugin=' . $plugin_id + . '&reactivate=true'); + } + + $upgrade_status = + $plugins->extract_plugin_files('upgrade', $_GET['upgrade'], $plugin_id); + + if (isset($_GET['reactivate'])) + { + $plugins->perform_action('activate', $plugin_id); + } + redirect($base_url.'&plugin='.$plugin_id.'&upgradestatus='.$upgrade_status); +} + +//--------------------------------------------------------------upgrade result +if (isset($_GET['upgradestatus']) and isset($_GET['plugin'])) +{ + switch ($_GET['upgradestatus']) + { + case 'ok': + array_push($page['infos'], + sprintf( + l10n('plugins_upgrade_ok'), + $plugins->fs_plugins[$_GET['plugin']]['name'])); + break; + + case 'temp_path_error': + array_push($page['errors'], l10n('plugins_temp_path_error')); + break; + + case 'dl_archive_error': + array_push($page['errors'], l10n('plugins_dl_archive_error')); + break; + + case 'archive_error': + array_push($page['errors'], l10n('plugins_archive_error')); + break; + + default: + array_push($page['errors'], + sprintf(l10n('plugins_extract_error'), $_GET['installstatus']), + l10n('plugins_check_chmod')); + } +} + +//--------------------------------------------------------------------Tabsheet +set_plugins_tabsheet($page['page']); + +// +-----------------------------------------------------------------------+ +// | start template output | +// +-----------------------------------------------------------------------+ +$plugins->get_server_plugins(); + +if (is_array($plugins->server_plugins)) +{ + foreach($plugins->fs_plugins as $plugin_id => $fs_plugin) + { + if (isset($fs_plugin['extension']) + and isset($plugins->server_plugins[$fs_plugin['extension']])) + { + $plugin_info = $plugins->server_plugins[$fs_plugin['extension']]; + + $ext_desc = nl2br(htmlspecialchars(strip_tags( + utf8_encode($plugin_info['ext_description'])))); + + $ver_desc = sprintf(l10n('plugins_description'), + $plugin_info['version'], + date('Y-m-d', $plugin_info['date']), + nl2br(htmlspecialchars(strip_tags( + utf8_encode($plugin_info['description']))))); + + if ($plugins->plugin_version_compare($fs_plugin, $plugin_info)) + { + // Plugin is up to date + $template->append('plugins_uptodate', + array('URL' => $fs_plugin['uri'], + 'NAME' => $fs_plugin['name'], + 'EXT_DESC' => $ext_desc, + 'VERSION' => $fs_plugin['version'])); + } + else + { + // Plugin need upgrade + $url_auto_update = $base_url + . '&plugin=' . $plugin_id + . '&upgrade=%2Fupload%2Fextension-' . $fs_plugin['extension'] + . '%2Frevision-' . $plugin_info['id_revision'] + . '%2F' . str_replace(' ', '%20',$plugin_info['url']); + + $url_download = PEM_URL.'/upload/extension-'. $fs_plugin['extension'] + . '/revision-' . $plugin_info['id_revision'] + . '/' . str_replace(' ', '%20',$plugin_info['url']); + + $template->append('plugins_not_uptodate', + array('EXT_NAME' => $fs_plugin['name'], + 'EXT_URL' => $fs_plugin['uri'], + 'EXT_DESC' => $ext_desc, + 'VERSION' => $fs_plugin['version'], + 'VERSION_URL' => PEM_URL.'/revision_view.php?rid='.$plugin_info['id_revision'], + 'NEW_VERSION' => $plugin_info['version'], + 'NEW_VER_DESC' => $ver_desc, + 'URL_UPDATE' => $url_auto_update, + 'URL_DOWNLOAD' => $url_download)); + } + } + else + { + // Can't check plugin + $template->append('plugins_cant_check', + array('NAME' => $fs_plugin['name'], + 'VERSION' => $fs_plugin['version'])); + } + } +} +else +{ + array_push($page['errors'], l10n('plugins_server_error')); +} + +$template->assign_var_from_handle('ADMIN_CONTENT', 'plugins'); +?>
\ No newline at end of file diff --git a/BSF/admin/profile.php b/BSF/admin/profile.php new file mode 100644 index 000000000..7c4244494 --- /dev/null +++ b/BSF/admin/profile.php @@ -0,0 +1,46 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if( !defined("PHPWG_ROOT_PATH") ) die ("Hacking attempt!"); + +$edit_user = build_user( $_GET['user_id'], false ); + +include_once(PHPWG_ROOT_PATH.'profile.php'); + + +$errors = array(); +if ( !is_adviser() ) +{ + save_profile_from_post($edit_user, $errors); +} + +load_profile_in_template( + get_root_url().'admin.php?page=profile&user_id='.$edit_user['id'], + get_root_url().'admin.php?page=user_list', + $edit_user + ); +$page['errors'] = array_merge($page['errors'], $errors); + +$template->set_filename('profile', 'admin/profile.tpl'); +$template->assign_var_from_handle('ADMIN_CONTENT', 'profile'); +?> diff --git a/BSF/admin/rating.php b/BSF/admin/rating.php new file mode 100644 index 000000000..18557b329 --- /dev/null +++ b/BSF/admin/rating.php @@ -0,0 +1,258 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | initialization | +// +-----------------------------------------------------------------------+ +if (isset($_GET['start']) and is_numeric($_GET['start'])) +{ + $start = $_GET['start']; +} +else +{ + $start = 0; +} + +$elements_per_page=10; +if (isset($_GET['display']) and is_numeric($_GET['display'])) +{ + $elements_per_page = $_GET['display']; +} + +$order_by_index=0; +if (isset($_GET['order_by']) and is_numeric($_GET['order_by'])) +{ + $order_by_index = $_GET['order_by']; +} + +$page['user_filter'] = ''; +if (isset($_GET['users'])) +{ + if ($_GET['users'] == 'user') + { + $page['user_filter'] = ' AND r.user_id <> '.$conf['guest_id']; + } + elseif ($_GET['users'] == 'guest') + { + $page['user_filter'] = ' AND r.user_id = '.$conf['guest_id']; + } +} + +if (isset($_GET['del']) and !is_adviser()) +{ + $del_params = urldecode( $_GET['del'] ); + parse_str($del_params, $vars); + if ( !is_numeric($vars['e']) or !is_numeric($vars['u']) ) + { + die('Hacking attempt'); + } + $query = ' +DELETE FROM '. RATE_TABLE .' +WHERE element_id=' . $vars['e'] . ' +AND user_id=' . $vars['u'] . ' +AND anonymous_id=\'' . $vars['a'] . '\' +;'; + pwg_query($query); + update_average_rate( $vars['e'] ); +} + +$users = array(); +$query = ' +SELECT '.$conf['user_fields']['username'].' as username, '.$conf['user_fields']['id'].' as id + FROM '.USERS_TABLE.' +;'; +$result = pwg_query($query); +while ($row = mysql_fetch_array($result)) +{ + $users[$row['id']]=$row['username']; +} + + +$query = 'SELECT COUNT(DISTINCT(i.id)) +FROM '.RATE_TABLE.' AS r, '.IMAGES_TABLE.' AS i +WHERE r.element_id=i.id'. $page['user_filter'] . +';'; +list($nb_images) = mysql_fetch_row(pwg_query($query)); + + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filename('rating', 'admin/rating.tpl'); + +$template->assign( + array( + 'NAVBAR' => create_navigation_bar( + PHPWG_ROOT_PATH.'admin.php'.get_query_string_diff(array('start','del')), + $nb_images, + $start, + $elements_per_page + ), + 'F_ACTION' => PHPWG_ROOT_PATH.'admin.php', + 'DISPLAY' => $elements_per_page, + 'NB_ELEMENTS' => $nb_images, + ) + ); + + + +$available_order_by= array( + array(l10n('Rate date'), 'recently_rated DESC'), + array(l10n('Average rate'), 'average_rate DESC'), + array(l10n('Number of rates'), 'nb_rates DESC'), + array(l10n('Sum of rates'), 'sum_rates DESC'), + array(l10n('Controversy'), 'std_rates DESC'), + array(l10n('File name'), 'file DESC'), + array(l10n('Creation date'), 'date_creation DESC'), + array(l10n('Post date'), 'date_available DESC'), + + ); + +for ($i=0; $i<count($available_order_by); $i++) +{ + $template->append( + 'order_by_options', + $available_order_by[$i][0] + ); +} +$template->assign('order_by_options_selected', array($order_by_index) ); + + +$user_options = array( + 'all' => l10n('all'), + 'user' => l10n('Users'), + 'guest' => l10n('Guests'), + ); + +$template->assign('user_options', $user_options ); +$template->assign('user_options_selected', array(@$_GET['users']) ); + + +$query = ' +SELECT i.id, + i.path, + i.file, + i.tn_ext, + i.average_rate, + i.storage_category_id, + MAX(r.date) AS recently_rated, + COUNT(r.rate) AS nb_rates, + SUM(r.rate) AS sum_rates, + ROUND(STD(r.rate),2) AS std_rates + FROM '.RATE_TABLE.' AS r + LEFT JOIN '.IMAGES_TABLE.' AS i ON r.element_id = i.id + WHERE 1 = 1 ' . $page['user_filter'] . ' + GROUP BY r.element_id + ORDER BY ' . $available_order_by[$order_by_index][1] .' + LIMIT '.$start.','.$elements_per_page.' +;'; + +$images = array(); +$result = pwg_query($query); +while ($row = mysql_fetch_assoc($result)) +{ + array_push($images, $row); +} + +$template->assign( 'images', array() ); +foreach ($images as $image) +{ + $thumbnail_src = get_thumbnail_url($image); + + $image_url = PHPWG_ROOT_PATH.'admin.php?page=picture_modify'. + '&image_id='.$image['id']; + + $query = 'SELECT * +FROM '.RATE_TABLE.' AS r +WHERE r.element_id='.$image['id'] . ' +ORDER BY date DESC;'; + $result = pwg_query($query); + $nb_rates = mysql_num_rows($result); + + $tpl_image = + array( + 'U_THUMB' => $thumbnail_src, + 'U_URL' => $image_url, + 'AVG_RATE' => $image['average_rate'], + 'STD_RATE' => $image['std_rates'], + 'SUM_RATE' => $image['sum_rates'], + 'NB_RATES' => (int)$image['nb_rates'], + 'NB_RATES_TOTAL' => (int)$nb_rates, + 'FILE' => $image['file'], + 'rates' => array() + ); + + while ($row = mysql_fetch_array($result)) + { + + $url_del = PHPWG_ROOT_PATH.'admin.php'. + get_query_string_diff(array('del')); + + $del_param = 'e='.$image['id']. + '&u='.$row['user_id']. + '&a='.$row['anonymous_id']; + + $url_del .= '&del='.urlencode(urlencode($del_param)); + + if ( isset($users[$row['user_id']]) ) + { + $user = $users[$row['user_id']]; + } + else + { + $user = '? '. $row['user_id']; + } + if ( strlen($row['anonymous_id'])>0 ) + { + $user .= '('.$row['anonymous_id'].')'; + } + + $tpl_image['rates'][] = + array( + 'DATE' => format_date($row['date']), + 'RATE' => $row['rate'], + 'USER' => $user, + 'U_DELETE' => $url_del + ); + } + $template->append( 'images', $tpl_image ); +} + +// +-----------------------------------------------------------------------+ +// | sending html code | +// +-----------------------------------------------------------------------+ +$template->assign_var_from_handle('ADMIN_CONTENT', 'rating'); +?> diff --git a/BSF/admin/site_manager.php b/BSF/admin/site_manager.php new file mode 100644 index 000000000..def9fe579 --- /dev/null +++ b/BSF/admin/site_manager.php @@ -0,0 +1,307 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +/** + * requests the given $url (a remote create_listing_file.php) and fills a + * list of lines corresponding to request output + * + * @param string $url + * @return void + */ +function remote_output($url) +{ + global $template, $page; + + if($lines = @file($url)) + { + // cleaning lines from HTML tags + foreach ($lines as $line) + { + $line = trim(strip_tags($line)); + if (preg_match('/^PWG-([A-Z]+)-/', $line, $matches)) + { + $template->append( + 'remote_output', + array( + 'CLASS' => 'remote'.ucfirst(strtolower($matches[1])), + 'CONTENT' => $line + ) + ); + } + } + } + else + { + array_push($page['errors'], l10n('site_err_remote_file_not_found')); + } +} + + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ +$template->set_filenames(array('site_manager'=>'admin/site_manager.tpl')); + +// +-----------------------------------------------------------------------+ +// | new site creation form | +// +-----------------------------------------------------------------------+ +if (isset($_POST['submit']) and !empty($_POST['galleries_url']) + and !is_adviser() ) +{ + $is_remote = url_is_remote( $_POST['galleries_url'] ); + $url = preg_replace('/[\/]*$/', '', $_POST['galleries_url']); + $url.= '/'; + if (! $is_remote) + { + if ( ! (strpos($url, '.') === 0 ) ) + { + $url = './' . $url; + } + } + + // site must not exists + $query = ' +SELECT COUNT(id) AS count + FROM '.SITES_TABLE.' + WHERE galleries_url = \''.$url.'\' +;'; + $row = mysql_fetch_array(pwg_query($query)); + if ($row['count'] > 0) + { + array_push($page['errors'], + l10n('site_already_exists').' ['.$url.']'); + } + if (count($page['errors']) == 0) + { + if ($is_remote) + { + if ( ! isset($_POST['no_check']) ) + { + $clf_url = $url.'create_listing_file.php'; + $clf_url.= '?action=test'; + $clf_url.= '&version='.PHPWG_VERSION; + if ( ($lines = @file($clf_url)) !== false) + { + $first_line = strip_tags($lines[0]); + if (!preg_match('/^PWG-INFO-2:/', $first_line)) + { + array_push($page['errors'], + l10n('site_err').' : '.$first_line); + } + } + else + { + array_push($page['errors'], l10n('site_err_remote_file_not_found') ); + } + } + } + else + { // local directory + if ( ! file_exists($url) ) + { + array_push($page['errors'], + l10n('Directory does not exist').' ['.$url.']'); + } + } + } + + if (count($page['errors']) == 0) + { + $query = ' +INSERT INTO '.SITES_TABLE.' + (galleries_url) + VALUES + (\''.$url.'\') +;'; + pwg_query($query); + array_push($page['infos'], + $url.' '.l10n('site_created')); + } +} + +// +-----------------------------------------------------------------------+ +// | actions on site | +// +-----------------------------------------------------------------------+ +if (isset($_GET['site']) and is_numeric($_GET['site'])) +{ + $page['site'] = $_GET['site']; +} +if (isset($_GET['action']) and isset($page['site']) and !is_adviser()) +{ + $query = ' +SELECT galleries_url + FROM '.SITES_TABLE.' + WHERE id = '.$page['site'].' +;'; + list($galleries_url) = mysql_fetch_array(pwg_query($query)); + switch($_GET['action']) + { + case 'generate' : + { + $title = $galleries_url.' : '.l10n('remote_site_generate'); + remote_output($galleries_url.'create_listing_file.php?action=generate'); + break; + } + case 'test' : + { + $title = $galleries_url.' : '.l10n('remote_site_test'); + remote_output($galleries_url.'create_listing_file.php?action=test&version='.PHPWG_VERSION); + break; + } + case 'clean' : + { + $title = $galleries_url.' : '.l10n('remote_site_clean'); + remote_output($galleries_url.'create_listing_file.php?action=clean'); + break; + } + case 'delete' : + { + delete_site($page['site']); + array_push($page['infos'], + $galleries_url.' '.l10n('site_deleted')); + break; + } + } +} + +$template->assign( array( + 'U_HELP' => get_root_url().'popuphelp.php?page=site_manager', + 'F_ACTION' => get_root_url().'admin.php' + .get_query_string_diff( array('action','site') ) + ) ); + +// +-----------------------------------------------------------------------+ +// | remote sites list | +// +-----------------------------------------------------------------------+ + +if ( is_file(PHPWG_ROOT_PATH.'listing.xml') ) +{ + $xml_content = getXmlCode(PHPWG_ROOT_PATH.'listing.xml'); + $local_listing_site_url = getAttribute( + getChild($xml_content, 'informations'), + 'url' + ); + if ( !url_is_remote($local_listing_site_url) ) + { + $local_listing_site_url = null; + } +} + +$query = ' +SELECT c.site_id, COUNT(DISTINCT c.id) AS nb_categories, COUNT(i.id) AS nb_images + FROM '.CATEGORIES_TABLE.' AS c LEFT JOIN '.IMAGES_TABLE.' AS i + ON c.id=i.storage_category_id + WHERE c.site_id IS NOT NULL + GROUP BY c.site_id +;'; +$sites_detail = hash_from_query($query, 'site_id'); + +$query = ' +SELECT * + FROM '.SITES_TABLE.' +;'; +$result = pwg_query($query); + +while ($row = mysql_fetch_array($result)) +{ + $is_remote = url_is_remote($row['galleries_url']); + $base_url = PHPWG_ROOT_PATH.'admin.php'; + $base_url.= '?page=site_manager'; + $base_url.= '&site='.$row['id']; + $base_url.= '&action='; + + $update_url = PHPWG_ROOT_PATH.'admin.php'; + $update_url.= '?page=site_update'; + $update_url.= '&site='.$row['id']; + + $tpl_var = + array( + 'NAME' => $row['galleries_url'], + 'TYPE' => l10n( $is_remote ? 'site_remote' : 'site_local' ), + 'CATEGORIES' => (int)@$sites_detail[$row['id']]['nb_categories'], + 'IMAGES' => (int)@$sites_detail[$row['id']]['nb_images'], + 'U_SYNCHRONIZE' => $update_url + ); + + if ($is_remote) + { + $tpl_var['remote'] = + array( + 'U_TEST' => $base_url.'test', + 'U_GENERATE' => $row['galleries_url'].'create_listing_file.php?action=generate', + 'U_CLEAN' => $base_url.'clean', + ); + } + + if ($row['id'] != 1) + { + $tpl_var['U_DELETE'] = $base_url.'delete'; + } + + $plugin_links = array(); + //$plugin_links is array of array composed of U_HREF, U_HINT & U_CAPTION + $plugin_links = + trigger_event('get_admins_site_links', + $plugin_links, $row['id'], $is_remote); + $tpl_var['plugin_links'] = $plugin_links; + + $template->append('sites', $tpl_var); + + if ( isset($local_listing_site_url) and + $row['galleries_url']==$local_listing_site_url ) + { + $local_listing_site_id = $row['id']; + $template->assign( 'local_listing', + array( + 'URL' => $local_listing_site_url, + 'U_SYNCHRONIZE' => $update_url.'&local_listing=1' + ) + ); + } +} + +if ( isset($local_listing_site_url) and !isset($local_listing_site_id) ) +{ + $template->assign( 'local_listing', + array( + 'URL' => $local_listing_site_url, + 'CREATE' => true + ) + ); +} + + +$template->assign_var_from_handle('ADMIN_CONTENT', 'site_manager'); +?> diff --git a/BSF/admin/site_reader_local.php b/BSF/admin/site_reader_local.php new file mode 100644 index 000000000..6d6d252ee --- /dev/null +++ b/BSF/admin/site_reader_local.php @@ -0,0 +1,265 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// provides data for site synchronization from the local file system +class LocalSiteReader +{ + +var $site_url; + +function LocalSiteReader($url) +{ + $this->site_url = $url; +} + +/** + * Is this local site ok ? + * + * @return true on success, false otherwise + */ +function open() +{ + global $errors; + + if (!is_dir($this->site_url)) + { + array_push( + $errors, + array( + 'path' => $this->site_url, + 'type' => 'PWG-ERROR-NO-FS' + ) + ); + + return false; + } + + return true; +} + +// retrieve file system sub-directories fulldirs +function get_full_directories($basedir) +{ + $fs_fulldirs = get_fs_directories($basedir); + return $fs_fulldirs; +} + +/** + * Returns an array with all file system files according to $conf['file_ext'] + * and $conf['picture_ext'] + * @param string $path recurse in this directory + * @return array like "pic.jpg"=>array('tn_ext'=>'jpg' ... ) + */ +function get_elements($path) +{ + global $conf; + if (!isset($conf['flip_file_ext'])) + { + $conf['flip_file_ext'] = array_flip($conf['file_ext']); + } + + $subdirs = array(); + $fs = array(); + if (is_dir($path) && $contents = opendir($path) ) + { + while (($node = readdir($contents)) !== false) + { + if (is_file($path.'/'.$node)) + { + $extension = get_extension($node); + $filename_wo_ext = get_filename_wo_extension($node); + + if ( isset($conf['flip_file_ext'][$extension]) ) + { + $tn_ext = $this->get_tn_ext($path, $filename_wo_ext); + $fs[ $path.'/'.$node ] = array( + 'tn_ext' => $tn_ext, + ); + } + } + elseif (is_dir($path.'/'.$node) + and $node != '.' + and $node != '..' + and $node != 'pwg_high' + and $node != 'pwg_representative' + and $node != 'thumbnail' ) + { + array_push($subdirs, $node); + } + } //end while readdir + closedir($contents); + + foreach ($subdirs as $subdir) + { + $tmp_fs = $this->get_elements($path.'/'.$subdir); + $fs = array_merge($fs, $tmp_fs); + } + } //end if is_dir + return $fs; +} + +// returns the name of the attributes that are supported for +// files update/synchronization +function get_update_attributes() +{ + return array('tn_ext', 'has_high', 'representative_ext'); +} + +function get_element_update_attributes($file) +{ + global $conf; + $data = array(); + + $filename = basename($file); + $dirname = dirname($file); + $filename_wo_ext = get_filename_wo_extension($filename); + $extension = get_extension($filename); + + $data['tn_ext'] = $this->get_tn_ext($dirname, $filename_wo_ext); + $data['has_high'] = $this->get_has_high($dirname, $filename); + + if ( !isset($conf['flip_picture_ext'][$extension]) ) + { + $data['representative_ext'] = $this->get_representative_ext( + $dirname, $filename_wo_ext + ); + } + return $data; +} + +// returns the name of the attributes that are supported for +// metadata update/synchronization according to configuration +function get_metadata_attributes() +{ + global $conf; + + $update_fields = array('filesize', 'width', 'height', 'high_filesize'); + + 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_keys($conf['use_iptc_mapping']) + ); + } + + return $update_fields; +} + +// returns a hash of attributes (metadata+filesize+width,...) for file +function get_element_metadata($file, $has_high = false) +{ + global $conf; + if (!is_file($file)) + { + return null; + } + + $data = array(); + + $data['filesize'] = floor(filesize($file)/1024); + + if ($image_size = @getimagesize($file)) + { + $data['width'] = $image_size[0]; + $data['height'] = $image_size[1]; + } + + if ($has_high) + { + $high_file = dirname($file).'/pwg_high/'.basename($file); + + $data['high_filesize'] = floor(filesize($high_file)/1024); + } + + if ($conf['use_exif']) + { + $data = array_merge($data, get_sync_exif_data($file) ); + } + + if ($conf['use_iptc']) + { + $data = array_merge($data, get_sync_iptc_data($file) ); + } + + return $data; +} + + +//-------------------------------------------------- private functions -------- +function get_representative_ext($path, $filename_wo_ext) +{ + global $conf; + $base_test = $path.'/pwg_representative/'.$filename_wo_ext.'.'; + foreach ($conf['picture_ext'] as $ext) + { + $test = $base_test.$ext; + if (is_file($test)) + { + return $ext; + } + } + return null; +} + +function get_tn_ext($path, $filename_wo_ext) +{ + global $conf; + + $base_test = + $path.'/thumbnail/'.$conf['prefix_thumbnail'].$filename_wo_ext.'.'; + + foreach ($conf['picture_ext'] as $ext) + { + $test = $base_test.$ext; + if (is_file($test)) + { + return $ext; + } + } + + return null; +} + +function get_has_high($path, $filename) +{ + if (is_file($path.'/pwg_high/'.$filename)) + { + return 'true'; + } + + return null; +} + +} +?>
\ No newline at end of file diff --git a/BSF/admin/site_reader_remote.php b/BSF/admin/site_reader_remote.php new file mode 100644 index 000000000..31ae3e792 --- /dev/null +++ b/BSF/admin/site_reader_remote.php @@ -0,0 +1,250 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + + +// provides data for site synchronization from a remote listing.xml +class RemoteSiteReader +{ + +var $site_url; +var $listing_url; +var $site_dirs; +var $site_files; +var $insert_attributes; +var $metadata_attributes; + +function RemoteSiteReader($url, $listing_url) +{ + $this->site_url = $url; + $this->insert_attributes = array( + 'tn_ext', + ); + $this->update_attributes = array( + 'tn_ext', 'representative_ext', 'has_high', + ); + $this->metadata_attributes = array( + 'filesize', 'width', 'height', 'high_filesize' + ); + + if (!isset($listing_url)) + { + $this->listing_url = $this->site_url.'/listing.xml'; + } + else + { + $this->listing_url = $listing_url; + } +} + +/** + * Is this remote site ok ? + * + * @return true on success, false otherwise + */ +function open() +{ + global $errors; + + if (@fopen($this->listing_url, 'r')) + { + $this->site_dirs = array(); + $this->site_files = array(); + $xml_content = getXmlCode($this->listing_url); + $info_xml_element = getChild($xml_content, 'informations'); + if (getAttribute($info_xml_element , 'phpwg_version') != PHPWG_VERSION) + { + array_push( + $errors, + array( + 'path' => $this->listing_url, + 'type' => 'PWG-ERROR-VERSION' + ) + ); + + return false; + } + + $additional_metadata = getAttribute($info_xml_element, 'metadata'); + + if ($additional_metadata != '') + { + $this->metadata_attributes = array_merge( + $this->metadata_attributes, + explode(',', $additional_metadata) + ); + } + + $this->build_structure($xml_content, '', 0); + + return true; + } + else + { + array_push( + $errors, + array( + 'path' => $this->listing_url, + 'type' => 'PWG-ERROR-NOLISTING' + ) + ); + + return false; + } +} + +// retrieve xml sub-directories fulldirs +function get_full_directories($basedir) +{ + $dirs = array(); + foreach ( array_keys($this->site_dirs) as $dir) + { + $full_dir = $this->site_url . $dir; + if ($full_dir != $basedir + and strpos($full_dir, $basedir) === 0 + ) + { + array_push($dirs, $full_dir); + } + } + return $dirs; +} + +/** + * Returns a hash with all elements (images and files) inside the full $path + * according to listing.xml + * @param string $path recurse in this directory only + * @return array like "pic.jpg"=>array('tn_ext'=>'jpg' ... ) + */ +function get_elements($path) +{ + $elements = array(); + foreach ( $this->site_dirs as $dir=>$files) + { + $full_dir = $this->site_url . $dir; + if (strpos($full_dir, $path) === 0) + { + foreach ($files as $file) + { + $data = $this->get_element_attributes( + $file, + $this->insert_attributes + ); + $elements[$file] = $data; + } + } + } + + return $elements; +} + +// returns the name of the attributes that are supported for +// files update/synchronization +function get_update_attributes() +{ + return $this->update_attributes; +} + +function get_element_update_attributes($file) +{ + return $this->get_element_attributes( + $file, + $this->update_attributes + ); +} + +// returns the name of the attributes that are supported for +// metadata update/synchronization according to listing.xml +function get_metadata_attributes() +{ + return $this->metadata_attributes; +} + +// returns a hash of attributes (metadata+width,...) for file +function get_element_metadata($file, $has_high = false) +{ + return $this->get_element_attributes( + $file, + $this->metadata_attributes + ); +} + +//-------------------------------------------------- private functions -------- +/** + * Returns a hash of image/file attributes + * @param string $file fully qualified file name + * @param array $attributes specifies which attributes to retrieve + * returned +*/ +function get_element_attributes($file, $attributes) +{ + $xml_element = $this->site_files[$file]; + if (!isset($xml_element)) + { + return null; + } + $data = array(); + foreach($attributes as $att) + { + if (getAttribute($xml_element, $att) != '') + { + $val = getAttribute($xml_element, $att); + $data[$att] = addslashes($val); + } + } + return $data; +} + +// recursively parse the xml_content for later usage +function build_structure($xml_content, $basedir, $level) +{ + $temp_dirs = getChildren($xml_content, 'dir'.$level); + foreach ($temp_dirs as $temp_dir) + { + $dir_name = $basedir; + if ($dir_name != '' ) + { + $dir_name .= '/'; + } + $dir_name .= getAttribute($temp_dir, 'name'); + $this->site_dirs[ $dir_name ] = array(); + $this->build_structure($temp_dir, $dir_name, $level+1); + } + + if ($basedir != '') + { + $xml_elements = getChildren( + getChild($xml_content, 'root'), + 'element' + ); + foreach ($xml_elements as $xml_element) + { + $path = getAttribute($xml_element, 'path'); + $this->site_files[$path] = $xml_element; + array_push($this->site_dirs[$basedir], $path); + } + } +} + +} + +?> diff --git a/BSF/admin/site_update.php b/BSF/admin/site_update.php new file mode 100644 index 000000000..e6fb6d4ef --- /dev/null +++ b/BSF/admin/site_update.php @@ -0,0 +1,991 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die('Hacking attempt!'); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +if (!is_numeric($_GET['site'])) +{ + die ('site param missing or invalid'); +} +$site_id = $_GET['site']; + +$query=' +SELECT galleries_url + FROM '.SITES_TABLE.' + WHERE id = '.$site_id.' +;'; +list($site_url) = mysql_fetch_row(pwg_query($query)); +if (!isset($site_url)) +{ + die('site '.$site_id.' does not exist'); +} +$site_is_remote = url_is_remote($site_url); + +list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();')); +define('CURRENT_DATE', $dbnow); + +$error_labels = array( + 'PWG-UPDATE-1' => array( + l10n('update_wrong_dirname_short'), + l10n('update_wrong_dirname_info') + ), + 'PWG-UPDATE-2' => array( + l10n('update_missing_tn_short'), + l10n('update_missing_tn_info').implode(',', $conf['picture_ext']) + ), + 'PWG-ERROR-NO-FS' => array( + l10n('update_missing_file_or_dir'), + l10n('update_missing_file_or_dir_info') + ), + 'PWG-ERROR-VERSION' => array( + l10n('update_err_pwg_version_differs'), + l10n('update_err_pwg_version_differs_info') + ), + 'PWG-ERROR-NOLISTING' => array( + l10n('update_err_remote_listing_not_found'), + l10n('update_err_remote_listing_not_found_info') + ) + ); +$errors = array(); +$infos = array(); + +if ($site_is_remote) +{ + include_once(PHPWG_ROOT_PATH.'admin/site_reader_remote.php'); + $local_listing = null; + if ( isset($_GET['local_listing']) + and $_GET['local_listing'] ) + { + $local_listing = PHPWG_ROOT_PATH.'listing.xml'; + } + $site_reader = new RemoteSiteReader($site_url, $local_listing); +} +else +{ + include_once( PHPWG_ROOT_PATH.'admin/site_reader_local.php'); + $site_reader = new LocalSiteReader($site_url); +} + +$general_failure = true; +if (isset($_POST['submit'])) +{ + if (!isset($conf['flip_picture_ext'])) + { + $conf['flip_picture_ext'] = array_flip($conf['picture_ext']); + } + if ($site_reader->open()) + { + $general_failure = false; + } + + // shall we simulate only + if ((isset($_POST['simulate']) and $_POST['simulate'] == 1) or is_adviser()) + { + $simulate = true; + } + else + { + $simulate = false; + } +} + +// +-----------------------------------------------------------------------+ +// | directories / categories | +// +-----------------------------------------------------------------------+ +if (isset($_POST['submit']) + and ($_POST['sync'] == 'dirs' or $_POST['sync'] == 'files')) +{ + $counts['new_categories'] = 0; + $counts['del_categories'] = 0; + $counts['del_elements'] = 0; + $counts['new_elements'] = 0; + $counts['upd_elements'] = 0; +} + + +if (isset($_POST['submit']) + and ($_POST['sync'] == 'dirs' or $_POST['sync'] == 'files') + and !$general_failure) +{ + $start = get_moment(); + // which categories to update ? + $cat_ids = array(); + + $query = ' +SELECT id, uppercats, global_rank, status, visible + FROM '.CATEGORIES_TABLE.' + WHERE dir IS NOT NULL + AND site_id = '.$site_id; + if (isset($_POST['cat']) and is_numeric($_POST['cat'])) + { + if (isset($_POST['subcats-included']) and $_POST['subcats-included'] == 1) + { + $query.= ' + AND uppercats REGEXP \'(^|,)'.$_POST['cat'].'(,|$)\' +'; + } + else + { + $query.= ' + AND id = '.$_POST['cat'].' +'; + } + } + $query.= ' +;'; + $result = pwg_query($query); + + $db_categories = array(); + while ($row = mysql_fetch_array($result)) + { + $db_categories[$row['id']] = $row; + } + + // get categort full directories in an array for comparison with file + // system directory tree + $db_fulldirs = get_fulldirs(array_keys($db_categories)); + + // what is the base directory to search file system sub-directories ? + if (isset($_POST['cat']) and is_numeric($_POST['cat'])) + { + $basedir = $db_fulldirs[$_POST['cat']]; + } + else + { + $basedir = preg_replace('#/*$#', '', $site_url); + } + + // we need to have fulldirs as keys to make efficient comparison + $db_fulldirs = array_flip($db_fulldirs); + + // finding next rank for each id_uppercat. By default, each category id + // has 1 for next rank on its sub-categories to create + $next_rank['NULL'] = 1; + + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $next_rank[$row['id']] = 1; + } + + // let's see if some categories already have some sub-categories... + $query = ' +SELECT id_uppercat, MAX(rank)+1 AS next_rank + FROM '.CATEGORIES_TABLE.' + GROUP BY id_uppercat +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + // for the id_uppercat NULL, we write 'NULL' and not the empty string + if (!isset($row['id_uppercat']) or $row['id_uppercat'] == '') + { + $row['id_uppercat'] = 'NULL'; + } + $next_rank[$row['id_uppercat']] = $row['next_rank']; + } + + // next category id available + $query = ' +SELECT IF(MAX(id)+1 IS NULL, 1, MAX(id)+1) AS next_id + FROM '.CATEGORIES_TABLE.' +;'; + list($next_id) = mysql_fetch_array(pwg_query($query)); + + // retrieve sub-directories fulldirs from the site reader + $fs_fulldirs = $site_reader->get_full_directories($basedir); + + // get_full_directories doesn't include the base directory, so if it's a + // category directory, we need to include it in our array + if (isset($_POST['cat'])) + { + array_push($fs_fulldirs, $basedir); + } + // If $_POST['subcats-included'] != 1 ("Search in subcategories" is unchecked) + // $db_fulldirs doesn't include any subdirectories and $fs_fulldirs does + // So $fs_fulldirs will be limited to the selected basedir + // (if that one is in $fs_fulldirs) + if (!isset($_POST['subcats-included']) or $_POST['subcats-included'] != 1) + { + $fs_fulldirs = array_intersect($fs_fulldirs, array_keys($db_fulldirs)); + } + $inserts = array(); + // new categories are the directories not present yet in the database + foreach (array_diff($fs_fulldirs, array_keys($db_fulldirs)) as $fulldir) + { + $dir = basename($fulldir); + if (preg_match('/^[a-zA-Z0-9-_.]+$/', $dir)) + { + $insert = array( + 'id' => $next_id++, + 'dir' => $dir, + 'name' => str_replace('_', ' ', $dir), + 'site_id' => $site_id, + 'commentable' => + boolean_to_string($conf['newcat_default_commentable']), + 'uploadable' => $site_is_remote + ? 'false' + : boolean_to_string($conf['newcat_default_uploadable']), + 'status' => $conf{'newcat_default_status'}, + 'visible' => boolean_to_string($conf{'newcat_default_visible'}), + ); + + if (isset($db_fulldirs[dirname($fulldir)])) + { + $parent = $db_fulldirs[dirname($fulldir)]; + + $insert{'id_uppercat'} = $parent; + $insert{'uppercats'} = + $db_categories[$parent]['uppercats'].','.$insert{'id'}; + $insert{'rank'} = $next_rank[$parent]++; + $insert{'global_rank'} = + $db_categories[$parent]['global_rank'].'.'.$insert{'rank'}; + if ('private' == $db_categories[$parent]['status']) + { + $insert{'status'} = 'private'; + } + if ('false' == $db_categories[$parent]['visible']) + { + $insert{'visible'} = 'false'; + } + } + else + { + $insert{'uppercats'} = $insert{'id'}; + $insert{'rank'} = $next_rank['NULL']++; + $insert{'global_rank'} = $insert{'rank'}; + } + + array_push($inserts, $insert); + array_push( + $infos, + array( + 'path' => $fulldir, + 'info' => l10n('update_research_added') + ) + ); + + // add the new category to $db_categories and $db_fulldirs array + $db_categories[$insert{'id'}] = + array( + 'id' => $insert{'id'}, + 'status' => $insert{'status'}, + 'visible' => $insert{'visible'}, + 'uppercats' => $insert{'uppercats'}, + 'global_rank' => $insert{'global_rank'} + ); + $db_fulldirs[$fulldir] = $insert{'id'}; + $next_rank[$insert{'id'}] = 1; + } + else + { + array_push( + $errors, + array( + 'path' => $fulldir, + 'type' => 'PWG-UPDATE-1' + ) + ); + } + } + + if (count($inserts) > 0) + { + if (!$simulate) + { + $dbfields = array( + 'id','dir','name','site_id','id_uppercat','uppercats','commentable', + 'uploadable','visible','status','rank','global_rank' + ); + mass_inserts(CATEGORIES_TABLE, $dbfields, $inserts); + } + + $counts['new_categories'] = count($inserts); + } + + // to delete categories + $to_delete = array(); + foreach (array_diff(array_keys($db_fulldirs), $fs_fulldirs) as $fulldir) + { + array_push($to_delete, $db_fulldirs[$fulldir]); + unset($db_fulldirs[$fulldir]); + array_push($infos, array('path' => $fulldir, + 'info' => l10n('update_research_deleted'))); + } + if (count($to_delete) > 0) + { + if (!$simulate) + { + delete_categories($to_delete); + } + $counts['del_categories'] = count($to_delete); + } + + $template->append('footer_elements', '<!-- scanning dirs : ' + . get_elapsed_time($start, get_moment()) + . ' -->' ); +} +// +-----------------------------------------------------------------------+ +// | files / elements | +// +-----------------------------------------------------------------------+ +if (isset($_POST['submit']) and $_POST['sync'] == 'files' + and !$general_failure) +{ + $start_files = get_moment(); + $start= $start_files; + + $fs = $site_reader->get_elements($basedir); + $template->append('footer_elements', '<!-- get_elements: ' + . get_elapsed_time($start, get_moment()) + . ' -->' ); + + $cat_ids = array_diff(array_keys($db_categories), $to_delete); + + $db_elements = array(); + $db_unvalidated = array(); + + if (count($cat_ids) > 0) + { + $query = ' +SELECT id, path + FROM '.IMAGES_TABLE.' + WHERE storage_category_id IN (' + .wordwrap( + implode(', ', $cat_ids), + 80, + "\n" + ).') +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $db_elements[$row['id']] = $row['path']; + } + + // searching the unvalidated waiting elements (they must not be taken into + // account) + $query = ' +SELECT file,storage_category_id + FROM '.WAITING_TABLE.' + WHERE storage_category_id IN ( +'.wordwrap(implode(', ', $cat_ids), 80, "\n").') + AND validated = \'false\' +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push( + $db_unvalidated, + array_search( + $row['storage_category_id'], + $db_fulldirs) + .'/'.$row['file'] + ); + } + } + + // next element id available + $query = ' +SELECT IF(MAX(id)+1 IS NULL, 1, MAX(id)+1) AS next_element_id + FROM '.IMAGES_TABLE.' +;'; + list($next_element_id) = mysql_fetch_array(pwg_query($query)); + + $start = get_moment(); + + $inserts = array(); + $insert_links = array(); + + foreach (array_diff(array_keys($fs), $db_elements, $db_unvalidated) as $path) + { + $insert = array(); + // storage category must exist + $dirname = dirname($path); + if (!isset($db_fulldirs[$dirname])) + { + continue; + } + $filename = basename($path); + if (!preg_match('/^[a-zA-Z0-9-_.]+$/', $filename)) + { + array_push( + $errors, + array( + 'path' => $path, + 'type' => 'PWG-UPDATE-1' + ) + ); + + continue; + } + + if ( isset( $conf['flip_picture_ext'][get_extension($filename)] ) + and !isset($fs[$path]['tn_ext']) ) + { // For a picture thumbnail is mandatory and for non picture element, + // thumbnail and representative are optionnal + array_push( + $errors, + array( + 'path' => $path, + 'type' => 'PWG-UPDATE-2' + ) + ); + } + else + { + $insert = array( + 'id' => $next_element_id++, + 'file' => $filename, + 'date_available' => CURRENT_DATE, + 'path' => $path, + 'tn_ext' => isset($fs[$path]['tn_ext']) + ? $fs[$path]['tn_ext'] + : null, + 'storage_category_id' => $db_fulldirs[$dirname], + ); + + if ( $_POST['privacy_level']!=0 ) + { + $insert['level'] = $_POST['privacy_level']; + } + + array_push( + $inserts, + $insert + ); + + array_push( + $insert_links, + array( + 'image_id' => $insert{'id'}, + 'category_id' => $insert['storage_category_id'], + ) + ); + + array_push( + $infos, + array( + 'path' => $insert{'path'}, + 'info' => l10n('update_research_added') + ) + ); + + $caddiables[] = $insert['id']; + } + } + + if (count($inserts) > 0) + { + if (!$simulate) + { + // inserts all new elements + mass_inserts( + IMAGES_TABLE, + array_keys($inserts[0]), + $inserts + ); + + // inserts all links between new elements and their storage category + mass_inserts( + IMAGE_CATEGORY_TABLE, + array_keys($insert_links[0]), + $insert_links + ); + + // add new elements to caddie + if (isset($_POST['add_to_caddie']) and $_POST['add_to_caddie'] == 1) + { + fill_caddie($caddiables); + } + } + $counts['new_elements'] = count($inserts); + } + + // delete elements that are in database but not in the filesystem + $to_delete_elements = array(); + foreach (array_diff($db_elements, array_keys($fs)) as $path) + { + array_push($to_delete_elements, array_search($path, $db_elements)); + array_push($infos, array('path' => $path, + 'info' => l10n('update_research_deleted'))); + } + if (count($to_delete_elements) > 0) + { + if (!$simulate) + { + delete_elements($to_delete_elements); + } + $counts['del_elements'] = count($to_delete_elements); + } + + $template->append('footer_elements', '<!-- scanning files : ' + . get_elapsed_time($start_files, get_moment()) + . ' -->' ); + + // retrieving informations given by uploaders + if (!$simulate and count($cat_ids) > 0) + { + $query = ' +SELECT id,file,storage_category_id,infos + FROM '.WAITING_TABLE.' + WHERE storage_category_id IN ( +'.wordwrap(implode(', ', $cat_ids), 80, "\n").') + AND validated = \'true\' +;'; + $result = pwg_query($query); + + $datas = array(); + $fields = + array( + 'primary' => array('id'), + 'update' => array('date_creation', 'author', 'name', 'comment') + ); + + $waiting_to_delete = array(); + + while ($row = mysql_fetch_array($result)) + { + $data = array(); + + $query = ' +SELECT id + FROM '.IMAGES_TABLE.' + WHERE storage_category_id = '.$row['storage_category_id'].' + AND file = \''.$row['file'].'\' +;'; + list($data['id']) = mysql_fetch_array(pwg_query($query)); + + foreach ($fields['update'] as $field) + { + $data[$field] = addslashes( getAttribute($row['infos'], $field) ); + } + + array_push($datas, $data); + array_push($waiting_to_delete, $row['id']); + } + + if (count($datas) > 0) + { + mass_updates(IMAGES_TABLE, $fields, $datas); + + // delete now useless waiting elements + $query = ' +DELETE + FROM '.WAITING_TABLE.' + WHERE id IN ('.implode(',', $waiting_to_delete).') +;'; + pwg_query($query); + } + } +} + +// +-----------------------------------------------------------------------+ +// | synchronize files | +// +-----------------------------------------------------------------------+ +if (isset($_POST['submit']) + and ($_POST['sync'] == 'dirs' or $_POST['sync'] == 'files') + and !$general_failure ) +{ + if (!$simulate) + { + $start = get_moment(); + update_category('all'); + $template->append('footer_elements', '<!-- update_category(all) : ' + . get_elapsed_time($start,get_moment()) + . ' -->' ); + $start = get_moment(); + update_global_rank(); + $template->append('footer_elements', '<!-- ordering categories : ' + . get_elapsed_time($start, get_moment()) + . ' -->'); + } + + if ($_POST['sync'] == 'files') + { + $start = get_moment(); + $opts['category_id'] = ''; + $opts['recursive'] = true; + if (isset($_POST['cat'])) + { + $opts['category_id'] = $_POST['cat']; + if (!isset($_POST['subcats-included']) or $_POST['subcats-included'] != 1) + { + $opts['recursive'] = false; + } + } + $files = get_filelist($opts['category_id'], $site_id, + $opts['recursive'], + false); + $template->append('footer_elements', '<!-- get_filelist : ' + . get_elapsed_time($start, get_moment()) + . ' -->'); + $start = get_moment(); + + $datas = array(); + foreach ( $files as $id=>$file ) + { + $data = $site_reader->get_element_update_attributes($file); + if ( !is_array($data) ) + { + continue; + } + $extension = get_extension($file); + if ( isset($conf['flip_picture_ext'][$extension]) ) + { + if ( !isset($data['tn_ext']) ) + { + array_push( + $errors, + array( + 'path' => $file, + 'type' => 'PWG-UPDATE-2' + ) + ); + continue; + } + } + + $data['id']=$id; + array_push($datas, $data); + } // end foreach file + + $counts['upd_elements'] = count($datas); + if (!$simulate and count($datas)>0 ) + { + mass_updates( + IMAGES_TABLE, + // fields + array( + 'primary' => array('id'), + 'update' => $site_reader->get_update_attributes(), + ), + $datas + ); + } + $template->append('footer_elements', '<!-- update files : ' + . get_elapsed_time($start,get_moment()) + . ' -->'); + }// end if sync files +} + +// +-----------------------------------------------------------------------+ +// | synchronize files | +// +-----------------------------------------------------------------------+ +if (isset($_POST['submit']) + and ($_POST['sync'] == 'dirs' or $_POST['sync'] == 'files')) +{ + $template->assign( + 'update_result', + array( + 'NB_NEW_CATEGORIES'=>$counts['new_categories'], + 'NB_DEL_CATEGORIES'=>$counts['del_categories'], + 'NB_NEW_ELEMENTS'=>$counts['new_elements'], + 'NB_DEL_ELEMENTS'=>$counts['del_elements'], + 'NB_UPD_ELEMENTS'=>$counts['upd_elements'], + 'NB_ERRORS'=>count($errors), + )); +} + +// +-----------------------------------------------------------------------+ +// | synchronize metadata | +// +-----------------------------------------------------------------------+ +if (isset($_POST['submit']) and preg_match('/^metadata/', $_POST['sync']) + and !$general_failure) +{ + // sync only never synchronized files ? + if ($_POST['sync'] == 'metadata_new') + { + $opts['only_new'] = true; + } + else + { + $opts['only_new'] = false; + } + $opts['category_id'] = ''; + $opts['recursive'] = true; + + if (isset($_POST['cat'])) + { + $opts['category_id'] = $_POST['cat']; + // recursive ? + if (!isset($_POST['subcats-included']) or $_POST['subcats-included'] != 1) + { + $opts['recursive'] = false; + } + } + $start = get_moment(); + $files = get_filelist($opts['category_id'], $site_id, + $opts['recursive'], + $opts['only_new']); + + $template->append('footer_elements', '<!-- get_filelist : ' + . get_elapsed_time($start, get_moment()) + . ' -->'); + + $start = get_moment(); + $datas = array(); + $tags_of = array(); + + $has_high_images = array(); + + $image_ids = array(); + foreach ($files as $id => $file) + { + array_push($image_ids, $id); + } + + if (count($image_ids) > 0) + { + $query = ' +SELECT id + FROM '.IMAGES_TABLE.' + WHERE has_high = \'true\' + AND id IN ( +'.wordwrap(implode(', ', $image_ids), 80, "\n").' +) +;'; + + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($has_high_images, $row['id']); + } + } + + foreach ( $files as $id=>$file ) + { + $data = $site_reader->get_element_metadata( + $file, + in_array($id, $has_high_images) + ); + + if ( is_array($data) ) + { + $data['date_metadata_update'] = CURRENT_DATE; + $data['id']=$id; + array_push($datas, $data); + + foreach (array('keywords', 'tags') as $key) + { + if (isset($data[$key])) + { + if (!isset($tags_of[$id])) + { + $tags_of[$id] = array(); + } + + foreach (explode(',', $data[$key]) as $tag_name) + { + array_push( + $tags_of[$id], + tag_id_from_tag_name($tag_name) + ); + } + } + } + } + else + { + array_push($errors, array('path' => $file, 'type' => 'PWG-ERROR-NO-FS')); + } + } + + if (!$simulate) + { + if (count($datas) > 0) + { + mass_updates( + IMAGES_TABLE, + // fields + array( + 'primary' => array('id'), + 'update' => array_unique( + array_merge( + array_diff( + $site_reader->get_metadata_attributes(), + // keywords and tags fields are managed separately + array('keywords', 'tags') + ), + array('date_metadata_update')) + ) + ), + $datas + ); + } + set_tags_of($tags_of); + } + + $template->append('footer_elements', '<!-- metadata update : ' + . get_elapsed_time($start, get_moment()) + . ' -->'); + + $template->assign( + 'metadata_result', + array( + 'NB_ELEMENTS_DONE' => count($datas), + 'NB_ELEMENTS_CANDIDATES' => count($files), + 'NB_ERRORS' => count($errors), + )); +} + +// +-----------------------------------------------------------------------+ +// | template initialization | +// +-----------------------------------------------------------------------+ +$template->set_filenames(array('update'=>'admin/site_update.tpl')); +$result_title = ''; +if (isset($simulate) and $simulate) +{ + $result_title.= l10n('update_simulation_title').' '; +} + +// used_metadata string is displayed to inform admin which metadata will be +// used from files for synchronization +$used_metadata = implode( ', ', $site_reader->get_metadata_attributes()); +if ($site_is_remote and !isset($_POST['submit']) ) +{ + $used_metadata.= ' + ...'; +} + +$template->assign( + array( + 'SITE_URL'=>$site_url, + 'U_SITE_MANAGER'=> get_root_url().'admin.php?page=site_manager', + 'L_RESULT_UPDATE'=>$result_title.l10n('update_part_research'), + 'L_RESULT_METADATA'=>$result_title.l10n('update_result_metadata'), + 'METADATA_LIST' => $used_metadata, + 'U_HELP' => get_root_url().'popuphelp.php?page=synchronize', + )); + +// +-----------------------------------------------------------------------+ +// | introduction : choices | +// +-----------------------------------------------------------------------+ +if (!isset($_POST['submit']) or (isset($simulate) and $simulate)) +{ + if (isset($simulate) and $simulate) + { + $tpl_introduction = array( + 'sync' => $_POST['sync'], + 'display_info' => isset($_POST['display_info']) and $_POST['display_info']==1, + 'add_to_caddie' => isset($_POST['add_to_caddie']) and $_POST['add_to_caddie']==1, + 'subcats_included' => isset($_POST['subcats-included']) and $_POST['subcats-included']==1, + 'privacy_level_selected' => (int)@$_POST['privacy_level'], + ); + + if (isset($_POST['cat']) and is_numeric($_POST['cat'])) + { + $cat_selected = array($_POST['cat']); + } + else + { + $cat_selected = array(); + } + } + else + { + $tpl_introduction = array( + 'sync' => 'dirs', + 'display_info' => false, + 'add_to_caddie' => false, + 'subcats_included' => true, + 'privacy_level_selected' => 0, + ); + + $cat_selected = array(); + } + + $tpl_introduction['privacy_level_options']=array(); + foreach ($conf['available_permission_levels'] as $level) + { + $tpl_introduction['privacy_level_options'][$level] = l10n( sprintf('Level %d', $level) ); + } + + $template->assign('introduction', $tpl_introduction); + + $query = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE site_id = '.$site_id.' +;'; + display_select_cat_wrapper($query, + $cat_selected, + 'category_options', + false); +} + +if (count($errors) > 0) +{ + foreach ($errors as $error) + { + $template->append( + 'sync_errors', + array( + 'ELEMENT' => $error['path'], + 'LABEL' => $error['type'].' ('.$error_labels[$error['type']][0].')' + )); + } + + foreach ($error_labels as $error_type=>$error_description) + { + $template->append( + 'sync_error_captions', + array( + 'TYPE' => $error_type, + 'LABEL' => $error_description[1] + )); + } +} + +if (count($infos) > 0 + and isset($_POST['display_info']) + and $_POST['display_info'] == 1) +{ + foreach ($infos as $info) + { + $template->append( + 'sync_infos', + array( + 'ELEMENT' => $info['path'], + 'LABEL' => $info['info'] + )); + } +} + +// +-----------------------------------------------------------------------+ +// | sending html code | +// +-----------------------------------------------------------------------+ +$template->assign_var_from_handle('ADMIN_CONTENT', 'update'); +?> diff --git a/BSF/admin/stats.php b/BSF/admin/stats.php new file mode 100644 index 000000000..9892127c8 --- /dev/null +++ b/BSF/admin/stats.php @@ -0,0 +1,514 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined("PHPWG_ROOT_PATH")) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); +include_once(PHPWG_ROOT_PATH.'admin/include/functions_history.inc.php'); + +// +-----------------------------------------------------------------------+ +// | Functions | +// +-----------------------------------------------------------------------+ + +function get_summary($year = null, $month = null, $day = null) +{ + $query = ' +SELECT + year, + month, + day, + hour, + nb_pages + FROM '.HISTORY_SUMMARY_TABLE; + + if (isset($day)) + { + $query.= ' + WHERE year = '.$year.' + AND month = '.$month.' + AND day = '.$day.' + AND hour IS NOT NULL + ORDER BY + year ASC, + month ASC, + day ASC, + hour ASC +;'; + } + elseif (isset($month)) + { + $query.= ' + WHERE year = '.$year.' + AND month = '.$month.' + AND day IS NOT NULL + AND hour IS NULL + ORDER BY + year ASC, + month ASC, + day ASC +;'; + } + elseif (isset($year)) + { + $query.= ' + WHERE year = '.$year.' + AND month IS NOT NULL + AND day IS NULL + ORDER BY + year ASC, + month ASC +;'; + } + else + { + $query.= ' + WHERE year IS NOT NULL + AND month IS NULL + ORDER BY + year ASC +;'; + } + + $result = pwg_query($query); + + $output = array(); + while ($row = mysql_fetch_array($result)) + { + array_push($output, $row); + } + + return $output; +} + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ + +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | Refresh summary from details | +// +-----------------------------------------------------------------------+ + +$query = ' +SELECT + date, + HOUR(time) AS hour, + MAX(id) AS max_id, + COUNT(*) AS nb_pages + FROM '.HISTORY_TABLE.' + WHERE summarized = \'false\' + GROUP BY + date ASC, + HOUR(time) ASC +;'; +$result = pwg_query($query); + +$need_update = array(); + +$max_id = 0; +$is_first = true; +$first_time_key = null; + +while ($row = mysql_fetch_array($result)) +{ + $time_keys = array( + substr($row['date'], 0, 4), //yyyy + substr($row['date'], 0, 7), //yyyy-mm + substr($row['date'], 0, 10),//yyyy-mm-dd + sprintf( + '%s-%02u', + $row['date'], $row['hour'] + ), + ); + + foreach ($time_keys as $time_key) + { + if (!isset($need_update[$time_key])) + { + $need_update[$time_key] = 0; + } + $need_update[$time_key] += $row['nb_pages']; + } + + if ($row['max_id'] > $max_id) + { + $max_id = $row['max_id']; + } + + if ($is_first) + { + $is_first = false; + $first_time_key = $time_keys[3]; + } +} + +// Only the oldest time_key might be already summarized, so we have to +// update the 4 corresponding lines instead of simply inserting them. +// +// For example, if the oldest unsummarized is 2005.08.25.21, the 4 lines +// that can be updated are: +// +// +---------------+----------+ +// | id | nb_pages | +// +---------------+----------+ +// | 2005 | 241109 | +// | 2005-08 | 20133 | +// | 2005-08-25 | 620 | +// | 2005-08-25-21 | 151 | +// +---------------+----------+ + + +$updates = array(); +$inserts = array(); + +if (isset($first_time_key)) +{ + list($year, $month, $day, $hour) = explode('-', $first_time_key); + + $query = ' +SELECT * + FROM '.HISTORY_SUMMARY_TABLE.' + WHERE year='.$year.' + AND ( month IS NULL + OR ( month='.$month.' + AND ( day is NULL + OR (day='.$day.' + AND (hour IS NULL OR hour='.$hour.') + ) + ) + ) + ) +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $key = sprintf('%4u', $row['year']); + if ( isset($row['month']) ) + { + $key .= sprintf('-%02u', $row['month']); + if ( isset($row['day']) ) + { + $key .= sprintf('-%02u', $row['day']); + if ( isset($row['hour']) ) + { + $key .= sprintf('-%02u', $row['hour']); + } + } + } + + if (isset($need_update[$key])) + { + $row['nb_pages'] += $need_update[$key]; + array_push($updates, $row); + unset($need_update[$key]); + } + } +} + +foreach ($need_update as $time_key => $nb_pages) +{ + $time_tokens = explode('-', $time_key); + + array_push( + $inserts, + array( + 'year' => $time_tokens[0], + 'month' => @$time_tokens[1], + 'day' => @$time_tokens[2], + 'hour' => @$time_tokens[3], + 'nb_pages' => $nb_pages, + ) + ); +} + +if (count($updates) > 0) +{ + mass_updates( + HISTORY_SUMMARY_TABLE, + array( + 'primary' => array('year','month','day','hour'), + 'update' => array('nb_pages'), + ), + $updates + ); +} + +if (count($inserts) > 0) +{ + mass_inserts( + HISTORY_SUMMARY_TABLE, + array_keys($inserts[0]), + $inserts + ); +} + +if ($max_id != 0) +{ + $query = ' +UPDATE '.HISTORY_TABLE.' + SET summarized = \'true\' + WHERE summarized = \'false\' + AND id <= '.$max_id.' +;'; + pwg_query($query); +} + +// +-----------------------------------------------------------------------+ +// | Page parameters check | +// +-----------------------------------------------------------------------+ + +foreach (array('day', 'month', 'year') as $key) +{ + if (isset($_GET[$key])) + { + $page[$key] = (int)$_GET[$key]; + } +} + +if (isset($page['day'])) +{ + if (!isset($page['month'])) + { + die('month is missing in URL'); + } +} + +if (isset($page['month'])) +{ + if (!isset($page['year'])) + { + die('year is missing in URL'); + } +} + +$summary_lines = get_summary( + @$page['year'], + @$page['month'], + @$page['day'] + ); + +// +-----------------------------------------------------------------------+ +// | Display statistics header | +// +-----------------------------------------------------------------------+ + +// page title creation +$title_parts = array(); + +$url = PHPWG_ROOT_PATH.'admin.php?page=stats'; + +array_push( + $title_parts, + '<a href="'.$url.'">'.l10n('Overall').'</a>' + ); + +$period_label = l10n('Year'); + +if (isset($page['year'])) +{ + $url.= '&year='.$page['year']; + + array_push( + $title_parts, + '<a href="'.$url.'">'.$page['year'].'</a>' + ); + + $period_label = l10n('Month'); +} + +if (isset($page['month'])) +{ + $url.= '&month='.$page['month']; + + array_push( + $title_parts, + '<a href="'.$url.'">'.$lang['month'][$page['month']].'</a>' + ); + + $period_label = l10n('Day'); +} + +if (isset($page['day'])) +{ + $url.= '&day='.$page['day']; + + $time = mktime(12, 0, 0, $page['month'], $page['day'], $page['year']); + + $day_title = sprintf( + '%u (%s)', + $page['day'], + $lang['day'][date('w', $time)] + ); + + array_push( + $title_parts, + '<a href="'.$url.'">'.$day_title.'</a>' + ); + + $period_label = l10n('Hour'); +} + +$template->set_filename('stats', 'admin/stats.tpl'); + +// TabSheet initialization +history_tabsheet(); + +$base_url = get_root_url().'admin.php?page=history'; + +$template->assign( + array( + 'L_STAT_TITLE' => implode($conf['level_separator'], $title_parts), + 'PERIOD_LABEL' => $period_label, + 'U_HELP' => get_root_url().'popuphelp.php?page=history', + 'F_ACTION' => $base_url, + ) + ); + +// +-----------------------------------------------------------------------+ +// | Display statistic rows | +// +-----------------------------------------------------------------------+ + +$max_width = 400; + +$datas = array(); + +if (isset($page['day'])) +{ + $key = 'hour'; + $min_x = 0; + $max_x = 23; +} +elseif (isset($page['month'])) +{ + $key = 'day'; + $min_x = 1; + $max_x = date( + 't', + mktime(12, 0, 0, $page['month'], 1, $page['year']) + ); +} +elseif (isset($page['year'])) +{ + $key = 'month'; + $min_x = 1; + $max_x = 12; +} +else +{ + $key = 'year'; +} + +$max_pages = 1; +foreach ($summary_lines as $line) +{ + if ($line['nb_pages'] > $max_pages) + { + $max_pages = $line['nb_pages']; + } + + $datas[ $line[$key] ] = $line['nb_pages']; +} + +if (!isset($min_x) and !isset($max_x) and count($datas) > 0) +{ + $min_x = min(array_keys($datas)); + $max_x = max(array_keys($datas)); +} + +if (count($datas) > 0) +{ + for ($i = $min_x; $i <= $max_x; $i++) + { + if (!isset($datas[$i])) + { + $datas[$i] = 0; + } + + $url = null; + + if (isset($page['day'])) + { + $value = sprintf('%02u', $i); + } + else if (isset($page['month'])) + { + $url = + get_root_url().'admin.php' + .'?page=stats' + .'&year='.$page['year'] + .'&month='.$page['month'] + .'&day='.$i + ; + + $time = mktime(12, 0, 0, $page['month'], $i, $page['year']); + + $value = $i.' ('.$lang['day'][date('w', $time)].')'; + } + else if (isset($page['year'])) + { + $url = + get_root_url().'admin.php' + .'?page=stats' + .'&year='.$page['year'] + .'&month='.$i + ; + + $value = $lang['month'][$i]; + } + else + { + // at least the year is defined + $url = + get_root_url().'admin.php' + .'?page=stats' + .'&year='.$i + ; + + $value = $i; + } + + if ($datas[$i] != 0 and isset($url)) + { + $value = '<a href="'.$url.'">'.$value.'</a>'; + } + + $template->append( + 'statrows', + array( + 'VALUE' => $value, + 'PAGES' => $datas[$i], + 'WIDTH' => ceil(($datas[$i] * $max_width) / $max_pages ), + ) + ); + } +} + +// +-----------------------------------------------------------------------+ +// | Sending html code | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('ADMIN_CONTENT', 'stats'); +?>
\ No newline at end of file diff --git a/BSF/admin/tags.php b/BSF/admin/tags.php new file mode 100644 index 000000000..36e668a3d --- /dev/null +++ b/BSF/admin/tags.php @@ -0,0 +1,246 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if( !defined("PHPWG_ROOT_PATH") ) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | edit tags | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['submit']) and !is_adviser()) +{ + $query = ' +SELECT name + FROM '.TAGS_TABLE.' +;'; + $existing_names = array_from_query($query, 'name'); + + + $current_name_of = array(); + $query = ' +SELECT id, name + FROM '.TAGS_TABLE.' + WHERE id IN ('.$_POST['edit_list'].') +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $current_name_of[ $row['id'] ] = $row['name']; + } + + $updates = array(); + // we must not rename tag with an already existing name + foreach (explode(',', $_POST['edit_list']) as $tag_id) + { + $tag_name = stripslashes($_POST['tag_name-'.$tag_id]); + + if ($tag_name != $current_name_of[$tag_id]) + { + if (in_array($tag_name, $existing_names)) + { + array_push( + $page['errors'], + sprintf( + l10n('Tag "%s" already exists'), + $tag_name + ) + ); + } + else if (!empty($tag_name)) + { + array_push( + $updates, + array( + 'id' => $tag_id, + 'name' => addslashes($tag_name), + 'url_name' => str2url($tag_name), + ) + ); + } + } + } + mass_updates( + TAGS_TABLE, + array( + 'primary' => array('id'), + 'update' => array('name', 'url_name'), + ), + $updates + ); +} + +// +-----------------------------------------------------------------------+ +// | delete tags | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['delete']) and isset($_POST['tags']) and !is_adviser()) +{ + $query = ' +SELECT name + FROM '.TAGS_TABLE.' + WHERE id IN ('.implode(',', $_POST['tags']).') +;'; + $tag_names = array_from_query($query, 'name'); + + $query = ' +DELETE + FROM '.IMAGE_TAG_TABLE.' + WHERE tag_id IN ('.implode(',', $_POST['tags']).') +;'; + pwg_query($query); + + $query = ' +DELETE + FROM '.TAGS_TABLE.' + WHERE id IN ('.implode(',', $_POST['tags']).') +;'; + pwg_query($query); + + array_push( + $page['infos'], + l10n_dec( + 'The %d following tag were deleted', + 'The %d following tags were deleted', + count($tag_names)).' : '. + implode(', ', $tag_names) + ); +} + +// +-----------------------------------------------------------------------+ +// | add a tag | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['add']) and !empty($_POST['add_tag']) and !is_adviser()) +{ + $tag_name = $_POST['add_tag']; + + // 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), + ) + ) + ); + + array_push( + $page['infos'], + sprintf( + l10n('Tag "%s" was added'), + stripslashes($tag_name) + ) + ); + } + else + { + array_push( + $page['errors'], + sprintf( + l10n('Tag "%s" already exists'), + stripslashes($tag_name) + ) + ); + } +} + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filenames(array('tags' => 'admin/tags.tpl')); + +$template->assign( + array( + 'F_ACTION' => PHPWG_ROOT_PATH.'admin.php?page=tags' + ) + ); + +// +-----------------------------------------------------------------------+ +// | form creation | +// +-----------------------------------------------------------------------+ + +$template->assign( + array( + 'TAG_SELECTION' => get_html_tag_selection( + get_all_tags(), + 'tags' + ), + ) + ); + +if (isset($_POST['edit']) and isset($_POST['tags'])) +{ + $template->assign( + array( + 'EDIT_TAGS_LIST' => implode(',', $_POST['tags']), + ) + ); + + $query = ' +SELECT id, name + FROM '.TAGS_TABLE.' + WHERE id IN ('.implode(',', $_POST['tags']).') +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $name_of[ $row['id'] ] = $row['name']; + } + + foreach ($_POST['tags'] as $tag_id) + { + $template->append( + 'tags', + array( + 'ID' => $tag_id, + 'NAME' => $name_of[$tag_id], + ) + ); + } +} + +// +-----------------------------------------------------------------------+ +// | sending html code | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('ADMIN_CONTENT', 'tags'); + +?> diff --git a/BSF/admin/thumbnail.php b/BSF/admin/thumbnail.php new file mode 100644 index 000000000..57ecf9cdb --- /dev/null +++ b/BSF/admin/thumbnail.php @@ -0,0 +1,352 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +//------------------------------------------------------------------- functions +// RatioResizeImg creates a new picture (a thumbnail since it is supposed to +// be smaller than original picture !) in the sub directory named +// "thumbnail". +function RatioResizeImg($path, $newWidth, $newHeight, $tn_ext) +{ + global $conf, $lang, $page; + + if (!function_exists('gd_info')) + { + return; + } + + $filename = basename($path); + $dirname = dirname($path); + + // extension of the picture filename + $extension = get_extension($filename); + + if (in_array($extension, array('jpg', 'JPG', 'jpeg', 'JPEG'))) + { + $srcImage = @imagecreatefromjpeg($path); + } + else if ($extension == 'png' or $extension == 'PNG') + { + $srcImage = @imagecreatefrompng($path); + } + else + { + unset($extension); + } + + if ( isset( $srcImage ) ) + { + // width/height + $srcWidth = imagesx( $srcImage ); + $srcHeight = imagesy( $srcImage ); + $ratioWidth = $srcWidth/$newWidth; + $ratioHeight = $srcHeight/$newHeight; + + // maximal size exceeded ? + if ( ( $ratioWidth > 1 ) or ( $ratioHeight > 1 ) ) + { + if ( $ratioWidth < $ratioHeight) + { + $destWidth = $srcWidth/$ratioHeight; + $destHeight = $newHeight; + } + else + { + $destWidth = $newWidth; + $destHeight = $srcHeight/$ratioWidth; + } + } + else + { + $destWidth = $srcWidth; + $destHeight = $srcHeight; + } + // according to the GD version installed on the server + if ( $_POST['gd'] == 2 ) + { + // GD 2.0 or more recent -> good results (but slower) + $destImage = imagecreatetruecolor( $destWidth, $destHeight); + imagecopyresampled( $destImage, $srcImage, 0, 0, 0, 0, + $destWidth,$destHeight,$srcWidth,$srcHeight ); + } + else + { + // GD prior to version 2 -> pretty bad results :-/ (but fast) + $destImage = imagecreate( $destWidth, $destHeight); + imagecopyresized( $destImage, $srcImage, 0, 0, 0, 0, + $destWidth,$destHeight,$srcWidth,$srcHeight ); + } + + if (($tndir = mkget_thumbnail_dir($dirname, $page['errors'])) == false) + { + return false; + } + + $dest_file = $tndir.'/'.$conf['prefix_thumbnail']; + $dest_file.= get_filename_wo_extension($filename); + $dest_file.= '.'.$tn_ext; + + // creation and backup of final picture + if (!is_writable($tndir)) + { + array_push($page['errors'], '['.$tndir.'] : '.l10n('no_write_access')); + return false; + } + imagejpeg($destImage, $dest_file); + // freeing memory ressources + imagedestroy( $srcImage ); + imagedestroy( $destImage ); + + list($tn_width, $tn_height) = getimagesize($dest_file); + $tn_size = floor(filesize($dest_file) / 1024).' KB'; + + $info = array( 'path' => $path, + 'tn_file' => $dest_file, + 'tn_width' => $tn_width, + 'tn_height' => $tn_height, + 'tn_size' => $tn_size ); + return $info; + } + // error + else + { + echo l10n('tn_no_support')." "; + if ( isset( $extenstion ) ) + { + echo l10n('tn_format').' '.$extension; + } + else + { + echo l10n('tn_thisformat'); + } + exit(); + } +} + +$pictures = array(); +$stats = array(); +// +-----------------------------------------------------------------------+ +// | template initialization | +// +-----------------------------------------------------------------------+ +$template->set_filenames( array('thumbnail'=>'admin/thumbnail.tpl') ); + +$template->assign(array( + 'U_HELP' => PHPWG_ROOT_PATH.'popuphelp.php?page=thumbnail', + )); +// +-----------------------------------------------------------------------+ +// | search pictures without thumbnails | +// +-----------------------------------------------------------------------+ +$wo_thumbnails = array(); +$thumbnalized = array(); + + +// what is the directory to search in ? +$query = ' +SELECT galleries_url FROM '.SITES_TABLE.' + WHERE galleries_url NOT LIKE "http://%" +;'; +$result = pwg_query($query); +while ( $row=mysql_fetch_assoc($result) ) +{ + $basedir = preg_replace('#/*$#', '', $row['galleries_url']); + $fs = get_fs($basedir); + + // because isset is one hundred time faster than in_array + $fs['thumbnails'] = array_flip($fs['thumbnails']); + + foreach ($fs['elements'] as $path) + { + // only pictures need thumbnails + if (in_array(get_extension($path), $conf['picture_ext'])) + { + $dirname = dirname($path); + $filename = basename($path); + + // only files matching the authorized filename pattern can be considered + // as "without thumbnail" + if (!preg_match('/^[a-zA-Z0-9-_.]+$/', $filename)) + { + continue; + } + + // searching the element + $filename_wo_ext = get_filename_wo_extension($filename); + $tn_ext = ''; + $base_test = $dirname.'/thumbnail/'; + $base_test.= $conf['prefix_thumbnail'].$filename_wo_ext.'.'; + foreach ($conf['picture_ext'] as $ext) + { + if (isset($fs['thumbnails'][$base_test.$ext])) + { + $tn_ext = $ext; + break; + } + } + + if (empty($tn_ext)) + { + array_push($wo_thumbnails, $path); + } + } + } // next element +} // next site id +// +-----------------------------------------------------------------------+ +// | thumbnails creation | +// +-----------------------------------------------------------------------+ +if (isset($_POST['submit'])) +{ + $times = array(); + $infos = array(); + + // checking criteria + if (!ereg('^[0-9]{2,3}$', $_POST['width']) or $_POST['width'] < 10) + { + array_push($page['errors'], l10n('tn_err_width').' 10'); + } + if (!ereg('^[0-9]{2,3}$', $_POST['height']) or $_POST['height'] < 10) + { + array_push($page['errors'], l10n('tn_err_height').' 10'); + } + + // picture miniaturization + if (count($page['errors']) == 0) + { + $num = 1; + foreach ($wo_thumbnails as $path) + { + if (is_numeric($_POST['n']) and $num > $_POST['n']) + { + break; + } + + $starttime = get_moment(); + if ($info = RatioResizeImg($path,$_POST['width'],$_POST['height'],'jpg')) + { + $endtime = get_moment(); + $info['time'] = ($endtime - $starttime) * 1000; + array_push($infos, $info); + array_push($times, $info['time']); + array_push($thumbnalized, $path); + $num++; + } + else + { + break; + } + } + + if (count($infos) > 0) + { + $sum = array_sum($times); + $average = $sum / count($times); + sort($times, SORT_NUMERIC); + $max = array_pop($times); + if (count($thumbnalized) == 1) + { + $min = $max; + } + else + { + $min = array_shift($times); + } + + $tpl_var = + array( + 'TN_NB'=>count($infos), + 'TN_TOTAL'=>number_format($sum, 2, '.', ' ').' ms', + 'TN_MAX'=>number_format($max, 2, '.', ' ').' ms', + 'TN_MIN'=>number_format($min, 2, '.', ' ').' ms', + 'TN_AVERAGE'=>number_format($average, 2, '.', ' ').' ms', + 'elements' => array() + ); + + foreach ($infos as $i => $info) + { + $tpl_var['elements'][] = + array( + 'PATH'=>$info['path'], + 'TN_FILE_IMG'=>$info['tn_file'], + 'TN_FILESIZE_IMG'=>$info['tn_size'], + 'TN_WIDTH_IMG'=>$info['tn_width'], + 'TN_HEIGHT_IMG'=>$info['tn_height'], + 'GEN_TIME'=>number_format($info['time'], 2, '.', ' ').' ms', + ); + } + $template->assign('results', $tpl_var); + } + } +} +// +-----------------------------------------------------------------------+ +// | form & pictures without thumbnails display | +// +-----------------------------------------------------------------------+ +$remainings = array_diff($wo_thumbnails, $thumbnalized); + +if (count($remainings) > 0) +{ + $form_url = get_root_url().'admin.php?page=thumbnail'; + $gd = !empty($_POST['gd']) ? $_POST['gd'] : 2; + $width = !empty($_POST['width']) ? $_POST['width'] : $conf['tn_width']; + $height = !empty($_POST['height']) ? $_POST['height'] : $conf['tn_height']; + $n = !empty($_POST['n']) ? $_POST['n'] : 5; + + $template->assign( + 'params', + array( + 'F_ACTION'=> $form_url, + 'GD_SELECTED' => $gd, + 'N_SELECTED' => $n, + 'WIDTH_TN'=>$width, + 'HEIGHT_TN'=>$height + )); + + $template->assign( + 'TOTAL_NB_REMAINING', + count($remainings)); + + foreach ($remainings as $path) + { + list($width, $height) = getimagesize($path); + $size = floor(filesize($path) / 1024).' KB'; + + $template->append( + 'remainings', + array( + 'PATH'=>$path, + 'FILESIZE_IMG'=>$size, + 'WIDTH_IMG'=>$width, + 'HEIGHT_IMG'=>$height, + )); + } +} + +// +-----------------------------------------------------------------------+ +// | return to admin | +// +-----------------------------------------------------------------------+ +$template->assign_var_from_handle('ADMIN_CONTENT', 'thumbnail'); +?> diff --git a/BSF/admin/upload.php b/BSF/admin/upload.php new file mode 100644 index 000000000..6e258f05a --- /dev/null +++ b/BSF/admin/upload.php @@ -0,0 +1,209 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if( !defined("PHPWG_ROOT_PATH") ) +{ + die ("Hacking attempt!"); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); +include_once(PHPWG_ROOT_PATH.'admin/include/functions_waiting.inc.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +//--------------------------------------------------------------------- updates + +if (isset($_POST)) +{ + $to_validate = array(); + $to_reject = array(); + + if (isset($_POST['submit'])) + { + foreach (explode(',', $_POST['list']) as $waiting_id) + { + if (isset($_POST['action-'.$waiting_id])) + { + switch ($_POST['action-'.$waiting_id]) + { + case 'reject' : + { + array_push($to_reject, $waiting_id); + break; + } + case 'validate' : + { + array_push($to_validate, $waiting_id); + break; + } + } + } + } + } + elseif (isset($_POST['validate-all']) and !empty($_POST['list'])) + { + $to_validate = explode(',', $_POST['list']); + } + elseif (isset($_POST['reject-all']) and !empty($_POST['list'])) + { + $to_reject = explode(',', $_POST['list']); + } + + if (count($to_validate) > 0) + { + $query = ' +UPDATE '.WAITING_TABLE.' + SET validated = \'true\' + WHERE id IN ('.implode(',', $to_validate).') +;'; + pwg_query($query); + + array_push( + $page['infos'], + sprintf( + l10n('%d waiting pictures validated'), + count($to_validate) + ) + ); + } + + if (count($to_reject) > 0) + { + // The uploaded element was refused, we have to delete its reference in + // the database and to delete the element as well. + $query = ' +SELECT id, storage_category_id, file, tn_ext + FROM '.WAITING_TABLE.' + WHERE id IN ('.implode(',', $to_reject).') +;'; + $result = pwg_query($query); + while($row = mysql_fetch_array($result)) + { + $dir = get_complete_dir($row['storage_category_id']); + unlink($dir.$row['file']); + $element_info = array( + 'path' => $dir.$row['file'], + 'tn_ext' => + (isset($row['tn_ext']) and $row['tn_ext']!='') ? $row['tn_ext']:'jpg' + ); + $tn_path = get_thumbnail_path( $element_info ); + + if ( @is_file($tn_path) ) + { + unlink( $tn_path ); + } + } + + $query = ' +DELETE + FROM '.WAITING_TABLE.' + WHERE id IN ('.implode(',', $to_reject).') +;'; + pwg_query($query); + + array_push( + $page['infos'], + sprintf( + l10n('%d waiting pictures rejected'), + count($to_reject) + ) + ); + } +} + +//----------------------------------------------------- template initialization +$template->set_filenames(array('upload'=>'admin/upload.tpl')); + +// TabSheet initialization +waiting_tabsheet(); + +$template->assign(array( + 'F_ACTION'=>str_replace( '&', '&', $_SERVER['REQUEST_URI']) + )); + +//---------------------------------------------------------------- form display +$cat_names = array(); +$list = array(); + +$query = 'SELECT * FROM '.WAITING_TABLE; +$query.= " WHERE validated = 'false'"; +$query.= ' ORDER BY storage_category_id'; +$query.= ';'; +$result = pwg_query( $query ); +while ( $row = mysql_fetch_array( $result ) ) +{ + if ( !isset( $cat_names[$row['storage_category_id']] ) ) + { + $cat = get_cat_info( $row['storage_category_id'] ); + $cat_names[$row['storage_category_id']] = array(); + $cat_names[$row['storage_category_id']]['dir'] = + PHPWG_ROOT_PATH.get_complete_dir( $row['storage_category_id'] ); + $cat_names[$row['storage_category_id']]['display_name'] = + get_cat_display_name($cat['upper_names']); + } + $preview_url = PHPWG_ROOT_PATH.$cat_names[$row['storage_category_id']]['dir'].$row['file']; + + $tpl_var = + array( + 'CATEGORY_IMG'=>$cat_names[$row['storage_category_id']]['display_name'], + 'ID_IMG'=>$row['id'], + 'DATE_IMG' => date('Y-m-d H:i:s', $row['date']), + 'FILE_TITLE'=>$row['file'], + 'FILE_IMG' => + (strlen($row['file']) > 10) ? + (substr($row['file'], 0, 10)).'...' : $row['file'], + 'PREVIEW_URL_IMG'=>$preview_url, + 'UPLOAD_EMAIL'=>get_email_address_as_display_text($row['mail_address']), + 'UPLOAD_USERNAME'=>$row['username'] + ); + + // is there an existing associated thumnail ? + if ( !empty( $row['tn_ext'] )) + { + $thumbnail = $conf['prefix_thumbnail']; + $thumbnail.= get_filename_wo_extension( $row['file'] ); + $thumbnail.= '.'.$row['tn_ext']; + $url = $cat_names[$row['storage_category_id']]['dir']; + $url.= 'thumbnail/'.$thumbnail; + + $tpl_var['thumbnail'] = + array( + 'PREVIEW_URL_TN_IMG' => $url, + 'FILE_TN_IMG' => + (strlen($thumbnail) > 10) ? + (substr($thumbnail, 0, 10)).'...' : $thumbnail, + 'FILE_TN_TITLE' => $thumbnail + ); + } + $template->append('pictures', $tpl_var); + array_push($list, $row['id']); +} + +$template->assign('LIST',implode(',', $list) ); + +//----------------------------------------------------------- sending html code +$template->assign_var_from_handle('ADMIN_CONTENT', 'upload'); +?> diff --git a/BSF/admin/user_list.php b/BSF/admin/user_list.php new file mode 100644 index 000000000..635424b6a --- /dev/null +++ b/BSF/admin/user_list.php @@ -0,0 +1,688 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * Add users and manage users list + */ + +// +-----------------------------------------------------------------------+ +// | functions | +// +-----------------------------------------------------------------------+ + +/** + * returns a list of users depending on page filters (in $_GET) + * + * Each user comes with his related informations : id, username, mail + * address, list of groups. + * + * @return array + */ +function get_filtered_user_list() +{ + global $conf, $page; + + $users = array(); + + // filter + $filter = array(); + + if (isset($_GET['username']) and !empty($_GET['username'])) + { + $username = str_replace('*', '%', $_GET['username']); + if (function_exists('mysql_real_escape_string')) + { + $filter['username'] = mysql_real_escape_string($username); + } + else + { + $filter['username'] = mysql_escape_string($username); + } + } + + if (isset($_GET['group']) + and -1 != $_GET['group'] + and is_numeric($_GET['group'])) + { + $filter['group'] = $_GET['group']; + } + + if (isset($_GET['status']) + and in_array($_GET['status'], get_enums(USER_INFOS_TABLE, 'status'))) + { + $filter['status'] = $_GET['status']; + } + + // how to order the list? + $order_by = 'id'; + if (isset($_GET['order_by']) + and in_array($_GET['order_by'], array_keys($page['order_by_items']))) + { + $order_by = $_GET['order_by']; + } + + $direction = 'ASC'; + if (isset($_GET['direction']) + and in_array($_GET['direction'], array_keys($page['direction_items']))) + { + $direction = strtoupper($_GET['direction']); + } + + // search users depending on filters and order + $query = ' +SELECT DISTINCT u.'.$conf['user_fields']['id'].' AS id, + u.'.$conf['user_fields']['username'].' AS username, + u.'.$conf['user_fields']['email'].' AS email, + ui.status, + ui.adviser, + ui.enabled_high, + ui.level + FROM '.USERS_TABLE.' AS u + INNER JOIN '.USER_INFOS_TABLE.' AS ui + ON u.'.$conf['user_fields']['id'].' = ui.user_id + LEFT JOIN '.USER_GROUP_TABLE.' AS ug + ON u.'.$conf['user_fields']['id'].' = ug.user_id + WHERE u.'.$conf['user_fields']['id'].' > 0'; + if (isset($filter['username'])) + { + $query.= ' + AND u.'.$conf['user_fields']['username'].' LIKE \''.$filter['username'].'\''; + } + if (isset($filter['group'])) + { + $query.= ' + AND ug.group_id = '.$filter['group']; + } + if (isset($filter['status'])) + { + $query.= ' + AND ui.status = \''.$filter['status']."'"; + } + $query.= ' + ORDER BY '.$order_by.' '.$direction.' +;'; + + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $user = $row; + $user['groups'] = array(); + + array_push($users, $user); + } + + // add group lists + $user_ids = array(); + foreach ($users as $i => $user) + { + $user_ids[$i] = $user['id']; + } + $user_nums = array_flip($user_ids); + + if (count($user_ids) > 0) + { + $query = ' +SELECT user_id, group_id + FROM '.USER_GROUP_TABLE.' + WHERE user_id IN ('.implode(',', $user_ids).') +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push( + $users[$user_nums[$row['user_id']]]['groups'], + $row['group_id'] + ); + } + } + + return $users; +} + +// +-----------------------------------------------------------------------+ +// | initialization | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die('Hacking attempt!'); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +$page['order_by_items'] = array( + 'id' => l10n('registration_date'), + 'username' => l10n('Username'), + 'level' => l10n('Privacy level'), + 'language' => l10n('language'), + ); + +$page['direction_items'] = array( + 'asc' => l10n('ascending'), + 'desc' => l10n('descending') + ); + +// +-----------------------------------------------------------------------+ +// | add a user | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['submit_add'])) +{ + $page['errors'] = register_user( + $_POST['login'], $_POST['password'], $_POST['email'], false); + + if (count($page['errors']) == 0) + { + array_push( + $page['infos'], + sprintf( + l10n('user "%s" added'), + $_POST['login'] + ) + ); + } +} + +// +-----------------------------------------------------------------------+ +// | user list | +// +-----------------------------------------------------------------------+ + +$page['filtered_users'] = get_filtered_user_list(); + +// +-----------------------------------------------------------------------+ +// | selected users | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['delete']) or isset($_POST['pref_submit'])) +{ + $collection = array(); + + switch ($_POST['target']) + { + case 'all' : + { + foreach($page['filtered_users'] as $local_user) + { + array_push($collection, $local_user['id']); + } + break; + } + case 'selection' : + { + if (isset($_POST['selection'])) + { + $collection = $_POST['selection']; + } + break; + } + } + + if (count($collection) == 0) + { + array_push($page['errors'], l10n('Select at least one user')); + } +} + +// +-----------------------------------------------------------------------+ +// | delete users | +// +-----------------------------------------------------------------------+ +if (isset($_POST['delete']) and count($collection) > 0) +{ + if (in_array($conf['guest_id'], $collection)) + { + array_push($page['errors'], l10n('Guest cannot be deleted')); + } + if (($conf['guest_id'] != $conf['default_user_id']) and + in_array($conf['default_user_id'], $collection)) + { + array_push($page['errors'], l10n('Default user cannot be deleted')); + } + if (in_array($conf['webmaster_id'], $collection)) + { + array_push($page['errors'], l10n('Webmaster cannot be deleted')); + } + if (in_array($user['id'], $collection)) + { + array_push($page['errors'], l10n('You cannot delete your account')); + } + + if (count($page['errors']) == 0) + { + if (isset($_POST['confirm_deletion']) and 1 == $_POST['confirm_deletion']) + { + foreach ($collection as $user_id) + { + delete_user($user_id); + } + array_push( + $page['infos'], + l10n_dec( + '%d user deleted', '%d users deleted', + count($collection) + ) + ); + foreach ($page['filtered_users'] as $filter_key => $filter_user) + { + if (in_array($filter_user['id'], $collection)) + { + unset($page['filtered_users'][$filter_key]); + } + } + } + else + { + array_push($page['errors'], l10n('You need to confirm deletion')); + } + } +} + +// +-----------------------------------------------------------------------+ +// | preferences form submission | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['pref_submit']) and count($collection) > 0) +{ + if (-1 != $_POST['associate']) + { + $datas = array(); + + $query = ' +SELECT user_id + FROM '.USER_GROUP_TABLE.' + WHERE group_id = '.$_POST['associate'].' +;'; + $associated = array_from_query($query, 'user_id'); + + $associable = array_diff($collection, $associated); + + if (count($associable) > 0) + { + foreach ($associable as $item) + { + array_push($datas, + array('group_id'=>$_POST['associate'], + 'user_id'=>$item)); + } + + mass_inserts(USER_GROUP_TABLE, + array('group_id', 'user_id'), + $datas); + } + } + + if (-1 != $_POST['dissociate']) + { + $query = ' +DELETE FROM '.USER_GROUP_TABLE.' + WHERE group_id = '.$_POST['dissociate'].' + AND user_id IN ('.implode(',', $collection).') +'; + pwg_query($query); + } + + // properties to set for the collection (a user list) + $datas = array(); + $dbfields = array('primary' => array('user_id'), 'update' => array()); + + $formfields = + array('nb_image_line', 'nb_line_page', 'template', 'language', + 'recent_period', 'maxwidth', 'expand', 'show_nb_comments', + 'show_nb_hits', 'maxheight', 'status', 'enabled_high', + 'level'); + + $true_false_fields = array('expand', 'show_nb_comments', + 'show_nb_hits', 'enabled_high'); + if ($conf['allow_adviser']) + { + array_push($formfields, 'adviser'); + array_push($true_false_fields, 'adviser'); + } + + foreach ($formfields as $formfield) + { + // special for true/false fields + if (in_array($formfield, $true_false_fields)) + { + $test = $formfield; + } + else + { + $test = $formfield.'_action'; + } + + if ($_POST[$test] != 'leave') + { + array_push($dbfields['update'], $formfield); + } + } + + // updating elements is useful only if needed... + if (count($dbfields['update']) > 0) + { + $datas = array(); + + foreach ($collection as $user_id) + { + $data = array(); + $data['user_id'] = $user_id; + + // TODO : verify if submited values are semanticaly correct + foreach ($dbfields['update'] as $dbfield) + { + // if the action is 'unset', the key won't be in row and + // mass_updates function will set this field to NULL + if (in_array($dbfield, $true_false_fields) + or 'set' == $_POST[$dbfield.'_action']) + { + $data[$dbfield] = $_POST[$dbfield]; + } + } + + // special users checks + if + ( + ($conf['webmaster_id'] == $user_id) or + ($conf['guest_id'] == $user_id) or + ($conf['default_user_id'] == $user_id) + ) + { + // status must not be changed + if (isset($data['status'])) + { + if ($conf['webmaster_id'] == $user_id) + { + $data['status'] = 'webmaster'; + } + else + { + $data['status'] = 'guest'; + } + } + + // could not be adivser + if (isset($data['adviser'])) + { + $data['adviser'] = 'false'; + } + } + + array_push($datas, $data); + } + + mass_updates(USER_INFOS_TABLE, $dbfields, $datas); + } + + redirect( + get_root_url(). + 'admin.php'. + get_query_string_diff(array(), false) + ); +} + +// +-----------------------------------------------------------------------+ +// | groups list | +// +-----------------------------------------------------------------------+ + +$groups[-1] = '------------'; + +$query = ' +SELECT id, name + FROM '.GROUPS_TABLE.' + ORDER BY name ASC +;'; +$result = pwg_query($query); + +while ($row = mysql_fetch_array($result)) +{ + $groups[$row['id']] = $row['name']; +} + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filenames(array('user_list'=>'admin/user_list.tpl')); + +$base_url = PHPWG_ROOT_PATH.'admin.php?page=user_list'; + +if (isset($_GET['start']) and is_numeric($_GET['start'])) +{ + $start = $_GET['start']; +} +else +{ + $start = 0; +} + +$template->assign( + array( + 'U_HELP' => get_root_url().'popuphelp.php?page=user_list', + + 'F_ADD_ACTION' => $base_url, + 'F_USERNAME' => @htmlentities($_GET['username']), + 'F_FILTER_ACTION' => get_root_url().'admin.php' + )); + +// Hide radio-button if not allow to assign adviser +if ($conf['allow_adviser']) +{ + $template->assign('adviser', true); +} + +// Filter status options +$status_options[-1] = '------------'; +foreach (get_enums(USER_INFOS_TABLE, 'status') as $status) +{ + $status_options[$status] = l10n('user_status_'.$status); +} +$template->assign('status_options', $status_options); +$template->assign('status_selected', + isset($_GET['status']) ? $_GET['status'] : ''); + +// Filter group options +$template->assign('group_options', $groups); +$template->assign('group_selected', + isset($_GET['group']) ? $_GET['group'] : ''); + +// Filter order options +$template->assign('order_options', $page['order_by_items']); +$template->assign('order_selected', + isset($_GET['order_by']) ? $_GET['order_by'] : ''); + +// Filter direction options +$template->assign('direction_options', $page['direction_items']); +$template->assign('direction_selected', + isset($_GET['direction']) ? $_GET['direction'] : ''); + + +if (isset($_POST['pref_submit'])) +{ + $template->assign( + array( + 'NB_IMAGE_LINE' => $_POST['nb_image_line'], + 'NB_LINE_PAGE' => $_POST['nb_line_page'], + 'MAXWIDTH' => $_POST['maxwidth'], + 'MAXHEIGHT' => $_POST['maxheight'], + 'RECENT_PERIOD' => $_POST['recent_period'], + )); +} +else +{ + $default_user = get_default_user_info(true); + $template->assign( + array( + 'NB_IMAGE_LINE' => $default_user['nb_image_line'], + 'NB_LINE_PAGE' => $default_user['nb_line_page'], + 'MAXWIDTH' => $default_user['maxwidth'], + 'MAXHEIGHT' => $default_user['maxheight'], + 'RECENT_PERIOD' => $default_user['recent_period'], + )); +} + +// Template Options +$template->assign('template_options', get_pwg_themes()); +$template->assign('template_selected', + isset($_POST['pref_submit']) ? $_POST['template'] : get_default_template()); + +// Language options +$template->assign('language_options', get_languages()); +$template->assign('language_selected', + isset($_POST['pref_submit']) ? $_POST['language'] : get_default_language()); + +// Status options +foreach (get_enums(USER_INFOS_TABLE, 'status') as $status) +{ + // Only status <= can be assign + if (is_autorize_status(get_access_type_status($status))) + { + $pref_status_options[$status] = l10n('user_status_'.$status); + } +} +$template->assign('pref_status_options', $pref_status_options); +$template->assign('pref_status_selected', + isset($_POST['pref_submit']) ? $_POST['status'] : 'normal'); + +// associate and dissociate options +$template->assign('association_options', $groups); +$template->assign('associate_selected', + isset($_POST['pref_submit']) ? $_POST['associate'] : ''); +$template->assign('dissociate_selected', + isset($_POST['pref_submit']) ? $_POST['dissociate'] : ''); + + +// user level options +foreach ($conf['available_permission_levels'] as $level) +{ + $level_options[$level] = l10n(sprintf('Level %d', $level)); +} +$template->assign('level_options', $level_options); +$template->assign('level_selected', + isset($_POST['pref_submit']) ? $_POST['level'] : $default_user['level']); + +// +-----------------------------------------------------------------------+ +// | navigation bar | +// +-----------------------------------------------------------------------+ + +$url = PHPWG_ROOT_PATH.'admin.php'.get_query_string_diff(array('start')); + +$navbar = create_navigation_bar( + $url, + count($page['filtered_users']), + $start, + $conf['users_page'] + ); + +$template->assign('NAVBAR', $navbar); + +// +-----------------------------------------------------------------------+ +// | user list | +// +-----------------------------------------------------------------------+ + +$profile_url = get_root_url().'admin.php?page=profile&user_id='; +$perm_url = get_root_url().'admin.php?page=user_perm&user_id='; + +$visible_user_list = array(); +foreach ($page['filtered_users'] as $num => $local_user) +{ + // simulate LIMIT $start, $conf['users_page'] + if ($num < $start) + { + continue; + } + if ($num >= $start + $conf['users_page']) + { + break; + } + + $visible_user_list[] = $local_user; +} + +// allow plugins to fill template var plugin_user_list_column_titles and +// plugin_columns/plugin_actions for each user in the list +$visible_user_list = trigger_event('loc_visible_user_list', $visible_user_list); + +foreach ($visible_user_list as $local_user) +{ + $groups_string = preg_replace( + '/(\d+)/e', + "\$groups['$1']", + implode( + ', ', + $local_user['groups'] + ) + ); + + if (isset($_POST['pref_submit']) + and isset($_POST['selection']) + and in_array($local_user['id'], $_POST['selection'])) + { + $checked = 'checked="checked"'; + } + else + { + $checked = ''; + } + + $properties = array(); + if ( $local_user['level'] != 0 ) + { + $properties[] = l10n( sprintf('Level %d', $local_user['level']) ); + } + $properties[] = + (isset($local_user['enabled_high']) and ($local_user['enabled_high'] == 'true')) + ? l10n('is_high_enabled') : l10n('is_high_disabled'); + + $template->append( + 'users', + array( + 'ID' => $local_user['id'], + 'CHECKED' => $checked, + 'U_PROFILE' => $profile_url.$local_user['id'], + 'U_PERM' => $perm_url.$local_user['id'], + 'USERNAME' => $local_user['username'] + .($local_user['id'] == $conf['guest_id'] + ? '<BR />['.l10n('is_the_guest').']' : '') + .($local_user['id'] == $conf['default_user_id'] + ? '<BR />['.l10n('is_the_default').']' : ''), + 'STATUS' => l10n('user_status_'. + $local_user['status']).(($local_user['adviser'] == 'true') + ? '<BR />['.l10n('adviser').']' : ''), + 'EMAIL' => get_email_address_as_display_text($local_user['email']), + 'GROUPS' => $groups_string, + 'PROPERTIES' => implode( ', ', $properties), + 'plugin_columns' => isset($local_user['plugin_columns']) ? $local_user['plugin_columns'] : array(), + 'plugin_actions' => isset($local_user['plugin_actions']) ? $local_user['plugin_actions'] : array(), + ) + ); +} + +// +-----------------------------------------------------------------------+ +// | html code display | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('ADMIN_CONTENT', 'user_list'); +?> diff --git a/BSF/admin/user_perm.php b/BSF/admin/user_perm.php new file mode 100644 index 000000000..f7002455a --- /dev/null +++ b/BSF/admin/user_perm.php @@ -0,0 +1,223 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('IN_ADMIN')) +{ + die('Hacking attempt!'); +} + +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// +-----------------------------------------------------------------------+ +// | variables init | +// +-----------------------------------------------------------------------+ + +if (isset($_GET['user_id']) and is_numeric($_GET['user_id'])) +{ + $page['user'] = $_GET['user_id']; +} +else +{ + die('user_id URL parameter is missing'); +} + +// +-----------------------------------------------------------------------+ +// | updates | +// +-----------------------------------------------------------------------+ + +if (isset($_POST['falsify']) + and isset($_POST['cat_true']) + and count($_POST['cat_true']) > 0) +{ + // if you forbid access to a category, all sub-categories become + // automatically forbidden + $subcats = get_subcat_ids($_POST['cat_true']); + $query = ' +DELETE FROM '.USER_ACCESS_TABLE.' + WHERE user_id = '.$page['user'].' + AND cat_id IN ('.implode(',', $subcats).') +;'; + pwg_query($query); +} +else if (isset($_POST['trueify']) + and isset($_POST['cat_false']) + and count($_POST['cat_false']) > 0) +{ + $uppercats = get_uppercat_ids($_POST['cat_false']); + $private_uppercats = array(); + + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE id IN ('.implode(',', $uppercats).') + AND status = \'private\' +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($private_uppercats, $row['id']); + } + + // retrying to authorize a category which is already authorized may cause + // an error (in SQL statement), so we need to know which categories are + // accesible + $authorized_ids = array(); + + $query = ' +SELECT cat_id + FROM '.USER_ACCESS_TABLE.' + WHERE user_id = '.$page['user'].' +;'; + $result = pwg_query($query); + + while ($row = mysql_fetch_array($result)) + { + array_push($authorized_ids, $row['cat_id']); + } + + $inserts = array(); + $to_autorize_ids = array_diff($private_uppercats, $authorized_ids); + foreach ($to_autorize_ids as $to_autorize_id) + { + array_push($inserts, array('user_id' => $page['user'], + 'cat_id' => $to_autorize_id)); + } + + mass_inserts(USER_ACCESS_TABLE, array('user_id','cat_id'), $inserts); +} + +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filenames( + array( + 'user_perm' => 'admin/user_perm.tpl', + 'double_select' => 'admin/double_select.tpl' + ) + ); + +$template->assign( + array( + 'TITLE' => + sprintf( + l10n('Manage permissions for user "%s"'), + get_username($page['user'] + ) + ), + 'L_CAT_OPTIONS_TRUE'=>l10n('authorized'), + 'L_CAT_OPTIONS_FALSE'=>l10n('forbidden'), + + 'F_ACTION' => + PHPWG_ROOT_PATH. + 'admin.php?page=user_perm'. + '&user_id='.$page['user'] + ) + ); + + +// retrieve category ids authorized to the groups the user belongs to +$group_authorized = array(); + +$query = ' +SELECT DISTINCT cat_id, c.uppercats, c.global_rank + FROM '.USER_GROUP_TABLE.' AS ug + INNER JOIN '.GROUP_ACCESS_TABLE.' AS ga + ON ug.group_id = ga.group_id + INNER JOIN '.CATEGORIES_TABLE.' AS c + ON c.id = ga.cat_id + WHERE ug.user_id = '.$page['user'].' +;'; +$result = pwg_query($query); + +if (mysql_num_rows($result) > 0) +{ + $cats = array(); + while ($row = mysql_fetch_array($result)) + { + array_push($cats, $row); + array_push($group_authorized, $row['cat_id']); + } + usort($cats, 'global_rank_compare'); + + foreach ($cats as $category) + { + $template->append( + 'categories_because_of_groups', + get_cat_display_name_cache($category['uppercats'], null, false) + ); + } +} + +// only private categories are listed +$query_true = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_ACCESS_TABLE.' ON cat_id = id + WHERE status = \'private\' + AND user_id = '.$page['user']; +if (count($group_authorized) > 0) +{ + $query_true.= ' + AND cat_id NOT IN ('.implode(',', $group_authorized).')'; +} +$query_true.= ' +;'; +display_select_cat_wrapper($query_true,array(),'category_option_true'); + +$result = pwg_query($query_true); +$authorized_ids = array(); +while ($row = mysql_fetch_array($result)) +{ + array_push($authorized_ids, $row['id']); +} + +$query_false = ' +SELECT id,name,uppercats,global_rank + FROM '.CATEGORIES_TABLE.' + WHERE status = \'private\''; +if (count($authorized_ids) > 0) +{ + $query_false.= ' + AND id NOT IN ('.implode(',', $authorized_ids).')'; +} +if (count($group_authorized) > 0) +{ + $query_false.= ' + AND id NOT IN ('.implode(',', $group_authorized).')'; +} +$query_false.= ' +;'; +display_select_cat_wrapper($query_false,array(),'category_option_false'); + +// +-----------------------------------------------------------------------+ +// | sending html code | +// +-----------------------------------------------------------------------+ + +$template->assign_var_from_handle('DOUBLE_SELECT', 'double_select'); +$template->assign_var_from_handle('ADMIN_CONTENT', 'user_perm'); +?> diff --git a/BSF/admin/ws_checker.php b/BSF/admin/ws_checker.php new file mode 100644 index 000000000..7da8fac10 --- /dev/null +++ b/BSF/admin/ws_checker.php @@ -0,0 +1,334 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// Next evolution... +// Out of parameter WS management +// The remainer objective is to check +// - Does Web Service working properly? +// - Does any access return something really? +// Give a way to check to the webmaster... +// These questions are one of module name explanations (checker). + +if((!defined("PHPWG_ROOT_PATH")) or (!$conf['allow_web_services'])) +{ + die('Hacking attempt!'); +} +include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); +include_once(PHPWG_ROOT_PATH.'include/ws_functions.inc.php'); + +/** + * official_req returns the managed requests list in array format + * FIXME A New list need to be build for ws_checker.php + * returns array of authrorized request/methods + * */ +function official_req() +{ + $official = array( /* Requests are limited to */ + 'categories.' /* all categories. methods */ + , 'categories.getImages' + , 'categories.getList' + , 'images.' /* all images. methods */ + , 'images.getInfo' + , 'images.addComment' + , 'images.search' + , 'tags.' /* all tags. methods */ + , 'tags.getImages' + , 'tags.getList' + ); + if (function_exists('local_req')) { + $local = local_req(); + return array_merge( $official, $local ); + } + return $official; +} + +/** + * check_target($string) verifies and corrects syntax of target parameter + * example : check_target(cat/23,24,24,24,25,27) returns cat/23-25,27 + * */ +function check_target($list) +{ + if ( $list !== '' ) + { + $type = explode('/',$list); // Find type list + if ( !in_array($type[0],array('list','cat','tag') ) ) + { + $type[0] = 'list'; // Assume an id list + } + $ids = explode( ',',$type[1] ); + $list = $type[0] . '/'; + + // 1,2,21,3,22,4,5,9-12,6,11,12,13,2,4,6, + + $result = expand_id_list( $ids ); + + // 1,2,3,4,5,6,9,10,11,12,13,21,22, + // I would like + // 1-6,9-13,21-22 + $serial[] = $result[0]; // To be shifted + foreach ($result as $k => $id) + { + $next_less_1 = (isset($result[$k + 1]))? $result[$k + 1] - 1:-1; + if ( $id == $next_less_1 and end($serial)=='-' ) + { // nothing to do + } + elseif ( $id == $next_less_1 ) + { + $serial[]=$id; + $serial[]='-'; + } + else + { + $serial[]=$id; // end serie or non serie + } + } + $null = array_shift($serial); // remove first value + $list .= array_shift($serial); // add the real first one + $separ = ','; + foreach ($serial as $id) + { + $list .= ($id=='-') ? '' : $separ . $id; + $separ = ($id=='-') ? '-':','; // add comma except if hyphen + } + } + return $list; +} + +// +-----------------------------------------------------------------------+ +// | Check Access and exit when user status is not ok | +// +-----------------------------------------------------------------------+ +check_status(ACCESS_ADMINISTRATOR); + +// accepted queries +$req_type_list = official_req(); + +//--------------------------------------------------------- update informations +$chk_partner = ''; +// Is a new access required? + +if (isset($_POST['wsa_submit'])) +{ +// Check $_post (Some values are commented - maybe a future use) +$add_partner = htmlspecialchars( $_POST['add_partner'], ENT_QUOTES); +$add_target = check_target( $_POST['add_target']) ; +$add_end = ( is_numeric($_POST['add_end']) ) ? $_POST['add_end']:0; +$add_request = htmlspecialchars( $_POST['add_request'], ENT_QUOTES); +$add_limit = ( is_numeric($_POST['add_limit']) ) ? $_POST['add_limit']:1; +$add_comment = htmlspecialchars( $_POST['add_comment'], ENT_QUOTES); +if ( strlen($add_partner) < 8 ) +{ // TODO What? Complete with some MD5... +} + $query = ' +INSERT INTO '.WEB_SERVICES_ACCESS_TABLE.' +( `name` , `access` , `start` , `end` , `request` , `limit` , `comment` ) +VALUES (' . " + '$add_partner', '$add_target', + NOW(), + ADDDATE( NOW(), INTERVAL $add_end DAY), + '$add_request', '$add_limit', '$add_comment' );"; + + pwg_query($query); + $chk_partner = $add_partner; + + $template->append( + 'update_results', + l10n('ws_adding_legend').l10n('ws_success_upd') + ); +} + +// Next, Update selected access +if (isset($_POST['wsu_submit'])) +{ + $upd_end = ( is_numeric($_POST['upd_end']) ) ? $_POST['upd_end']:0; + $settxt = ' end = ADDDATE(NOW(), INTERVAL '. $upd_end .' DAY)'; + + if ((isset($_POST['selection'])) and (trim($settxt) != '')) + { + $uid = (int) $_POST['selection']; + $query = ' + UPDATE '.WEB_SERVICES_ACCESS_TABLE.' + SET '.$settxt.' + WHERE id = '.$uid.'; '; + pwg_query($query); + $template->append( + 'update_results', + l10n('ws_update_legend').l10n('ws_success_upd') + ); + } else { + $template->append( + 'update_results', + l10n('ws_update_legend').l10n('ws_failed_upd') + ); + } +} +// Next, Delete selected access + +if (isset($_POST['wsX_submit'])) +{ + if ((isset($_POST['delete_confirmation'])) + and (isset($_POST['selection']))) + { + $uid = (int) $_POST['selection']; + $query = 'DELETE FROM '.WEB_SERVICES_ACCESS_TABLE.' + WHERE id = '.$uid.'; '; + pwg_query($query); + $template->append( + 'update_results', + l10n('ws_delete_legend').l10n('ws_success_upd') + ); + } else { + $template->append( + 'update_results', + l10n('Not selected / Not confirmed').l10n('ws_failed_upd') + ); + } +} + + + +$template->assign( + array( + 'U_HELP' => get_root_url().'popuphelp.php?page=web_service', + ) + ); + +// Build where +$where = ''; +$order = ' ORDER BY `id` DESC' ; + +$query = ' +SELECT * + FROM '.WEB_SERVICES_ACCESS_TABLE.' +WHERE 1=1 ' +.$where. +' ' +.$order. +';'; +$result = pwg_query($query); +$acc_list = mysql_num_rows($result); +$result = pwg_query($query); +// +-----------------------------------------------------------------------+ +// | template init | +// +-----------------------------------------------------------------------+ + +$template->set_filenames( + array( + 'ws_checker' => 'admin/ws_checker.tpl' + ) + ); + + +// Access List +while ($row = mysql_fetch_array($result)) +{ + $chk_partner = ( $chk_partner == '' ) ? $row['name'] : $chk_partner; + $template->append( + 'access_list', + array( + 'ID' => $row['id'], + 'NAME' => + (is_adviser()) ? '*********' : $row['name'], + 'TARGET' => $row['access'], + 'END' => $row['end'], + 'REQUEST' => $row['request'], + 'LIMIT' => $row['limit'], + 'COMMENT' => $row['comment'], + ) + ); +} + +$template->assign('add_requests', $req_type_list); + +$template->assign('add_limits', $conf['ws_allowed_limit'] ); + +// Postponed Start Date +// By default 0, 1, 2, 3, 5, 7, 14 or 30 days +/*foreach ($conf['ws_postponed_start'] as $value) { + $template->assign_block_vars( + 'add_start', + array( + 'VALUE'=> $value, + 'CONTENT' => $value, + 'SELECTED' => ($conf['ws_postponed_start'][0] == $value) ? $selected:'', + ) + ); +}*/ + +// Durations (Allowed Web Services Period) +// By default 10, 5, 2, 1 year(s) or 6, 3, 1 month(s) or 15, 10, 7, 5, 1, 0 day(s) +$template->assign('add_ends', $conf['ws_durations']); + +if ( $chk_partner !== '' ) +{ + if (function_exists('curl_init')) + { + $request = get_absolute_root_url().'ws.php?method=pwg.getVersion&format=rest&' + . "partner=$chk_partner" ; + $session = curl_init($request); + curl_setopt ($session, CURLOPT_POST, true); + curl_setopt($session, CURLOPT_HEADER, true); + curl_setopt($session, CURLOPT_RETURNTRANSFER, true); + $response = curl_exec($session); + curl_close($session); + $status_code = array(); + preg_match('/\d\d\d/', $response, $status_code); + switch( $status_code[0] ) { + case 200: + $ws_status = l10n('Web Services under control'); + break; + case 503: + $ws_status = 'Piwigo Web Services failed and returned an ' + . 'HTTP status of 503. Service is unavailable. An internal ' + . 'problem prevented us from returning data to you.'; + break; + case 403: + $ws_status = 'Piwigo Web Services failed and returned an ' + . 'HTTP status of 403. Access is forbidden. You do not have ' + . 'permission to access this resource, or are over ' + . 'your rate limit.'; + break; + case 400: + // You may want to fall through here and read the specific XML error + $ws_status = 'Piwigo Web Services failed and returned an ' + . 'HTTP status of 400. Bad request. The parameters passed ' + . 'to the service did not match as expected. The exact ' + . 'error is returned in the XML response.'; + break; + default: + $ws_status = 'Piwigo Web Services returned an unexpected HTTP ' + . 'status of:' . $status_code[0]; + } + } + else + { + $ws_status = 'Cannot check - curl not installed'; + } + $template->assign( 'WS_STATUS', $ws_status ); +} + +//----------------------------------------------------------- sending html code + +$template->assign_var_from_handle('ADMIN_CONTENT', 'ws_checker'); + +include_once(PHPWG_ROOT_PATH.'include/ws_core.inc.php'); +?> |