From 77fd1f51a3c5f5a52f72ef8a299fe368228e2285 Mon Sep 17 00:00:00 2001 From: vdigital Date: Fri, 23 May 2008 21:05:41 +0000 Subject: git-svn-id: http://piwigo.org/svn/trunk@2357 68402e56-0260-453c-a942-63ccdbb3a9ee --- BSF/about.php | 70 + BSF/action.php | 203 + BSF/admin.php | 172 + BSF/admin/advanced_feature.php | 107 + BSF/admin/cat_list.php | 253 + BSF/admin/cat_modify.php | 553 ++ BSF/admin/cat_move.php | 104 + BSF/admin/cat_options.php | 312 ++ BSF/admin/cat_perm.php | 330 ++ BSF/admin/comments.php | 179 + BSF/admin/configuration.php | 301 + BSF/admin/element_set.php | 232 + BSF/admin/element_set_global.php | 382 ++ BSF/admin/element_set_unit.php | 274 + BSF/admin/group_list.php | 207 + BSF/admin/group_perm.php | 185 + BSF/admin/help.php | 32 + BSF/admin/history.php | 685 +++ BSF/admin/images/index.php | 30 + BSF/admin/include/c13y_internal.class.php | 249 + BSF/admin/include/check_integrity.class.php | 345 ++ BSF/admin/include/functions.php | 1872 +++++++ BSF/admin/include/functions_history.inc.php | 179 + BSF/admin/include/functions_metadata.php | 298 + .../include/functions_notification_by_mail.inc.php | 522 ++ BSF/admin/include/functions_permalinks.php | 204 + BSF/admin/include/functions_plugins.inc.php | 64 + BSF/admin/include/functions_upgrade.php | 98 + BSF/admin/include/functions_waiting.inc.php | 41 + BSF/admin/include/index.php | 30 + BSF/admin/include/pclzip.lib.php | 5872 ++++++++++++++++++++ BSF/admin/include/plugins.class.php | 484 ++ BSF/admin/include/tabsheet.class.php | 146 + BSF/admin/index.php | 30 + BSF/admin/intro.php | 285 + BSF/admin/maintenance.php | 142 + BSF/admin/notification_by_mail.php | 738 +++ BSF/admin/permalinks.php | 179 + BSF/admin/picture_modify.php | 437 ++ BSF/admin/plugin.php | 62 + BSF/admin/plugins_list.php | 154 + BSF/admin/plugins_new.php | 139 + BSF/admin/plugins_update.php | 169 + BSF/admin/profile.php | 46 + BSF/admin/rating.php | 258 + BSF/admin/site_manager.php | 307 + BSF/admin/site_reader_local.php | 265 + BSF/admin/site_reader_remote.php | 250 + BSF/admin/site_update.php | 991 ++++ BSF/admin/stats.php | 514 ++ BSF/admin/tags.php | 246 + BSF/admin/thumbnail.php | 352 ++ BSF/admin/upload.php | 209 + BSF/admin/user_list.php | 688 +++ BSF/admin/user_perm.php | 223 + BSF/admin/ws_checker.php | 334 ++ BSF/category.php | 65 + BSF/comments.php | 394 ++ BSF/doc/COPYING | 340 ++ BSF/doc/ChangeLog | 822 +++ BSF/doc/README_en.txt | 105 + BSF/doc/README_fr.txt | 116 + BSF/doc/index.php | 30 + BSF/feed.php | 202 + BSF/galleries/.cvsignore | 1 + BSF/galleries/index.php | 30 + BSF/identification.php | 93 + BSF/include/calendar_base.class.php | 351 ++ BSF/include/calendar_monthly.class.php | 515 ++ BSF/include/calendar_weekly.class.php | 136 + BSF/include/category_cats.inc.php | 298 + BSF/include/category_default.inc.php | 170 + BSF/include/class_smtp_mail.inc.php | 157 + BSF/include/common.inc.php | 283 + BSF/include/config_default.inc.php | 700 +++ BSF/include/constants.php | 112 + BSF/include/feedcreator.class.php | 1541 +++++ BSF/include/filter.inc.php | 141 + BSF/include/functions.inc.php | 1557 ++++++ BSF/include/functions_calendar.inc.php | 295 + BSF/include/functions_category.inc.php | 509 ++ BSF/include/functions_comment.inc.php | 228 + BSF/include/functions_cookie.inc.php | 115 + BSF/include/functions_filter.inc.php | 63 + BSF/include/functions_group.inc.php | 26 + BSF/include/functions_html.inc.php | 751 +++ BSF/include/functions_mail.inc.php | 822 +++ BSF/include/functions_metadata.inc.php | 142 + BSF/include/functions_notification.inc.php | 608 ++ BSF/include/functions_picture.inc.php | 330 ++ BSF/include/functions_plugins.inc.php | 284 + BSF/include/functions_rate.inc.php | 134 + BSF/include/functions_search.inc.php | 560 ++ BSF/include/functions_session.inc.php | 225 + BSF/include/functions_tag.inc.php | 323 ++ BSF/include/functions_url.inc.php | 740 +++ BSF/include/functions_user.inc.php | 1340 +++++ BSF/include/functions_xml.inc.php | 141 + BSF/include/index.php | 30 + BSF/include/menubar.inc.php | 311 ++ BSF/include/page_header.php | 90 + BSF/include/page_tail.php | 74 + BSF/include/php_compat/array_intersect_key.php | 35 + BSF/include/php_compat/file_put_contents.php | 14 + BSF/include/php_compat/hash_hmac.php | 25 + BSF/include/php_compat/index.php | 30 + BSF/include/php_compat/preg_last_error.php | 41 + BSF/include/picture_comment.inc.php | 183 + BSF/include/picture_metadata.inc.php | 99 + BSF/include/picture_rate.inc.php | 91 + BSF/include/section_init.inc.php | 620 +++ BSF/include/smarty/COPYING.lib | 458 ++ BSF/include/smarty/NEWS | 1024 ++++ BSF/include/smarty/README | 85 + BSF/include/smarty/libs/Config_File.class.php | 389 ++ BSF/include/smarty/libs/Smarty.class.php | 1968 +++++++ BSF/include/smarty/libs/Smarty_Compiler.class.php | 2325 ++++++++ BSF/include/smarty/libs/debug.tpl | 157 + .../internals/core.assemble_plugin_filepath.php | 67 + .../internals/core.assign_smarty_interface.php | 43 + .../libs/internals/core.create_dir_structure.php | 79 + .../libs/internals/core.display_debug_console.php | 61 + .../libs/internals/core.get_include_path.php | 44 + .../smarty/libs/internals/core.get_microtime.php | 23 + .../libs/internals/core.get_php_resource.php | 80 + .../smarty/libs/internals/core.is_secure.php | 59 + .../smarty/libs/internals/core.is_trusted.php | 47 + .../smarty/libs/internals/core.load_plugins.php | 125 + .../libs/internals/core.load_resource_plugin.php | 74 + .../libs/internals/core.process_cached_inserts.php | 71 + .../internals/core.process_compiled_include.php | 37 + .../smarty/libs/internals/core.read_cache_file.php | 101 + BSF/include/smarty/libs/internals/core.rm_auto.php | 71 + BSF/include/smarty/libs/internals/core.rmdir.php | 54 + .../libs/internals/core.run_insert_handler.php | 71 + .../libs/internals/core.smarty_include_php.php | 50 + .../libs/internals/core.write_cache_file.php | 96 + .../libs/internals/core.write_compiled_include.php | 91 + .../internals/core.write_compiled_resource.php | 35 + .../smarty/libs/internals/core.write_file.php | 54 + .../smarty/libs/plugins/block.textformat.php | 103 + .../smarty/libs/plugins/compiler.assign.php | 40 + .../libs/plugins/function.assign_debug_info.php | 40 + .../smarty/libs/plugins/function.config_load.php | 142 + .../smarty/libs/plugins/function.counter.php | 80 + BSF/include/smarty/libs/plugins/function.cycle.php | 102 + BSF/include/smarty/libs/plugins/function.debug.php | 35 + BSF/include/smarty/libs/plugins/function.eval.php | 49 + BSF/include/smarty/libs/plugins/function.fetch.php | 221 + .../libs/plugins/function.html_checkboxes.php | 143 + .../smarty/libs/plugins/function.html_image.php | 142 + .../smarty/libs/plugins/function.html_options.php | 122 + .../smarty/libs/plugins/function.html_radios.php | 156 + .../libs/plugins/function.html_select_date.php | 331 ++ .../libs/plugins/function.html_select_time.php | 194 + .../smarty/libs/plugins/function.html_table.php | 177 + .../smarty/libs/plugins/function.mailto.php | 165 + BSF/include/smarty/libs/plugins/function.math.php | 84 + BSF/include/smarty/libs/plugins/function.popup.php | 119 + .../smarty/libs/plugins/function.popup_init.php | 40 + .../smarty/libs/plugins/modifier.capitalize.php | 43 + BSF/include/smarty/libs/plugins/modifier.cat.php | 33 + .../libs/plugins/modifier.count_characters.php | 32 + .../libs/plugins/modifier.count_paragraphs.php | 29 + .../libs/plugins/modifier.count_sentences.php | 29 + .../smarty/libs/plugins/modifier.count_words.php | 33 + .../smarty/libs/plugins/modifier.date_format.php | 58 + .../libs/plugins/modifier.debug_print_var.php | 90 + .../smarty/libs/plugins/modifier.default.php | 32 + .../smarty/libs/plugins/modifier.escape.php | 93 + .../smarty/libs/plugins/modifier.indent.php | 28 + BSF/include/smarty/libs/plugins/modifier.lower.php | 26 + BSF/include/smarty/libs/plugins/modifier.nl2br.php | 35 + .../smarty/libs/plugins/modifier.regex_replace.php | 37 + .../smarty/libs/plugins/modifier.replace.php | 30 + .../smarty/libs/plugins/modifier.spacify.php | 30 + .../smarty/libs/plugins/modifier.string_format.php | 29 + BSF/include/smarty/libs/plugins/modifier.strip.php | 33 + .../smarty/libs/plugins/modifier.strip_tags.php | 32 + .../smarty/libs/plugins/modifier.truncate.php | 50 + BSF/include/smarty/libs/plugins/modifier.upper.php | 26 + .../smarty/libs/plugins/modifier.wordwrap.php | 29 + .../libs/plugins/outputfilter.trimwhitespace.php | 75 + .../libs/plugins/shared.escape_special_chars.php | 31 + .../smarty/libs/plugins/shared.make_timestamp.php | 46 + BSF/include/template.class.php | 385 ++ BSF/include/upload.class.php | 41 + BSF/include/user.inc.php | 74 + BSF/include/ws_core.inc.php | 619 +++ BSF/include/ws_functions.inc.php | 1103 ++++ BSF/include/ws_protocols/index.php | 30 + BSF/include/ws_protocols/json_encoder.php | 87 + BSF/include/ws_protocols/php_encoder.php | 54 + BSF/include/ws_protocols/rest_encoder.php | 281 + BSF/include/ws_protocols/rest_handler.php | 57 + BSF/include/ws_protocols/xmlrpc_encoder.php | 115 + BSF/index.php | 292 + BSF/install.php | 409 ++ BSF/install/config.sql | 29 + BSF/install/db/1-database.php | 42 + BSF/install/db/10-database.php | 52 + BSF/install/db/11-database.php | 65 + BSF/install/db/12-database.php | 99 + BSF/install/db/13-database.php | 69 + BSF/install/db/14-database.php | 59 + BSF/install/db/15-database.php | 46 + BSF/install/db/16-database.php | 50 + BSF/install/db/17-database.php | 60 + BSF/install/db/18-database.php | 88 + BSF/install/db/19-database.php | 149 + BSF/install/db/2-database.php | 74 + BSF/install/db/20-database.php | 87 + BSF/install/db/21-database.php | 48 + BSF/install/db/22-database.php | 54 + BSF/install/db/23-database.php | 46 + BSF/install/db/24-database.php | 46 + BSF/install/db/25-database.php | 47 + BSF/install/db/26-database.php | 43 + BSF/install/db/27-database.php | 43 + BSF/install/db/28-database.php | 42 + BSF/install/db/29-database.php | 42 + BSF/install/db/3-database.php | 53 + BSF/install/db/30-database.php | 50 + BSF/install/db/31-database.php | 43 + BSF/install/db/32-database.php | 43 + BSF/install/db/33-database.php | 51 + BSF/install/db/34-database.php | 56 + BSF/install/db/35-database.php | 58 + BSF/install/db/36-database.php | 43 + BSF/install/db/37-database.php | 63 + BSF/install/db/38-database.php | 46 + BSF/install/db/39-database.php | 40 + BSF/install/db/4-database.php | 50 + BSF/install/db/40-database.php | 40 + BSF/install/db/41-database.php | 61 + BSF/install/db/42-database.php | 84 + BSF/install/db/43-database.php | 47 + BSF/install/db/44-database.php | 47 + BSF/install/db/45-database.php | 48 + BSF/install/db/46-database.php | 46 + BSF/install/db/47-database.php | 52 + BSF/install/db/48-database.php | 48 + BSF/install/db/49-database.php | 54 + BSF/install/db/5-database.php | 46 + BSF/install/db/50-database.php | 50 + BSF/install/db/51-database.php | 57 + BSF/install/db/52-database.php | 69 + BSF/install/db/53-database.php | 57 + BSF/install/db/54-database.php | 69 + BSF/install/db/55-database.php | 59 + BSF/install/db/56-database.php | 49 + BSF/install/db/57-database.php | 63 + BSF/install/db/58-database.php | 48 + BSF/install/db/59-database.php | 79 + BSF/install/db/6-database.php | 53 + BSF/install/db/60-database.php | 86 + BSF/install/db/61-database.php | 50 + BSF/install/db/62-database.php | 48 + BSF/install/db/63-database.php | 73 + BSF/install/db/64-database.php | 50 + BSF/install/db/65-database.php | 319 ++ BSF/install/db/66-database.php | 48 + BSF/install/db/67-database.php | 48 + BSF/install/db/68-database.php | 55 + BSF/install/db/69-database.php | 58 + BSF/install/db/7-database.php | 65 + BSF/install/db/70-database.php | 53 + BSF/install/db/71-database.php | 58 + BSF/install/db/8-database.php | 83 + BSF/install/db/9-database.php | 86 + BSF/install/db/index.php | 30 + BSF/install/index.php | 30 + BSF/install/piwigo_structure.sql | 457 ++ BSF/install/upgrade_1.3.0.php | 126 + BSF/install/upgrade_1.3.1.php | 601 ++ BSF/install/upgrade_1.4.0.php | 292 + BSF/install/upgrade_1.5.0.php | 469 ++ BSF/install/upgrade_1.6.0.php | 54 + BSF/install/upgrade_1.6.2.php | 346 ++ BSF/language/en_UK/about.html | 10 + BSF/language/en_UK/admin.lang.php | 649 +++ BSF/language/en_UK/common.lang.php | 368 ++ BSF/language/en_UK/help.html | 259 + BSF/language/en_UK/help/advanced_feature.html | 16 + BSF/language/en_UK/help/cat_modify.html | 141 + BSF/language/en_UK/help/cat_move.html | 14 + BSF/language/en_UK/help/cat_options.html | 36 + BSF/language/en_UK/help/cat_perm.html | 15 + BSF/language/en_UK/help/configuration.html | 135 + BSF/language/en_UK/help/group_list.html | 22 + BSF/language/en_UK/help/history.html | 45 + BSF/language/en_UK/help/index.php | 30 + BSF/language/en_UK/help/maintenance.html | 46 + BSF/language/en_UK/help/notification_by_mail.html | 15 + BSF/language/en_UK/help/permalinks.html | 7 + BSF/language/en_UK/help/search.html | 24 + BSF/language/en_UK/help/site_manager.html | 51 + BSF/language/en_UK/help/synchronize.html | 13 + BSF/language/en_UK/help/thumbnail.html | 28 + BSF/language/en_UK/help/user_list.html | 43 + BSF/language/en_UK/help/web_service.html | 47 + BSF/language/en_UK/index.php | 30 + BSF/language/en_UK/install.lang.php | 70 + BSF/language/en_UK/iso.txt | 1 + BSF/language/es_ES/about.html | 8 + BSF/language/es_ES/admin.lang.php | 655 +++ BSF/language/es_ES/common.lang.php | 368 ++ BSF/language/es_ES/help.html | 183 + BSF/language/es_ES/help/advanced_feature.html | 16 + BSF/language/es_ES/help/cat_modify.html | 117 + BSF/language/es_ES/help/cat_move.html | 12 + BSF/language/es_ES/help/cat_options.html | 30 + BSF/language/es_ES/help/cat_perm.html | 11 + BSF/language/es_ES/help/configuration.html | 101 + BSF/language/es_ES/help/group_list.html | 21 + BSF/language/es_ES/help/history.html | 51 + BSF/language/es_ES/help/index.php | 30 + BSF/language/es_ES/help/maintenance.html | 27 + BSF/language/es_ES/help/notification_by_mail.html | 15 + BSF/language/es_ES/help/permalinks.html | 7 + BSF/language/es_ES/help/search.html | 23 + BSF/language/es_ES/help/site_manager.html | 42 + BSF/language/es_ES/help/synchronize.html | 12 + BSF/language/es_ES/help/thumbnail.html | 25 + BSF/language/es_ES/help/user_list.html | 33 + BSF/language/es_ES/help/web_service.html | 46 + BSF/language/es_ES/index.php | 30 + BSF/language/es_ES/install.lang.php | 68 + BSF/language/es_ES/iso.txt | 1 + BSF/language/fr_FR/about.html | 8 + BSF/language/fr_FR/admin.lang.php | 649 +++ BSF/language/fr_FR/common.lang.php | 368 ++ BSF/language/fr_FR/help.html | 250 + BSF/language/fr_FR/help/advanced_feature.html | 16 + BSF/language/fr_FR/help/cat_modify.html | 149 + BSF/language/fr_FR/help/cat_move.html | 15 + BSF/language/fr_FR/help/cat_options.html | 42 + BSF/language/fr_FR/help/cat_perm.html | 16 + BSF/language/fr_FR/help/configuration.html | 137 + BSF/language/fr_FR/help/group_list.html | 21 + BSF/language/fr_FR/help/history.html | 52 + BSF/language/fr_FR/help/index.php | 30 + BSF/language/fr_FR/help/maintenance.html | 51 + BSF/language/fr_FR/help/notification_by_mail.html | 15 + BSF/language/fr_FR/help/permalinks.html | 7 + BSF/language/fr_FR/help/search.html | 27 + BSF/language/fr_FR/help/site_manager.html | 56 + BSF/language/fr_FR/help/synchronize.html | 19 + BSF/language/fr_FR/help/thumbnail.html | 36 + BSF/language/fr_FR/help/user_list.html | 39 + BSF/language/fr_FR/help/web_service.html | 48 + BSF/language/fr_FR/index.php | 30 + BSF/language/fr_FR/install.lang.php | 68 + BSF/language/fr_FR/iso.txt | 1 + BSF/language/index.php | 30 + BSF/language/nl_NL/about.html | 10 + BSF/language/nl_NL/admin.lang.php | 655 +++ BSF/language/nl_NL/common.lang.php | 368 ++ BSF/language/nl_NL/help.html | 227 + BSF/language/nl_NL/help/advanced_feature.html | 16 + BSF/language/nl_NL/help/cat_modify.html | 128 + BSF/language/nl_NL/help/cat_move.html | 15 + BSF/language/nl_NL/help/cat_options.html | 30 + BSF/language/nl_NL/help/cat_perm.html | 14 + BSF/language/nl_NL/help/configuration.html | 105 + BSF/language/nl_NL/help/group_list.html | 22 + BSF/language/nl_NL/help/index.php | 30 + BSF/language/nl_NL/help/maintenance.html | 37 + BSF/language/nl_NL/help/notification_by_mail.html | 15 + BSF/language/nl_NL/help/permalinks.html | 7 + BSF/language/nl_NL/help/search.html | 19 + BSF/language/nl_NL/help/site_manager.html | 36 + BSF/language/nl_NL/help/synchronize.html | 8 + BSF/language/nl_NL/help/thumbnail.html | 25 + BSF/language/nl_NL/help/user_list.html | 39 + BSF/language/nl_NL/help/web_service.html | 45 + BSF/language/nl_NL/index.php | 30 + BSF/language/nl_NL/install.lang.php | 67 + BSF/language/nl_NL/iso.txt | 1 + BSF/nbm.php | 87 + BSF/notification.php | 91 + BSF/password.php | 165 + BSF/picture.php | 877 +++ BSF/plugins/LocalFilesEditor/admin.php | 304 + BSF/plugins/LocalFilesEditor/admin.tpl | 49 + .../LocalFilesEditor/editarea/edit_area_full.js | 38 + .../LocalFilesEditor/editarea/images/close.gif | Bin 0 -> 102 bytes .../editarea/images/fullscreen.gif | Bin 0 -> 198 bytes .../editarea/images/go_to_line.gif | Bin 0 -> 1053 bytes .../LocalFilesEditor/editarea/images/help.gif | Bin 0 -> 295 bytes .../LocalFilesEditor/editarea/images/highlight.gif | Bin 0 -> 256 bytes .../LocalFilesEditor/editarea/images/index.php | 30 + .../LocalFilesEditor/editarea/images/load.gif | Bin 0 -> 1041 bytes .../LocalFilesEditor/editarea/images/move.gif | Bin 0 -> 257 bytes .../editarea/images/newdocument.gif | Bin 0 -> 170 bytes .../LocalFilesEditor/editarea/images/opacity.png | Bin 0 -> 147 bytes .../editarea/images/processing.gif | Bin 0 -> 825 bytes .../LocalFilesEditor/editarea/images/redo.gif | Bin 0 -> 169 bytes .../editarea/images/reset_highlight.gif | Bin 0 -> 168 bytes .../LocalFilesEditor/editarea/images/save.gif | Bin 0 -> 285 bytes .../LocalFilesEditor/editarea/images/search.gif | Bin 0 -> 191 bytes .../editarea/images/smooth_selection.gif | Bin 0 -> 174 bytes .../LocalFilesEditor/editarea/images/spacer.gif | Bin 0 -> 43 bytes .../editarea/images/statusbar_resize.gif | Bin 0 -> 79 bytes .../LocalFilesEditor/editarea/images/undo.gif | Bin 0 -> 175 bytes BSF/plugins/LocalFilesEditor/editarea/index.php | 30 + BSF/plugins/LocalFilesEditor/editarea/langs/cs.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/de.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/dk.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/en.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/es.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/fr.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/hr.js | 61 + .../LocalFilesEditor/editarea/langs/index.php | 30 + BSF/plugins/LocalFilesEditor/editarea/langs/it.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/ja.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/mk.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/nl.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/pl.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/pt.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/ru.js | 61 + BSF/plugins/LocalFilesEditor/editarea/langs/sk.js | 61 + .../LocalFilesEditor/editarea/reg_syntax/css.js | 84 + .../LocalFilesEditor/editarea/reg_syntax/html.js | 50 + .../LocalFilesEditor/editarea/reg_syntax/index.php | 30 + .../LocalFilesEditor/editarea/reg_syntax/js.js | 60 + .../LocalFilesEditor/editarea/reg_syntax/php.js | 75 + .../LocalFilesEditor/editarea/reg_syntax/sql.js | 55 + .../LocalFilesEditor/editarea/reg_syntax/xml.js | 56 + BSF/plugins/LocalFilesEditor/functions.inc.php | 70 + BSF/plugins/LocalFilesEditor/index.php | 30 + .../LocalFilesEditor/language/en_UK/index.php | 30 + .../language/en_UK/plugin.lang.php | 45 + .../LocalFilesEditor/language/es_ES/index.php | 30 + .../language/es_ES/plugin.lang.php | 45 + .../LocalFilesEditor/language/fr_FR/index.php | 30 + .../language/fr_FR/plugin.lang.php | 45 + BSF/plugins/LocalFilesEditor/language/index.php | 30 + BSF/plugins/LocalFilesEditor/main.inc.php | 46 + BSF/plugins/LocalFilesEditor/show_default.php | 68 + BSF/plugins/LocalFilesEditor/show_default.tpl | 13 + BSF/plugins/add_index/admin/index.php | 30 + BSF/plugins/add_index/admin/main_page.php | 205 + BSF/plugins/add_index/admin/main_page.tpl | 15 + BSF/plugins/add_index/index.php | 30 + .../language/en_UK/help/advanced_feature.html | 7 + .../add_index/language/en_UK/help/index.php | 30 + .../language/en_UK/help/site_manager.html | 7 + BSF/plugins/add_index/language/en_UK/index.php | 30 + .../add_index/language/en_UK/plugin.lang.php | 39 + .../language/es_ES/help/advanced_feature.html | 7 + .../add_index/language/es_ES/help/index.php | 30 + .../language/es_ES/help/site_manager.html | 7 + BSF/plugins/add_index/language/es_ES/index.php | 30 + .../add_index/language/es_ES/plugin.lang.php | 39 + .../language/fr_FR/help/advanced_feature.html | 7 + .../add_index/language/fr_FR/help/index.php | 30 + .../language/fr_FR/help/site_manager.html | 7 + BSF/plugins/add_index/language/fr_FR/index.php | 30 + .../add_index/language/fr_FR/plugin.lang.php | 39 + BSF/plugins/add_index/language/index.php | 30 + BSF/plugins/add_index/main.admin.inc.php | 93 + BSF/plugins/add_index/main.base.inc.php | 39 + BSF/plugins/add_index/main.inc.php | 53 + BSF/plugins/add_index/main.normal.inc.php | 60 + BSF/plugins/admin_advices/admin_advices.tpl | 39 + BSF/plugins/admin_advices/default-layout.css | 19 + BSF/plugins/admin_advices/en_UK/index.php | 30 + BSF/plugins/admin_advices/en_UK/lang.adv.php | 447 ++ BSF/plugins/admin_advices/fr_FR/index.php | 30 + BSF/plugins/admin_advices/fr_FR/lang.adv.php | 480 ++ BSF/plugins/admin_advices/index.php | 30 + BSF/plugins/admin_advices/main.inc.php | 127 + BSF/plugins/admin_multi_view/controller.php | 221 + BSF/plugins/admin_multi_view/index.php | 30 + BSF/plugins/admin_multi_view/is_admin.inc.php | 47 + BSF/plugins/admin_multi_view/main.inc.php | 42 + BSF/plugins/c13y_upgrade/index.php | 30 + BSF/plugins/c13y_upgrade/initialize.inc.php | 142 + BSF/plugins/c13y_upgrade/language/en_UK/index.php | 30 + .../c13y_upgrade/language/en_UK/plugin.lang.php | 32 + BSF/plugins/c13y_upgrade/language/es_ES/index.php | 30 + .../c13y_upgrade/language/es_ES/plugin.lang.php | 32 + BSF/plugins/c13y_upgrade/language/fr_FR/index.php | 30 + .../c13y_upgrade/language/fr_FR/plugin.lang.php | 32 + BSF/plugins/c13y_upgrade/language/index.php | 30 + BSF/plugins/c13y_upgrade/main.inc.php | 46 + BSF/plugins/event_tracer/event_list.php | 90 + BSF/plugins/event_tracer/event_list.tpl | 17 + BSF/plugins/event_tracer/index.php | 30 + BSF/plugins/event_tracer/main.inc.php | 137 + BSF/plugins/event_tracer/maintain.inc.php | 9 + BSF/plugins/event_tracer/tracer_admin.php | 31 + BSF/plugins/event_tracer/tracer_admin.tpl | 29 + BSF/plugins/extended_description/index.php | 30 + BSF/plugins/extended_description/main.inc.php | 69 + BSF/plugins/hello_world/index.php | 30 + BSF/plugins/hello_world/main.inc.php | 56 + BSF/plugins/index.php | 30 + BSF/plugins/language_switch/icons/cz_CZ.gif | Bin 0 -> 903 bytes BSF/plugins/language_switch/icons/de_DE.gif | Bin 0 -> 899 bytes BSF/plugins/language_switch/icons/en_UK.gif | Bin 0 -> 1161 bytes BSF/plugins/language_switch/icons/es_AR.gif | Bin 0 -> 1166 bytes BSF/plugins/language_switch/icons/es_ES.gif | Bin 0 -> 1025 bytes BSF/plugins/language_switch/icons/fr_FR.gif | Bin 0 -> 236 bytes BSF/plugins/language_switch/icons/hu_HU.gif | Bin 0 -> 1033 bytes BSF/plugins/language_switch/icons/index.php | 30 + BSF/plugins/language_switch/icons/it_IT.gif | Bin 0 -> 959 bytes BSF/plugins/language_switch/icons/nl_NL.gif | Bin 0 -> 103 bytes BSF/plugins/language_switch/icons/pl_PL.gif | Bin 0 -> 156 bytes BSF/plugins/language_switch/index.php | 30 + .../language_switch/language_switch.inc.php | 92 + BSF/plugins/language_switch/main.inc.php | 36 + BSF/popuphelp.php | 80 + BSF/profile.php | 271 + BSF/qsearch.php | 74 + BSF/random.php | 63 + BSF/register.php | 91 + BSF/search.php | 226 + BSF/search_rules.php | 243 + BSF/tags.php | 101 + BSF/template-common/csshover.htc | 120 + BSF/template-common/default-layout.css | 82 + BSF/template-common/favicon.ico | Bin 0 -> 1150 bytes BSF/template-common/index.php | 30 + BSF/template-common/inputfix.htc | 42 + BSF/template-common/jquery.accordion.js | 311 ++ BSF/template-common/jquery.accordion.min.js | 14 + BSF/template-common/jquery.accordion.pack.js | 15 + BSF/template-common/lib/chili-1.7.pack.js | 1 + BSF/template-common/lib/jquery.dimensions.js | 116 + BSF/template-common/lib/jquery.easing.js | 102 + BSF/template-common/lib/jquery.js | 11 + BSF/template-common/pngfix.js | 37 + BSF/template-common/scripts.js | 74 + BSF/template-common/tooltipfix.htc | 31 + BSF/template-extension/index.php | 30 + BSF/template-extension/yoga/index.php | 30 + BSF/template-extension/yoga/local/README | 19 + BSF/template-extension/yoga/local/index.php | 30 + BSF/template/index.php | 30 + BSF/template/yoga/about.tpl | 19 + BSF/template/yoga/admin.tpl | 103 + BSF/template/yoga/admin/advanced_feature.tpl | 13 + BSF/template/yoga/admin/cat_list.tpl | 65 + BSF/template/yoga/admin/cat_modify.tpl | 229 + BSF/template/yoga/admin/cat_move.tpl | 38 + BSF/template/yoga/admin/cat_options.tpl | 16 + BSF/template/yoga/admin/cat_perm.tpl | 68 + BSF/template/yoga/admin/check_integrity.tpl | 84 + BSF/template/yoga/admin/comments.tpl | 33 + BSF/template/yoga/admin/configuration.tpl | 179 + BSF/template/yoga/admin/default-layout.css | 245 + BSF/template/yoga/admin/double_select.tpl | 20 + BSF/template/yoga/admin/element_set_global.tpl | 190 + BSF/template/yoga/admin/element_set_unit.tpl | 93 + BSF/template/yoga/admin/group_list.tpl | 46 + BSF/template/yoga/admin/group_perm.tpl | 8 + BSF/template/yoga/admin/history.tpl | 151 + BSF/template/yoga/admin/index.php | 30 + BSF/template/yoga/admin/intro.tpl | 46 + BSF/template/yoga/admin/maintenance.tpl | 25 + BSF/template/yoga/admin/notification_by_mail.tpl | 124 + BSF/template/yoga/admin/permalinks.tpl | 70 + BSF/template/yoga/admin/picture_modify.tpl | 190 + BSF/template/yoga/admin/plugins_list.tpl | 51 + BSF/template/yoga/admin/plugins_new.tpl | 37 + BSF/template/yoga/admin/plugins_update.tpl | 71 + BSF/template/yoga/admin/profile.tpl | 6 + BSF/template/yoga/admin/rating.tpl | 64 + BSF/template/yoga/admin/site_manager.tpl | 73 + BSF/template/yoga/admin/site_update.tpl | 109 + BSF/template/yoga/admin/stats.tpl | 38 + BSF/template/yoga/admin/tabsheet.tpl | 8 + BSF/template/yoga/admin/tags.tpl | 54 + BSF/template/yoga/admin/thumbnail.tpl | 123 + BSF/template/yoga/admin/upload.tpl | 53 + BSF/template/yoga/admin/user_list.tpl | 312 ++ BSF/template/yoga/admin/user_perm.tpl | 23 + BSF/template/yoga/admin/ws_checker.tpl | 218 + BSF/template/yoga/comments.tpl | 99 + BSF/template/yoga/content.css | 241 + BSF/template/yoga/default-colors.css | 112 + BSF/template/yoga/default-layout.css | 270 + BSF/template/yoga/fix-ie5-ie6.css | 23 + BSF/template/yoga/fix-ie7.css | 22 + BSF/template/yoga/fix-khtml.css | 20 + BSF/template/yoga/footer.tpl | 32 + BSF/template/yoga/header.tpl | 84 + BSF/template/yoga/icon/add_tag.png | Bin 0 -> 59 bytes BSF/template/yoga/icon/admin/errors.png | Bin 0 -> 3249 bytes BSF/template/yoga/icon/admin/index.php | 30 + BSF/template/yoga/icon/admin/infos.png | Bin 0 -> 2250 bytes BSF/template/yoga/icon/admin/plugin_active.gif | Bin 0 -> 108 bytes BSF/template/yoga/icon/admin/plugin_inactive.gif | Bin 0 -> 107 bytes BSF/template/yoga/icon/caddie_add.png | Bin 0 -> 1186 bytes BSF/template/yoga/icon/calendar.png | Bin 0 -> 844 bytes BSF/template/yoga/icon/calendar_created.png | Bin 0 -> 1230 bytes BSF/template/yoga/icon/category_children.png | Bin 0 -> 1554 bytes BSF/template/yoga/icon/category_delete.png | Bin 0 -> 1752 bytes BSF/template/yoga/icon/category_edit.png | Bin 0 -> 1606 bytes BSF/template/yoga/icon/category_elements.png | Bin 0 -> 1681 bytes BSF/template/yoga/icon/category_jump-to.png | Bin 0 -> 1604 bytes BSF/template/yoga/icon/category_permissions.png | Bin 0 -> 1839 bytes .../yoga/icon/category_representant_random.png | Bin 0 -> 3171 bytes BSF/template/yoga/icon/check.png | Bin 0 -> 367 bytes BSF/template/yoga/icon/dec_period.png | Bin 0 -> 1230 bytes BSF/template/yoga/icon/dec_period_unactive.png | Bin 0 -> 1042 bytes BSF/template/yoga/icon/del_favorite.png | Bin 0 -> 1424 bytes BSF/template/yoga/icon/delete.png | Bin 0 -> 778 bytes BSF/template/yoga/icon/edit_s.png | Bin 0 -> 585 bytes BSF/template/yoga/icon/exit.png | Bin 0 -> 1432 bytes BSF/template/yoga/icon/favorite.png | Bin 0 -> 1457 bytes BSF/template/yoga/icon/first.png | Bin 0 -> 1645 bytes BSF/template/yoga/icon/first_unactive.png | Bin 0 -> 1573 bytes BSF/template/yoga/icon/flat.png | Bin 0 -> 754 bytes BSF/template/yoga/icon/help.png | Bin 0 -> 1994 bytes BSF/template/yoga/icon/home.png | Bin 0 -> 1591 bytes BSF/template/yoga/icon/inc_period.png | Bin 0 -> 1209 bytes BSF/template/yoga/icon/inc_period_unactive.png | Bin 0 -> 1039 bytes BSF/template/yoga/icon/index.php | 30 + BSF/template/yoga/icon/last.png | Bin 0 -> 1642 bytes BSF/template/yoga/icon/last_unactive.png | Bin 0 -> 1556 bytes BSF/template/yoga/icon/left.png | Bin 0 -> 1644 bytes BSF/template/yoga/icon/left_unactive.png | Bin 0 -> 1574 bytes BSF/template/yoga/icon/lost_password.png | Bin 0 -> 1717 bytes BSF/template/yoga/icon/metadata.png | Bin 0 -> 1520 bytes BSF/template/yoga/icon/mimetypes/avi.png | Bin 0 -> 4284 bytes BSF/template/yoga/icon/mimetypes/index.php | 30 + BSF/template/yoga/icon/mimetypes/mp3.png | Bin 0 -> 3902 bytes BSF/template/yoga/icon/mimetypes/mpg.png | Bin 0 -> 4271 bytes BSF/template/yoga/icon/mimetypes/ogg.png | Bin 0 -> 4063 bytes BSF/template/yoga/icon/mimetypes/zip.png | Bin 0 -> 3721 bytes BSF/template/yoga/icon/normal_mode.png | Bin 0 -> 360 bytes BSF/template/yoga/icon/note.png | Bin 0 -> 1862 bytes BSF/template/yoga/icon/page_end.png | Bin 0 -> 536 bytes BSF/template/yoga/icon/page_top.png | Bin 0 -> 555 bytes BSF/template/yoga/icon/pause.png | Bin 0 -> 1597 bytes BSF/template/yoga/icon/permissions.png | Bin 0 -> 729 bytes BSF/template/yoga/icon/play.png | Bin 0 -> 1568 bytes BSF/template/yoga/icon/preferences.png | Bin 0 -> 1606 bytes BSF/template/yoga/icon/rating-stars.gif | Bin 0 -> 251 bytes BSF/template/yoga/icon/recent.png | Bin 0 -> 757 bytes BSF/template/yoga/icon/recent_by_child.png | Bin 0 -> 738 bytes BSF/template/yoga/icon/register.png | Bin 0 -> 1445 bytes BSF/template/yoga/icon/remove_s.png | Bin 0 -> 451 bytes BSF/template/yoga/icon/representative.png | Bin 0 -> 1556 bytes BSF/template/yoga/icon/right.png | Bin 0 -> 1661 bytes BSF/template/yoga/icon/right_unactive.png | Bin 0 -> 1556 bytes BSF/template/yoga/icon/save.png | Bin 0 -> 961 bytes BSF/template/yoga/icon/search_rules.png | Bin 0 -> 1509 bytes BSF/template/yoga/icon/start_filter.png | Bin 0 -> 1064 bytes BSF/template/yoga/icon/start_repeat.png | Bin 0 -> 1691 bytes BSF/template/yoga/icon/start_slideshow.png | Bin 0 -> 1344 bytes BSF/template/yoga/icon/stop_filter.png | Bin 0 -> 1083 bytes BSF/template/yoga/icon/stop_repeat.png | Bin 0 -> 1683 bytes BSF/template/yoga/icon/stop_slideshow.png | Bin 0 -> 1149 bytes BSF/template/yoga/icon/sync_metadata.png | Bin 0 -> 1797 bytes BSF/template/yoga/icon/toggle_is_default_group.png | Bin 0 -> 571 bytes BSF/template/yoga/icon/uncheck.png | Bin 0 -> 213 bytes BSF/template/yoga/icon/up.png | Bin 0 -> 1641 bytes BSF/template/yoga/icon/validate_s.png | Bin 0 -> 315 bytes BSF/template/yoga/icon/virt_category.png | Bin 0 -> 796 bytes BSF/template/yoga/identification.tpl | 71 + BSF/template/yoga/index.php | 30 + BSF/template/yoga/index.tpl | 119 + BSF/template/yoga/install.tpl | 255 + BSF/template/yoga/layout.css | 15 + BSF/template/yoga/mail/index.php | 30 + .../yoga/mail/text/html/admin/cat_group_info.tpl | 9 + BSF/template/yoga/mail/text/html/admin/index.php | 30 + .../mail/text/html/admin/notification_by_mail.tpl | 57 + BSF/template/yoga/mail/text/html/footer.tpl | 20 + .../yoga/mail/text/html/global-mail-css.tpl | 12 + BSF/template/yoga/mail/text/html/header.tpl | 19 + .../yoga/mail/text/html/images/footer-bg.png | Bin 0 -> 15656 bytes .../yoga/mail/text/html/images/header-bg.png | Bin 0 -> 30525 bytes BSF/template/yoga/mail/text/html/images/index.php | 30 + .../yoga/mail/text/html/images/mailbody-bg.png | Bin 0 -> 924 bytes BSF/template/yoga/mail/text/html/index.php | 30 + BSF/template/yoga/mail/text/index.php | 30 + .../yoga/mail/text/plain/admin/cat_group_info.tpl | 9 + BSF/template/yoga/mail/text/plain/admin/index.php | 30 + .../mail/text/plain/admin/notification_by_mail.tpl | 42 + BSF/template/yoga/mail/text/plain/footer.tpl | 4 + BSF/template/yoga/mail/text/plain/header.tpl | 4 + BSF/template/yoga/mail/text/plain/index.php | 30 + BSF/template/yoga/mainpage_categories.tpl | 27 + BSF/template/yoga/menubar.css | 149 + BSF/template/yoga/menubar.tpl | 165 + BSF/template/yoga/month_calendar.tpl | 70 + BSF/template/yoga/nbm.tpl | 31 + BSF/template/yoga/not-ie.css | 24 + BSF/template/yoga/notification.tpl | 15 + BSF/template/yoga/password.tpl | 54 + BSF/template/yoga/picture.css | 143 + BSF/template/yoga/picture.tpl | 230 + BSF/template/yoga/picture_content.tpl | 9 + BSF/template/yoga/picture_nav_buttons.tpl | 103 + BSF/template/yoga/popuphelp.tpl | 6 + BSF/template/yoga/print.css | 14 + BSF/template/yoga/profile.tpl | 22 + BSF/template/yoga/profile_content.tpl | 109 + BSF/template/yoga/rating.js | 90 + BSF/template/yoga/redirect.tpl | 3 + BSF/template/yoga/register.tpl | 69 + BSF/template/yoga/search.tpl | 126 + BSF/template/yoga/search_rules.tpl | 56 + BSF/template/yoga/slideshow.tpl | 23 + BSF/template/yoga/tags.tpl | 19 + .../yoga/theme/admin/images/bottom-left-bg.png | Bin 0 -> 22748 bytes .../yoga/theme/admin/images/content-bg.png | Bin 0 -> 170 bytes .../yoga/theme/admin/images/header_bottom.png | Bin 0 -> 190 bytes BSF/template/yoga/theme/admin/images/index.php | 54 + .../yoga/theme/admin/images/internal_onglet.png | Bin 0 -> 239 bytes .../yoga/theme/admin/images/list-hover.png | Bin 0 -> 273 bytes .../yoga/theme/admin/images/list-image.png | Bin 0 -> 279 bytes .../yoga/theme/admin/images/menubar-bg.jpg | Bin 0 -> 694 bytes .../yoga/theme/admin/images/menubar-bg.png | Bin 0 -> 165 bytes .../yoga/theme/admin/images/menubar-bottom.png | Bin 0 -> 275 bytes .../yoga/theme/admin/images/menubar-detail.png | Bin 0 -> 196 bytes .../yoga/theme/admin/images/menubar-top.png | Bin 0 -> 375 bytes .../yoga/theme/admin/images/onglet_actif.png | Bin 0 -> 1168 bytes .../theme/admin/images/onglet_actif_transp.png | Bin 0 -> 1456 bytes .../yoga/theme/admin/images/onglet_inactif.png | Bin 0 -> 1250 bytes .../theme/admin/images/onglet_inactif_transp.png | Bin 0 -> 1498 bytes .../admin/images/piwigo_logo_sombre_214x100.png | Bin 0 -> 12154 bytes .../yoga/theme/admin/images/pre-menubar-bg.png | Bin 0 -> 720 bytes .../yoga/theme/admin/images/tableh1_bg.png | Bin 0 -> 150 bytes .../yoga/theme/admin/images/tableh2_bg.png | Bin 0 -> 141 bytes .../yoga/theme/admin/images/top-left-bg.png | Bin 0 -> 54307 bytes BSF/template/yoga/theme/admin/index.php | 54 + BSF/template/yoga/theme/admin/mail-css.tpl | 19 + BSF/template/yoga/theme/admin/theme.css | 468 ++ BSF/template/yoga/theme/admin/themeconf.inc.php | 72 + BSF/template/yoga/theme/clear/index.php | 30 + BSF/template/yoga/theme/clear/mail-css.tpl | 13 + BSF/template/yoga/theme/clear/theme.css | 94 + BSF/template/yoga/theme/clear/themeconf.inc.php | 11 + BSF/template/yoga/theme/dark/images/index.php | 30 + BSF/template/yoga/theme/dark/images/tableh1_bg.png | Bin 0 -> 271 bytes BSF/template/yoga/theme/dark/images/tableh2_bg.png | Bin 0 -> 307 bytes BSF/template/yoga/theme/dark/index.php | 30 + BSF/template/yoga/theme/dark/mail-css.tpl | 13 + BSF/template/yoga/theme/dark/theme.css | 92 + BSF/template/yoga/theme/dark/themeconf.inc.php | 11 + BSF/template/yoga/theme/index.php | 30 + BSF/template/yoga/theme/p0w0/images/button-bg.png | Bin 0 -> 233 bytes BSF/template/yoga/theme/p0w0/images/index.php | 30 + BSF/template/yoga/theme/p0w0/index.php | 30 + BSF/template/yoga/theme/p0w0/mail-css.tpl | 12 + BSF/template/yoga/theme/p0w0/theme.css | 269 + BSF/template/yoga/theme/p0w0/themeconf.inc.php | 11 + BSF/template/yoga/theme/wipi/images/index.php | 30 + BSF/template/yoga/theme/wipi/images/tableh1_bg.png | Bin 0 -> 142 bytes BSF/template/yoga/theme/wipi/images/tableh2_bg.png | Bin 0 -> 141 bytes BSF/template/yoga/theme/wipi/index.php | 30 + BSF/template/yoga/theme/wipi/mail-css.tpl | 19 + BSF/template/yoga/theme/wipi/theme.css | 322 ++ BSF/template/yoga/theme/wipi/themeconf.inc.php | 16 + BSF/template/yoga/thumbnails-fix-ie5-ie6.css | 27 + BSF/template/yoga/thumbnails.css | 60 + BSF/template/yoga/thumbnails.tpl | 38 + BSF/template/yoga/upgrade.tpl | 44 + BSF/template/yoga/upload.tpl | 110 + BSF/tools/config_local.inc.php | 8 + BSF/tools/create_listing_file.php | 1696 ++++++ BSF/tools/create_listing_file_local.inc.php | 14 + BSF/tools/fill_history.pl | 336 ++ BSF/tools/index.php | 30 + BSF/tools/local-layout.css | 10 + BSF/tools/metadata.php | 97 + BSF/tools/prototype.js | 3277 +++++++++++ BSF/tools/pwg_rel_create.sh | 61 + BSF/tools/release_creation.readme | 50 + BSF/tools/ws.htm | 402 ++ BSF/upgrade.php | 316 ++ BSF/upgrade_feed.php | 93 + BSF/upload.php | 438 ++ BSF/ws.php | 235 + 780 files changed, 94595 insertions(+) create mode 100644 BSF/about.php create mode 100644 BSF/action.php create mode 100644 BSF/admin.php create mode 100644 BSF/admin/advanced_feature.php create mode 100644 BSF/admin/cat_list.php create mode 100644 BSF/admin/cat_modify.php create mode 100644 BSF/admin/cat_move.php create mode 100644 BSF/admin/cat_options.php create mode 100644 BSF/admin/cat_perm.php create mode 100644 BSF/admin/comments.php create mode 100644 BSF/admin/configuration.php create mode 100644 BSF/admin/element_set.php create mode 100644 BSF/admin/element_set_global.php create mode 100644 BSF/admin/element_set_unit.php create mode 100644 BSF/admin/group_list.php create mode 100644 BSF/admin/group_perm.php create mode 100644 BSF/admin/help.php create mode 100644 BSF/admin/history.php create mode 100644 BSF/admin/images/index.php create mode 100644 BSF/admin/include/c13y_internal.class.php create mode 100644 BSF/admin/include/check_integrity.class.php create mode 100644 BSF/admin/include/functions.php create mode 100644 BSF/admin/include/functions_history.inc.php create mode 100644 BSF/admin/include/functions_metadata.php create mode 100644 BSF/admin/include/functions_notification_by_mail.inc.php create mode 100644 BSF/admin/include/functions_permalinks.php create mode 100644 BSF/admin/include/functions_plugins.inc.php create mode 100644 BSF/admin/include/functions_upgrade.php create mode 100644 BSF/admin/include/functions_waiting.inc.php create mode 100644 BSF/admin/include/index.php create mode 100644 BSF/admin/include/pclzip.lib.php create mode 100644 BSF/admin/include/plugins.class.php create mode 100644 BSF/admin/include/tabsheet.class.php create mode 100644 BSF/admin/index.php create mode 100644 BSF/admin/intro.php create mode 100644 BSF/admin/maintenance.php create mode 100644 BSF/admin/notification_by_mail.php create mode 100644 BSF/admin/permalinks.php create mode 100644 BSF/admin/picture_modify.php create mode 100644 BSF/admin/plugin.php create mode 100644 BSF/admin/plugins_list.php create mode 100644 BSF/admin/plugins_new.php create mode 100644 BSF/admin/plugins_update.php create mode 100644 BSF/admin/profile.php create mode 100644 BSF/admin/rating.php create mode 100644 BSF/admin/site_manager.php create mode 100644 BSF/admin/site_reader_local.php create mode 100644 BSF/admin/site_reader_remote.php create mode 100644 BSF/admin/site_update.php create mode 100644 BSF/admin/stats.php create mode 100644 BSF/admin/tags.php create mode 100644 BSF/admin/thumbnail.php create mode 100644 BSF/admin/upload.php create mode 100644 BSF/admin/user_list.php create mode 100644 BSF/admin/user_perm.php create mode 100644 BSF/admin/ws_checker.php create mode 100644 BSF/category.php create mode 100644 BSF/comments.php create mode 100644 BSF/doc/COPYING create mode 100644 BSF/doc/ChangeLog create mode 100644 BSF/doc/README_en.txt create mode 100644 BSF/doc/README_fr.txt create mode 100644 BSF/doc/index.php create mode 100644 BSF/feed.php create mode 100644 BSF/galleries/.cvsignore create mode 100644 BSF/galleries/index.php create mode 100644 BSF/identification.php create mode 100644 BSF/include/calendar_base.class.php create mode 100644 BSF/include/calendar_monthly.class.php create mode 100644 BSF/include/calendar_weekly.class.php create mode 100644 BSF/include/category_cats.inc.php create mode 100644 BSF/include/category_default.inc.php create mode 100644 BSF/include/class_smtp_mail.inc.php create mode 100644 BSF/include/common.inc.php create mode 100644 BSF/include/config_default.inc.php create mode 100644 BSF/include/constants.php create mode 100644 BSF/include/feedcreator.class.php create mode 100644 BSF/include/filter.inc.php create mode 100644 BSF/include/functions.inc.php create mode 100644 BSF/include/functions_calendar.inc.php create mode 100644 BSF/include/functions_category.inc.php create mode 100644 BSF/include/functions_comment.inc.php create mode 100644 BSF/include/functions_cookie.inc.php create mode 100644 BSF/include/functions_filter.inc.php create mode 100644 BSF/include/functions_group.inc.php create mode 100644 BSF/include/functions_html.inc.php create mode 100644 BSF/include/functions_mail.inc.php create mode 100644 BSF/include/functions_metadata.inc.php create mode 100644 BSF/include/functions_notification.inc.php create mode 100644 BSF/include/functions_picture.inc.php create mode 100644 BSF/include/functions_plugins.inc.php create mode 100644 BSF/include/functions_rate.inc.php create mode 100644 BSF/include/functions_search.inc.php create mode 100644 BSF/include/functions_session.inc.php create mode 100644 BSF/include/functions_tag.inc.php create mode 100644 BSF/include/functions_url.inc.php create mode 100644 BSF/include/functions_user.inc.php create mode 100644 BSF/include/functions_xml.inc.php create mode 100644 BSF/include/index.php create mode 100644 BSF/include/menubar.inc.php create mode 100644 BSF/include/page_header.php create mode 100644 BSF/include/page_tail.php create mode 100644 BSF/include/php_compat/array_intersect_key.php create mode 100644 BSF/include/php_compat/file_put_contents.php create mode 100644 BSF/include/php_compat/hash_hmac.php create mode 100644 BSF/include/php_compat/index.php create mode 100644 BSF/include/php_compat/preg_last_error.php create mode 100644 BSF/include/picture_comment.inc.php create mode 100644 BSF/include/picture_metadata.inc.php create mode 100644 BSF/include/picture_rate.inc.php create mode 100644 BSF/include/section_init.inc.php create mode 100644 BSF/include/smarty/COPYING.lib create mode 100644 BSF/include/smarty/NEWS create mode 100644 BSF/include/smarty/README create mode 100644 BSF/include/smarty/libs/Config_File.class.php create mode 100644 BSF/include/smarty/libs/Smarty.class.php create mode 100644 BSF/include/smarty/libs/Smarty_Compiler.class.php create mode 100644 BSF/include/smarty/libs/debug.tpl create mode 100644 BSF/include/smarty/libs/internals/core.assemble_plugin_filepath.php create mode 100644 BSF/include/smarty/libs/internals/core.assign_smarty_interface.php create mode 100644 BSF/include/smarty/libs/internals/core.create_dir_structure.php create mode 100644 BSF/include/smarty/libs/internals/core.display_debug_console.php create mode 100644 BSF/include/smarty/libs/internals/core.get_include_path.php create mode 100644 BSF/include/smarty/libs/internals/core.get_microtime.php create mode 100644 BSF/include/smarty/libs/internals/core.get_php_resource.php create mode 100644 BSF/include/smarty/libs/internals/core.is_secure.php create mode 100644 BSF/include/smarty/libs/internals/core.is_trusted.php create mode 100644 BSF/include/smarty/libs/internals/core.load_plugins.php create mode 100644 BSF/include/smarty/libs/internals/core.load_resource_plugin.php create mode 100644 BSF/include/smarty/libs/internals/core.process_cached_inserts.php create mode 100644 BSF/include/smarty/libs/internals/core.process_compiled_include.php create mode 100644 BSF/include/smarty/libs/internals/core.read_cache_file.php create mode 100644 BSF/include/smarty/libs/internals/core.rm_auto.php create mode 100644 BSF/include/smarty/libs/internals/core.rmdir.php create mode 100644 BSF/include/smarty/libs/internals/core.run_insert_handler.php create mode 100644 BSF/include/smarty/libs/internals/core.smarty_include_php.php create mode 100644 BSF/include/smarty/libs/internals/core.write_cache_file.php create mode 100644 BSF/include/smarty/libs/internals/core.write_compiled_include.php create mode 100644 BSF/include/smarty/libs/internals/core.write_compiled_resource.php create mode 100644 BSF/include/smarty/libs/internals/core.write_file.php create mode 100644 BSF/include/smarty/libs/plugins/block.textformat.php create mode 100644 BSF/include/smarty/libs/plugins/compiler.assign.php create mode 100644 BSF/include/smarty/libs/plugins/function.assign_debug_info.php create mode 100644 BSF/include/smarty/libs/plugins/function.config_load.php create mode 100644 BSF/include/smarty/libs/plugins/function.counter.php create mode 100644 BSF/include/smarty/libs/plugins/function.cycle.php create mode 100644 BSF/include/smarty/libs/plugins/function.debug.php create mode 100644 BSF/include/smarty/libs/plugins/function.eval.php create mode 100644 BSF/include/smarty/libs/plugins/function.fetch.php create mode 100644 BSF/include/smarty/libs/plugins/function.html_checkboxes.php create mode 100644 BSF/include/smarty/libs/plugins/function.html_image.php create mode 100644 BSF/include/smarty/libs/plugins/function.html_options.php create mode 100644 BSF/include/smarty/libs/plugins/function.html_radios.php create mode 100644 BSF/include/smarty/libs/plugins/function.html_select_date.php create mode 100644 BSF/include/smarty/libs/plugins/function.html_select_time.php create mode 100644 BSF/include/smarty/libs/plugins/function.html_table.php create mode 100644 BSF/include/smarty/libs/plugins/function.mailto.php create mode 100644 BSF/include/smarty/libs/plugins/function.math.php create mode 100644 BSF/include/smarty/libs/plugins/function.popup.php create mode 100644 BSF/include/smarty/libs/plugins/function.popup_init.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.capitalize.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.cat.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.count_characters.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.count_paragraphs.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.count_sentences.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.count_words.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.date_format.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.debug_print_var.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.default.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.escape.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.indent.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.lower.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.nl2br.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.regex_replace.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.replace.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.spacify.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.string_format.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.strip.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.strip_tags.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.truncate.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.upper.php create mode 100644 BSF/include/smarty/libs/plugins/modifier.wordwrap.php create mode 100644 BSF/include/smarty/libs/plugins/outputfilter.trimwhitespace.php create mode 100644 BSF/include/smarty/libs/plugins/shared.escape_special_chars.php create mode 100644 BSF/include/smarty/libs/plugins/shared.make_timestamp.php create mode 100644 BSF/include/template.class.php create mode 100644 BSF/include/upload.class.php create mode 100644 BSF/include/user.inc.php create mode 100644 BSF/include/ws_core.inc.php create mode 100644 BSF/include/ws_functions.inc.php create mode 100644 BSF/include/ws_protocols/index.php create mode 100644 BSF/include/ws_protocols/json_encoder.php create mode 100644 BSF/include/ws_protocols/php_encoder.php create mode 100644 BSF/include/ws_protocols/rest_encoder.php create mode 100644 BSF/include/ws_protocols/rest_handler.php create mode 100644 BSF/include/ws_protocols/xmlrpc_encoder.php create mode 100644 BSF/index.php create mode 100644 BSF/install.php create mode 100644 BSF/install/config.sql create mode 100644 BSF/install/db/1-database.php create mode 100644 BSF/install/db/10-database.php create mode 100644 BSF/install/db/11-database.php create mode 100644 BSF/install/db/12-database.php create mode 100644 BSF/install/db/13-database.php create mode 100644 BSF/install/db/14-database.php create mode 100644 BSF/install/db/15-database.php create mode 100644 BSF/install/db/16-database.php create mode 100644 BSF/install/db/17-database.php create mode 100644 BSF/install/db/18-database.php create mode 100644 BSF/install/db/19-database.php create mode 100644 BSF/install/db/2-database.php create mode 100644 BSF/install/db/20-database.php create mode 100644 BSF/install/db/21-database.php create mode 100644 BSF/install/db/22-database.php create mode 100644 BSF/install/db/23-database.php create mode 100644 BSF/install/db/24-database.php create mode 100644 BSF/install/db/25-database.php create mode 100644 BSF/install/db/26-database.php create mode 100644 BSF/install/db/27-database.php create mode 100644 BSF/install/db/28-database.php create mode 100644 BSF/install/db/29-database.php create mode 100644 BSF/install/db/3-database.php create mode 100644 BSF/install/db/30-database.php create mode 100644 BSF/install/db/31-database.php create mode 100644 BSF/install/db/32-database.php create mode 100644 BSF/install/db/33-database.php create mode 100644 BSF/install/db/34-database.php create mode 100644 BSF/install/db/35-database.php create mode 100644 BSF/install/db/36-database.php create mode 100644 BSF/install/db/37-database.php create mode 100644 BSF/install/db/38-database.php create mode 100644 BSF/install/db/39-database.php create mode 100644 BSF/install/db/4-database.php create mode 100644 BSF/install/db/40-database.php create mode 100644 BSF/install/db/41-database.php create mode 100644 BSF/install/db/42-database.php create mode 100644 BSF/install/db/43-database.php create mode 100644 BSF/install/db/44-database.php create mode 100644 BSF/install/db/45-database.php create mode 100644 BSF/install/db/46-database.php create mode 100644 BSF/install/db/47-database.php create mode 100644 BSF/install/db/48-database.php create mode 100644 BSF/install/db/49-database.php create mode 100644 BSF/install/db/5-database.php create mode 100644 BSF/install/db/50-database.php create mode 100644 BSF/install/db/51-database.php create mode 100644 BSF/install/db/52-database.php create mode 100644 BSF/install/db/53-database.php create mode 100644 BSF/install/db/54-database.php create mode 100644 BSF/install/db/55-database.php create mode 100644 BSF/install/db/56-database.php create mode 100644 BSF/install/db/57-database.php create mode 100644 BSF/install/db/58-database.php create mode 100644 BSF/install/db/59-database.php create mode 100644 BSF/install/db/6-database.php create mode 100644 BSF/install/db/60-database.php create mode 100644 BSF/install/db/61-database.php create mode 100644 BSF/install/db/62-database.php create mode 100644 BSF/install/db/63-database.php create mode 100644 BSF/install/db/64-database.php create mode 100644 BSF/install/db/65-database.php create mode 100644 BSF/install/db/66-database.php create mode 100644 BSF/install/db/67-database.php create mode 100644 BSF/install/db/68-database.php create mode 100644 BSF/install/db/69-database.php create mode 100644 BSF/install/db/7-database.php create mode 100644 BSF/install/db/70-database.php create mode 100644 BSF/install/db/71-database.php create mode 100644 BSF/install/db/8-database.php create mode 100644 BSF/install/db/9-database.php create mode 100644 BSF/install/db/index.php create mode 100644 BSF/install/index.php create mode 100644 BSF/install/piwigo_structure.sql create mode 100644 BSF/install/upgrade_1.3.0.php create mode 100644 BSF/install/upgrade_1.3.1.php create mode 100644 BSF/install/upgrade_1.4.0.php create mode 100644 BSF/install/upgrade_1.5.0.php create mode 100644 BSF/install/upgrade_1.6.0.php create mode 100644 BSF/install/upgrade_1.6.2.php create mode 100644 BSF/language/en_UK/about.html create mode 100644 BSF/language/en_UK/admin.lang.php create mode 100644 BSF/language/en_UK/common.lang.php create mode 100644 BSF/language/en_UK/help.html create mode 100644 BSF/language/en_UK/help/advanced_feature.html create mode 100644 BSF/language/en_UK/help/cat_modify.html create mode 100644 BSF/language/en_UK/help/cat_move.html create mode 100644 BSF/language/en_UK/help/cat_options.html create mode 100644 BSF/language/en_UK/help/cat_perm.html create mode 100644 BSF/language/en_UK/help/configuration.html create mode 100644 BSF/language/en_UK/help/group_list.html create mode 100644 BSF/language/en_UK/help/history.html create mode 100644 BSF/language/en_UK/help/index.php create mode 100644 BSF/language/en_UK/help/maintenance.html create mode 100644 BSF/language/en_UK/help/notification_by_mail.html create mode 100644 BSF/language/en_UK/help/permalinks.html create mode 100644 BSF/language/en_UK/help/search.html create mode 100644 BSF/language/en_UK/help/site_manager.html create mode 100644 BSF/language/en_UK/help/synchronize.html create mode 100644 BSF/language/en_UK/help/thumbnail.html create mode 100644 BSF/language/en_UK/help/user_list.html create mode 100644 BSF/language/en_UK/help/web_service.html create mode 100644 BSF/language/en_UK/index.php create mode 100644 BSF/language/en_UK/install.lang.php create mode 100644 BSF/language/en_UK/iso.txt create mode 100644 BSF/language/es_ES/about.html create mode 100644 BSF/language/es_ES/admin.lang.php create mode 100644 BSF/language/es_ES/common.lang.php create mode 100644 BSF/language/es_ES/help.html create mode 100644 BSF/language/es_ES/help/advanced_feature.html create mode 100644 BSF/language/es_ES/help/cat_modify.html create mode 100644 BSF/language/es_ES/help/cat_move.html create mode 100644 BSF/language/es_ES/help/cat_options.html create mode 100644 BSF/language/es_ES/help/cat_perm.html create mode 100644 BSF/language/es_ES/help/configuration.html create mode 100644 BSF/language/es_ES/help/group_list.html create mode 100644 BSF/language/es_ES/help/history.html create mode 100644 BSF/language/es_ES/help/index.php create mode 100644 BSF/language/es_ES/help/maintenance.html create mode 100644 BSF/language/es_ES/help/notification_by_mail.html create mode 100644 BSF/language/es_ES/help/permalinks.html create mode 100644 BSF/language/es_ES/help/search.html create mode 100644 BSF/language/es_ES/help/site_manager.html create mode 100644 BSF/language/es_ES/help/synchronize.html create mode 100644 BSF/language/es_ES/help/thumbnail.html create mode 100644 BSF/language/es_ES/help/user_list.html create mode 100644 BSF/language/es_ES/help/web_service.html create mode 100644 BSF/language/es_ES/index.php create mode 100644 BSF/language/es_ES/install.lang.php create mode 100644 BSF/language/es_ES/iso.txt create mode 100644 BSF/language/fr_FR/about.html create mode 100644 BSF/language/fr_FR/admin.lang.php create mode 100644 BSF/language/fr_FR/common.lang.php create mode 100644 BSF/language/fr_FR/help.html create mode 100644 BSF/language/fr_FR/help/advanced_feature.html create mode 100644 BSF/language/fr_FR/help/cat_modify.html create mode 100644 BSF/language/fr_FR/help/cat_move.html create mode 100644 BSF/language/fr_FR/help/cat_options.html create mode 100644 BSF/language/fr_FR/help/cat_perm.html create mode 100644 BSF/language/fr_FR/help/configuration.html create mode 100644 BSF/language/fr_FR/help/group_list.html create mode 100644 BSF/language/fr_FR/help/history.html create mode 100644 BSF/language/fr_FR/help/index.php create mode 100644 BSF/language/fr_FR/help/maintenance.html create mode 100644 BSF/language/fr_FR/help/notification_by_mail.html create mode 100644 BSF/language/fr_FR/help/permalinks.html create mode 100644 BSF/language/fr_FR/help/search.html create mode 100644 BSF/language/fr_FR/help/site_manager.html create mode 100644 BSF/language/fr_FR/help/synchronize.html create mode 100644 BSF/language/fr_FR/help/thumbnail.html create mode 100644 BSF/language/fr_FR/help/user_list.html create mode 100644 BSF/language/fr_FR/help/web_service.html create mode 100644 BSF/language/fr_FR/index.php create mode 100644 BSF/language/fr_FR/install.lang.php create mode 100644 BSF/language/fr_FR/iso.txt create mode 100644 BSF/language/index.php create mode 100644 BSF/language/nl_NL/about.html create mode 100644 BSF/language/nl_NL/admin.lang.php create mode 100644 BSF/language/nl_NL/common.lang.php create mode 100644 BSF/language/nl_NL/help.html create mode 100644 BSF/language/nl_NL/help/advanced_feature.html create mode 100644 BSF/language/nl_NL/help/cat_modify.html create mode 100644 BSF/language/nl_NL/help/cat_move.html create mode 100644 BSF/language/nl_NL/help/cat_options.html create mode 100644 BSF/language/nl_NL/help/cat_perm.html create mode 100644 BSF/language/nl_NL/help/configuration.html create mode 100644 BSF/language/nl_NL/help/group_list.html create mode 100644 BSF/language/nl_NL/help/index.php create mode 100644 BSF/language/nl_NL/help/maintenance.html create mode 100644 BSF/language/nl_NL/help/notification_by_mail.html create mode 100644 BSF/language/nl_NL/help/permalinks.html create mode 100644 BSF/language/nl_NL/help/search.html create mode 100644 BSF/language/nl_NL/help/site_manager.html create mode 100644 BSF/language/nl_NL/help/synchronize.html create mode 100644 BSF/language/nl_NL/help/thumbnail.html create mode 100644 BSF/language/nl_NL/help/user_list.html create mode 100644 BSF/language/nl_NL/help/web_service.html create mode 100644 BSF/language/nl_NL/index.php create mode 100644 BSF/language/nl_NL/install.lang.php create mode 100644 BSF/language/nl_NL/iso.txt create mode 100644 BSF/nbm.php create mode 100644 BSF/notification.php create mode 100644 BSF/password.php create mode 100644 BSF/picture.php create mode 100644 BSF/plugins/LocalFilesEditor/admin.php create mode 100644 BSF/plugins/LocalFilesEditor/admin.tpl create mode 100644 BSF/plugins/LocalFilesEditor/editarea/edit_area_full.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/close.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/fullscreen.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/go_to_line.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/help.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/highlight.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/index.php create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/load.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/move.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/newdocument.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/opacity.png create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/processing.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/redo.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/reset_highlight.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/save.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/search.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/smooth_selection.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/spacer.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/statusbar_resize.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/images/undo.gif create mode 100644 BSF/plugins/LocalFilesEditor/editarea/index.php create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/cs.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/de.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/dk.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/en.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/es.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/fr.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/hr.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/index.php create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/it.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/ja.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/mk.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/nl.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/pl.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/pt.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/ru.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/langs/sk.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/reg_syntax/css.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/reg_syntax/html.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/reg_syntax/index.php create mode 100644 BSF/plugins/LocalFilesEditor/editarea/reg_syntax/js.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/reg_syntax/php.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/reg_syntax/sql.js create mode 100644 BSF/plugins/LocalFilesEditor/editarea/reg_syntax/xml.js create mode 100644 BSF/plugins/LocalFilesEditor/functions.inc.php create mode 100644 BSF/plugins/LocalFilesEditor/index.php create mode 100644 BSF/plugins/LocalFilesEditor/language/en_UK/index.php create mode 100644 BSF/plugins/LocalFilesEditor/language/en_UK/plugin.lang.php create mode 100644 BSF/plugins/LocalFilesEditor/language/es_ES/index.php create mode 100644 BSF/plugins/LocalFilesEditor/language/es_ES/plugin.lang.php create mode 100644 BSF/plugins/LocalFilesEditor/language/fr_FR/index.php create mode 100644 BSF/plugins/LocalFilesEditor/language/fr_FR/plugin.lang.php create mode 100644 BSF/plugins/LocalFilesEditor/language/index.php create mode 100644 BSF/plugins/LocalFilesEditor/main.inc.php create mode 100644 BSF/plugins/LocalFilesEditor/show_default.php create mode 100644 BSF/plugins/LocalFilesEditor/show_default.tpl create mode 100644 BSF/plugins/add_index/admin/index.php create mode 100644 BSF/plugins/add_index/admin/main_page.php create mode 100644 BSF/plugins/add_index/admin/main_page.tpl create mode 100644 BSF/plugins/add_index/index.php create mode 100644 BSF/plugins/add_index/language/en_UK/help/advanced_feature.html create mode 100644 BSF/plugins/add_index/language/en_UK/help/index.php create mode 100644 BSF/plugins/add_index/language/en_UK/help/site_manager.html create mode 100644 BSF/plugins/add_index/language/en_UK/index.php create mode 100644 BSF/plugins/add_index/language/en_UK/plugin.lang.php create mode 100644 BSF/plugins/add_index/language/es_ES/help/advanced_feature.html create mode 100644 BSF/plugins/add_index/language/es_ES/help/index.php create mode 100644 BSF/plugins/add_index/language/es_ES/help/site_manager.html create mode 100644 BSF/plugins/add_index/language/es_ES/index.php create mode 100644 BSF/plugins/add_index/language/es_ES/plugin.lang.php create mode 100644 BSF/plugins/add_index/language/fr_FR/help/advanced_feature.html create mode 100644 BSF/plugins/add_index/language/fr_FR/help/index.php create mode 100644 BSF/plugins/add_index/language/fr_FR/help/site_manager.html create mode 100644 BSF/plugins/add_index/language/fr_FR/index.php create mode 100644 BSF/plugins/add_index/language/fr_FR/plugin.lang.php create mode 100644 BSF/plugins/add_index/language/index.php create mode 100644 BSF/plugins/add_index/main.admin.inc.php create mode 100644 BSF/plugins/add_index/main.base.inc.php create mode 100644 BSF/plugins/add_index/main.inc.php create mode 100644 BSF/plugins/add_index/main.normal.inc.php create mode 100644 BSF/plugins/admin_advices/admin_advices.tpl create mode 100644 BSF/plugins/admin_advices/default-layout.css create mode 100644 BSF/plugins/admin_advices/en_UK/index.php create mode 100644 BSF/plugins/admin_advices/en_UK/lang.adv.php create mode 100644 BSF/plugins/admin_advices/fr_FR/index.php create mode 100644 BSF/plugins/admin_advices/fr_FR/lang.adv.php create mode 100644 BSF/plugins/admin_advices/index.php create mode 100644 BSF/plugins/admin_advices/main.inc.php create mode 100644 BSF/plugins/admin_multi_view/controller.php create mode 100644 BSF/plugins/admin_multi_view/index.php create mode 100644 BSF/plugins/admin_multi_view/is_admin.inc.php create mode 100644 BSF/plugins/admin_multi_view/main.inc.php create mode 100644 BSF/plugins/c13y_upgrade/index.php create mode 100644 BSF/plugins/c13y_upgrade/initialize.inc.php create mode 100644 BSF/plugins/c13y_upgrade/language/en_UK/index.php create mode 100644 BSF/plugins/c13y_upgrade/language/en_UK/plugin.lang.php create mode 100644 BSF/plugins/c13y_upgrade/language/es_ES/index.php create mode 100644 BSF/plugins/c13y_upgrade/language/es_ES/plugin.lang.php create mode 100644 BSF/plugins/c13y_upgrade/language/fr_FR/index.php create mode 100644 BSF/plugins/c13y_upgrade/language/fr_FR/plugin.lang.php create mode 100644 BSF/plugins/c13y_upgrade/language/index.php create mode 100644 BSF/plugins/c13y_upgrade/main.inc.php create mode 100644 BSF/plugins/event_tracer/event_list.php create mode 100644 BSF/plugins/event_tracer/event_list.tpl create mode 100644 BSF/plugins/event_tracer/index.php create mode 100644 BSF/plugins/event_tracer/main.inc.php create mode 100644 BSF/plugins/event_tracer/maintain.inc.php create mode 100644 BSF/plugins/event_tracer/tracer_admin.php create mode 100644 BSF/plugins/event_tracer/tracer_admin.tpl create mode 100644 BSF/plugins/extended_description/index.php create mode 100644 BSF/plugins/extended_description/main.inc.php create mode 100644 BSF/plugins/hello_world/index.php create mode 100644 BSF/plugins/hello_world/main.inc.php create mode 100644 BSF/plugins/index.php create mode 100644 BSF/plugins/language_switch/icons/cz_CZ.gif create mode 100644 BSF/plugins/language_switch/icons/de_DE.gif create mode 100644 BSF/plugins/language_switch/icons/en_UK.gif create mode 100644 BSF/plugins/language_switch/icons/es_AR.gif create mode 100644 BSF/plugins/language_switch/icons/es_ES.gif create mode 100644 BSF/plugins/language_switch/icons/fr_FR.gif create mode 100644 BSF/plugins/language_switch/icons/hu_HU.gif create mode 100644 BSF/plugins/language_switch/icons/index.php create mode 100644 BSF/plugins/language_switch/icons/it_IT.gif create mode 100644 BSF/plugins/language_switch/icons/nl_NL.gif create mode 100644 BSF/plugins/language_switch/icons/pl_PL.gif create mode 100644 BSF/plugins/language_switch/index.php create mode 100644 BSF/plugins/language_switch/language_switch.inc.php create mode 100644 BSF/plugins/language_switch/main.inc.php create mode 100644 BSF/popuphelp.php create mode 100644 BSF/profile.php create mode 100644 BSF/qsearch.php create mode 100644 BSF/random.php create mode 100644 BSF/register.php create mode 100644 BSF/search.php create mode 100644 BSF/search_rules.php create mode 100644 BSF/tags.php create mode 100644 BSF/template-common/csshover.htc create mode 100644 BSF/template-common/default-layout.css create mode 100644 BSF/template-common/favicon.ico create mode 100644 BSF/template-common/index.php create mode 100644 BSF/template-common/inputfix.htc create mode 100644 BSF/template-common/jquery.accordion.js create mode 100644 BSF/template-common/jquery.accordion.min.js create mode 100644 BSF/template-common/jquery.accordion.pack.js create mode 100644 BSF/template-common/lib/chili-1.7.pack.js create mode 100644 BSF/template-common/lib/jquery.dimensions.js create mode 100644 BSF/template-common/lib/jquery.easing.js create mode 100644 BSF/template-common/lib/jquery.js create mode 100644 BSF/template-common/pngfix.js create mode 100644 BSF/template-common/scripts.js create mode 100644 BSF/template-common/tooltipfix.htc create mode 100644 BSF/template-extension/index.php create mode 100644 BSF/template-extension/yoga/index.php create mode 100644 BSF/template-extension/yoga/local/README create mode 100644 BSF/template-extension/yoga/local/index.php create mode 100644 BSF/template/index.php create mode 100644 BSF/template/yoga/about.tpl create mode 100644 BSF/template/yoga/admin.tpl create mode 100644 BSF/template/yoga/admin/advanced_feature.tpl create mode 100644 BSF/template/yoga/admin/cat_list.tpl create mode 100644 BSF/template/yoga/admin/cat_modify.tpl create mode 100644 BSF/template/yoga/admin/cat_move.tpl create mode 100644 BSF/template/yoga/admin/cat_options.tpl create mode 100644 BSF/template/yoga/admin/cat_perm.tpl create mode 100644 BSF/template/yoga/admin/check_integrity.tpl create mode 100644 BSF/template/yoga/admin/comments.tpl create mode 100644 BSF/template/yoga/admin/configuration.tpl create mode 100644 BSF/template/yoga/admin/default-layout.css create mode 100644 BSF/template/yoga/admin/double_select.tpl create mode 100644 BSF/template/yoga/admin/element_set_global.tpl create mode 100644 BSF/template/yoga/admin/element_set_unit.tpl create mode 100644 BSF/template/yoga/admin/group_list.tpl create mode 100644 BSF/template/yoga/admin/group_perm.tpl create mode 100644 BSF/template/yoga/admin/history.tpl create mode 100644 BSF/template/yoga/admin/index.php create mode 100644 BSF/template/yoga/admin/intro.tpl create mode 100644 BSF/template/yoga/admin/maintenance.tpl create mode 100644 BSF/template/yoga/admin/notification_by_mail.tpl create mode 100644 BSF/template/yoga/admin/permalinks.tpl create mode 100644 BSF/template/yoga/admin/picture_modify.tpl create mode 100644 BSF/template/yoga/admin/plugins_list.tpl create mode 100644 BSF/template/yoga/admin/plugins_new.tpl create mode 100644 BSF/template/yoga/admin/plugins_update.tpl create mode 100644 BSF/template/yoga/admin/profile.tpl create mode 100644 BSF/template/yoga/admin/rating.tpl create mode 100644 BSF/template/yoga/admin/site_manager.tpl create mode 100644 BSF/template/yoga/admin/site_update.tpl create mode 100644 BSF/template/yoga/admin/stats.tpl create mode 100644 BSF/template/yoga/admin/tabsheet.tpl create mode 100644 BSF/template/yoga/admin/tags.tpl create mode 100644 BSF/template/yoga/admin/thumbnail.tpl create mode 100644 BSF/template/yoga/admin/upload.tpl create mode 100644 BSF/template/yoga/admin/user_list.tpl create mode 100644 BSF/template/yoga/admin/user_perm.tpl create mode 100644 BSF/template/yoga/admin/ws_checker.tpl create mode 100644 BSF/template/yoga/comments.tpl create mode 100644 BSF/template/yoga/content.css create mode 100644 BSF/template/yoga/default-colors.css create mode 100644 BSF/template/yoga/default-layout.css create mode 100644 BSF/template/yoga/fix-ie5-ie6.css create mode 100644 BSF/template/yoga/fix-ie7.css create mode 100644 BSF/template/yoga/fix-khtml.css create mode 100644 BSF/template/yoga/footer.tpl create mode 100644 BSF/template/yoga/header.tpl create mode 100644 BSF/template/yoga/icon/add_tag.png create mode 100644 BSF/template/yoga/icon/admin/errors.png create mode 100644 BSF/template/yoga/icon/admin/index.php create mode 100644 BSF/template/yoga/icon/admin/infos.png create mode 100644 BSF/template/yoga/icon/admin/plugin_active.gif create mode 100644 BSF/template/yoga/icon/admin/plugin_inactive.gif create mode 100644 BSF/template/yoga/icon/caddie_add.png create mode 100644 BSF/template/yoga/icon/calendar.png create mode 100644 BSF/template/yoga/icon/calendar_created.png create mode 100644 BSF/template/yoga/icon/category_children.png create mode 100644 BSF/template/yoga/icon/category_delete.png create mode 100644 BSF/template/yoga/icon/category_edit.png create mode 100644 BSF/template/yoga/icon/category_elements.png create mode 100644 BSF/template/yoga/icon/category_jump-to.png create mode 100644 BSF/template/yoga/icon/category_permissions.png create mode 100644 BSF/template/yoga/icon/category_representant_random.png create mode 100644 BSF/template/yoga/icon/check.png create mode 100644 BSF/template/yoga/icon/dec_period.png create mode 100644 BSF/template/yoga/icon/dec_period_unactive.png create mode 100644 BSF/template/yoga/icon/del_favorite.png create mode 100644 BSF/template/yoga/icon/delete.png create mode 100644 BSF/template/yoga/icon/edit_s.png create mode 100644 BSF/template/yoga/icon/exit.png create mode 100644 BSF/template/yoga/icon/favorite.png create mode 100644 BSF/template/yoga/icon/first.png create mode 100644 BSF/template/yoga/icon/first_unactive.png create mode 100644 BSF/template/yoga/icon/flat.png create mode 100644 BSF/template/yoga/icon/help.png create mode 100644 BSF/template/yoga/icon/home.png create mode 100644 BSF/template/yoga/icon/inc_period.png create mode 100644 BSF/template/yoga/icon/inc_period_unactive.png create mode 100644 BSF/template/yoga/icon/index.php create mode 100644 BSF/template/yoga/icon/last.png create mode 100644 BSF/template/yoga/icon/last_unactive.png create mode 100644 BSF/template/yoga/icon/left.png create mode 100644 BSF/template/yoga/icon/left_unactive.png create mode 100644 BSF/template/yoga/icon/lost_password.png create mode 100644 BSF/template/yoga/icon/metadata.png create mode 100644 BSF/template/yoga/icon/mimetypes/avi.png create mode 100644 BSF/template/yoga/icon/mimetypes/index.php create mode 100644 BSF/template/yoga/icon/mimetypes/mp3.png create mode 100644 BSF/template/yoga/icon/mimetypes/mpg.png create mode 100644 BSF/template/yoga/icon/mimetypes/ogg.png create mode 100644 BSF/template/yoga/icon/mimetypes/zip.png create mode 100644 BSF/template/yoga/icon/normal_mode.png create mode 100644 BSF/template/yoga/icon/note.png create mode 100644 BSF/template/yoga/icon/page_end.png create mode 100644 BSF/template/yoga/icon/page_top.png create mode 100644 BSF/template/yoga/icon/pause.png create mode 100644 BSF/template/yoga/icon/permissions.png create mode 100644 BSF/template/yoga/icon/play.png create mode 100644 BSF/template/yoga/icon/preferences.png create mode 100644 BSF/template/yoga/icon/rating-stars.gif create mode 100644 BSF/template/yoga/icon/recent.png create mode 100644 BSF/template/yoga/icon/recent_by_child.png create mode 100644 BSF/template/yoga/icon/register.png create mode 100644 BSF/template/yoga/icon/remove_s.png create mode 100644 BSF/template/yoga/icon/representative.png create mode 100644 BSF/template/yoga/icon/right.png create mode 100644 BSF/template/yoga/icon/right_unactive.png create mode 100644 BSF/template/yoga/icon/save.png create mode 100644 BSF/template/yoga/icon/search_rules.png create mode 100644 BSF/template/yoga/icon/start_filter.png create mode 100644 BSF/template/yoga/icon/start_repeat.png create mode 100644 BSF/template/yoga/icon/start_slideshow.png create mode 100644 BSF/template/yoga/icon/stop_filter.png create mode 100644 BSF/template/yoga/icon/stop_repeat.png create mode 100644 BSF/template/yoga/icon/stop_slideshow.png create mode 100644 BSF/template/yoga/icon/sync_metadata.png create mode 100644 BSF/template/yoga/icon/toggle_is_default_group.png create mode 100644 BSF/template/yoga/icon/uncheck.png create mode 100644 BSF/template/yoga/icon/up.png create mode 100644 BSF/template/yoga/icon/validate_s.png create mode 100644 BSF/template/yoga/icon/virt_category.png create mode 100644 BSF/template/yoga/identification.tpl create mode 100644 BSF/template/yoga/index.php create mode 100644 BSF/template/yoga/index.tpl create mode 100644 BSF/template/yoga/install.tpl create mode 100644 BSF/template/yoga/layout.css create mode 100644 BSF/template/yoga/mail/index.php create mode 100644 BSF/template/yoga/mail/text/html/admin/cat_group_info.tpl create mode 100644 BSF/template/yoga/mail/text/html/admin/index.php create mode 100644 BSF/template/yoga/mail/text/html/admin/notification_by_mail.tpl create mode 100644 BSF/template/yoga/mail/text/html/footer.tpl create mode 100644 BSF/template/yoga/mail/text/html/global-mail-css.tpl create mode 100644 BSF/template/yoga/mail/text/html/header.tpl create mode 100644 BSF/template/yoga/mail/text/html/images/footer-bg.png create mode 100644 BSF/template/yoga/mail/text/html/images/header-bg.png create mode 100644 BSF/template/yoga/mail/text/html/images/index.php create mode 100644 BSF/template/yoga/mail/text/html/images/mailbody-bg.png create mode 100644 BSF/template/yoga/mail/text/html/index.php create mode 100644 BSF/template/yoga/mail/text/index.php create mode 100644 BSF/template/yoga/mail/text/plain/admin/cat_group_info.tpl create mode 100644 BSF/template/yoga/mail/text/plain/admin/index.php create mode 100644 BSF/template/yoga/mail/text/plain/admin/notification_by_mail.tpl create mode 100644 BSF/template/yoga/mail/text/plain/footer.tpl create mode 100644 BSF/template/yoga/mail/text/plain/header.tpl create mode 100644 BSF/template/yoga/mail/text/plain/index.php create mode 100644 BSF/template/yoga/mainpage_categories.tpl create mode 100644 BSF/template/yoga/menubar.css create mode 100644 BSF/template/yoga/menubar.tpl create mode 100644 BSF/template/yoga/month_calendar.tpl create mode 100644 BSF/template/yoga/nbm.tpl create mode 100644 BSF/template/yoga/not-ie.css create mode 100644 BSF/template/yoga/notification.tpl create mode 100644 BSF/template/yoga/password.tpl create mode 100644 BSF/template/yoga/picture.css create mode 100644 BSF/template/yoga/picture.tpl create mode 100644 BSF/template/yoga/picture_content.tpl create mode 100644 BSF/template/yoga/picture_nav_buttons.tpl create mode 100644 BSF/template/yoga/popuphelp.tpl create mode 100644 BSF/template/yoga/print.css create mode 100644 BSF/template/yoga/profile.tpl create mode 100644 BSF/template/yoga/profile_content.tpl create mode 100644 BSF/template/yoga/rating.js create mode 100644 BSF/template/yoga/redirect.tpl create mode 100644 BSF/template/yoga/register.tpl create mode 100644 BSF/template/yoga/search.tpl create mode 100644 BSF/template/yoga/search_rules.tpl create mode 100644 BSF/template/yoga/slideshow.tpl create mode 100644 BSF/template/yoga/tags.tpl create mode 100644 BSF/template/yoga/theme/admin/images/bottom-left-bg.png create mode 100644 BSF/template/yoga/theme/admin/images/content-bg.png create mode 100644 BSF/template/yoga/theme/admin/images/header_bottom.png create mode 100644 BSF/template/yoga/theme/admin/images/index.php create mode 100644 BSF/template/yoga/theme/admin/images/internal_onglet.png create mode 100644 BSF/template/yoga/theme/admin/images/list-hover.png create mode 100644 BSF/template/yoga/theme/admin/images/list-image.png create mode 100644 BSF/template/yoga/theme/admin/images/menubar-bg.jpg create mode 100644 BSF/template/yoga/theme/admin/images/menubar-bg.png create mode 100644 BSF/template/yoga/theme/admin/images/menubar-bottom.png create mode 100644 BSF/template/yoga/theme/admin/images/menubar-detail.png create mode 100644 BSF/template/yoga/theme/admin/images/menubar-top.png create mode 100644 BSF/template/yoga/theme/admin/images/onglet_actif.png create mode 100644 BSF/template/yoga/theme/admin/images/onglet_actif_transp.png create mode 100644 BSF/template/yoga/theme/admin/images/onglet_inactif.png create mode 100644 BSF/template/yoga/theme/admin/images/onglet_inactif_transp.png create mode 100644 BSF/template/yoga/theme/admin/images/piwigo_logo_sombre_214x100.png create mode 100644 BSF/template/yoga/theme/admin/images/pre-menubar-bg.png create mode 100644 BSF/template/yoga/theme/admin/images/tableh1_bg.png create mode 100644 BSF/template/yoga/theme/admin/images/tableh2_bg.png create mode 100644 BSF/template/yoga/theme/admin/images/top-left-bg.png create mode 100644 BSF/template/yoga/theme/admin/index.php create mode 100644 BSF/template/yoga/theme/admin/mail-css.tpl create mode 100644 BSF/template/yoga/theme/admin/theme.css create mode 100644 BSF/template/yoga/theme/admin/themeconf.inc.php create mode 100644 BSF/template/yoga/theme/clear/index.php create mode 100644 BSF/template/yoga/theme/clear/mail-css.tpl create mode 100644 BSF/template/yoga/theme/clear/theme.css create mode 100644 BSF/template/yoga/theme/clear/themeconf.inc.php create mode 100644 BSF/template/yoga/theme/dark/images/index.php create mode 100644 BSF/template/yoga/theme/dark/images/tableh1_bg.png create mode 100644 BSF/template/yoga/theme/dark/images/tableh2_bg.png create mode 100644 BSF/template/yoga/theme/dark/index.php create mode 100644 BSF/template/yoga/theme/dark/mail-css.tpl create mode 100644 BSF/template/yoga/theme/dark/theme.css create mode 100644 BSF/template/yoga/theme/dark/themeconf.inc.php create mode 100644 BSF/template/yoga/theme/index.php create mode 100644 BSF/template/yoga/theme/p0w0/images/button-bg.png create mode 100644 BSF/template/yoga/theme/p0w0/images/index.php create mode 100644 BSF/template/yoga/theme/p0w0/index.php create mode 100644 BSF/template/yoga/theme/p0w0/mail-css.tpl create mode 100644 BSF/template/yoga/theme/p0w0/theme.css create mode 100644 BSF/template/yoga/theme/p0w0/themeconf.inc.php create mode 100644 BSF/template/yoga/theme/wipi/images/index.php create mode 100644 BSF/template/yoga/theme/wipi/images/tableh1_bg.png create mode 100644 BSF/template/yoga/theme/wipi/images/tableh2_bg.png create mode 100644 BSF/template/yoga/theme/wipi/index.php create mode 100644 BSF/template/yoga/theme/wipi/mail-css.tpl create mode 100644 BSF/template/yoga/theme/wipi/theme.css create mode 100644 BSF/template/yoga/theme/wipi/themeconf.inc.php create mode 100644 BSF/template/yoga/thumbnails-fix-ie5-ie6.css create mode 100644 BSF/template/yoga/thumbnails.css create mode 100644 BSF/template/yoga/thumbnails.tpl create mode 100644 BSF/template/yoga/upgrade.tpl create mode 100644 BSF/template/yoga/upload.tpl create mode 100644 BSF/tools/config_local.inc.php create mode 100644 BSF/tools/create_listing_file.php create mode 100644 BSF/tools/create_listing_file_local.inc.php create mode 100644 BSF/tools/fill_history.pl create mode 100644 BSF/tools/index.php create mode 100644 BSF/tools/local-layout.css create mode 100644 BSF/tools/metadata.php create mode 100644 BSF/tools/prototype.js create mode 100644 BSF/tools/pwg_rel_create.sh create mode 100644 BSF/tools/release_creation.readme create mode 100644 BSF/tools/ws.htm create mode 100644 BSF/upgrade.php create mode 100644 BSF/upgrade_feed.php create mode 100644 BSF/upload.php create mode 100644 BSF/ws.php diff --git a/BSF/about.php b/BSF/about.php new file mode 100644 index 000000000..c44520f45 --- /dev/null +++ b/BSF/about.php @@ -0,0 +1,70 @@ +set_filenames( + array( + 'about'=>'about.tpl', + ) + ); +if ( isset($lang['Theme: '.$user['theme']]) ) +{ + $template->assign( + 'THEME_ABOUT',l10n('Theme: '.$user['theme']) + ); +} + +$template->assign('ABOUT_MESSAGE', load_language('about.html','','',true) ); + +$template->pparse('about'); +include(PHPWG_ROOT_PATH.'include/page_tail.php'); +?> diff --git a/BSF/action.php b/BSF/action.php new file mode 100644 index 000000000..3d16b1bd9 --- /dev/null +++ b/BSF/action.php @@ -0,0 +1,203 @@ + restriction) +$query=' +SELECT id + FROM '.CATEGORIES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON category_id = id + WHERE image_id = '.$_GET['id'].' +'.get_sql_condition_FandF( + array( + 'forbidden_categories' => 'category_id', + 'forbidden_images' => 'image_id', + ), + ' AND' + ).' + LIMIT 1 +;'; +if ( mysql_num_rows(pwg_query($query))<1 ) +{ + do_error(401, 'Access denied'); +} + +include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php'); +$file=''; +switch ($_GET['part']) +{ + case 't': + $file = get_thumbnail_path($element_info); + break; + case 'e': + $file = get_element_path($element_info); + break; + case 'i': + $file = get_image_path($element_info); + break; + case 'h': + if ( $user['enabled_high']!='true' ) + { + do_error(401, 'Access denied h'); + } + $file = get_high_path($element_info); + break; +} + +if ( empty($file) ) +{ + do_error(404, 'Requested file not found'); +} + +if ($_GET['part'] == 'h') { + pwg_log($_GET['id'], 'high'); +} +else if ($_GET['part'] == 'e') +{ + pwg_log($_GET['id'], 'other'); +} + +$http_headers = array(); + +$ctype = null; +if (!url_is_remote($file)) +{ + if ( !@is_readable($file) ) + { + do_error(404, "Requested file not found - $file"); + } + $http_headers[] = 'Content-Length: '.@filesize($file); + if ( function_exists('mime_content_type') ) + { + $ctype = mime_content_type($file); + } + + $gmt_mtime = gmdate('D, d M Y H:i:s', filemtime($file)).' GMT'; + $http_headers[] = 'Last-Modified: '.$gmt_mtime; + + // following lines would indicate how the client should handle the cache + /* $max_age=300; + $http_headers[] = 'Expires: '.gmdate('D, d M Y H:i:s', time()+$max_age).' GMT'; + // HTTP/1.1 only + $http_headers[] = 'Cache-Control: private, must-revalidate, max-age='.$max_age;*/ + + if ( isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) + { + set_status_header(304); + foreach ($http_headers as $header) + { + header( $header ); + } + exit(); + } +} + +if (!isset($ctype)) +{ // give it a guess + $ctype = guess_mime_type( get_extension($file) ); +} + +$http_headers[] = 'Content-Type: '.$ctype; + +if (!isset($_GET['view'])) +{ + $http_headers[] = 'Content-Disposition: attachment; filename="' + .basename($file).'";'; + $http_headers[] = 'Content-Transfer-Encoding: binary'; +} +else +{ + $http_headers[] = 'Content-Disposition: inline; filename="' + .basename($file).'";'; +} + +foreach ($http_headers as $header) +{ + header( $header ); +} + +// Looking at the safe_mode configuration for execution time +if (ini_get('safe_mode') == 0) +{ + @set_time_limit(0); +} + +@readfile($file); + +?> \ No newline at end of file diff --git a/BSF/admin.php b/BSF/admin.php new file mode 100644 index 000000000..f932b53a4 --- /dev/null +++ b/BSF/admin.php @@ -0,0 +1,172 @@ +'.l10n('Piwigo Administration').''; +$page['body_id'] = 'theAdminPage'; + +$template->set_filenames(array('admin' => 'admin.tpl')); + +$template->assign( + array( + 'U_SITE_MANAGER'=> $link_start.'site_manager', + 'U_HISTORY_STAT'=> $link_start.'stats', + 'U_FAQ'=> $link_start.'help', + 'U_SITES'=> $link_start.'remote_site', + 'U_MAINTENANCE'=> $link_start.'maintenance', + 'U_NOTIFICATION_BY_MAIL'=> $link_start.'notification_by_mail', + 'U_ADVANCED_FEATURE'=> $link_start.'advanced_feature', + 'U_CONFIG_GENERAL'=> $link_start.'configuration', + 'U_CONFIG_DISPLAY'=> $conf_link.'default', + 'U_CATEGORIES'=> $link_start.'cat_list', + 'U_MOVE'=> $link_start.'cat_move', + 'U_CAT_OPTIONS'=> $link_start.'cat_options', + 'U_CAT_UPDATE'=> $link_start.'site_update&site=1', + 'U_WAITING'=> $link_start.'comments', + 'U_RATING'=> $link_start.'rating', + 'U_CADDIE'=> $link_start.'element_set&cat=caddie', + 'U_TAGS'=> $link_start.'tags', + 'U_THUMBNAILS'=> $link_start.'thumbnail', + 'U_USERS'=> $link_start.'user_list', + 'U_GROUPS'=> $link_start.'group_list', + 'U_PERMALINKS'=> $link_start.'permalinks', + 'U_RETURN'=> make_index_url(), + 'U_ADMIN'=> PHPWG_ROOT_PATH.'admin.php' + ) + ); +if ($conf['ws_access_control']) // Do we need to display ws_checker +{ + $template->assign('U_WS_CHECKER', $link_start.'ws_checker' ); +} + +//---------------------------------------------------------------- plugin menus +$plugin_menu_links = trigger_event('get_admin_plugin_menu_links', array() ); + +function UC_name_compare($a, $b) +{ + return strcmp(strtolower($a['NAME']), strtolower($b['NAME'])); +} +usort($plugin_menu_links, 'UC_name_compare'); + +array_unshift($plugin_menu_links, + array( + 'NAME' => l10n('admin'), + 'URL' => $link_start.'plugins_list' + ) + ); + +$template->assign('plugin_menu_items', $plugin_menu_links); + +include(PHPWG_ROOT_PATH.'admin/'.$page['page'].'.php'); + +//------------------------------------------------------------- content display + +// +-----------------------------------------------------------------------+ +// | errors & infos | +// +-----------------------------------------------------------------------+ + +if (count($page['errors']) != 0) +{ + $template->assign('errors', $page['errors']); +} + +if (count($page['infos']) != 0) +{ + $template->assign('infos', $page['infos']); +} + +// Add the Piwigo Official menu + $template->assign( 'pwgmenu', pwg_URL() ); + +include(PHPWG_ROOT_PATH.'include/page_header.php'); +$template->pparse('admin'); + +// +-----------------------------------------------------------------------+ +// | order permission refreshment | +// +-----------------------------------------------------------------------+ +// Only for pages witch change permissions +if ( + in_array($page['page'], + array( + 'site_manager', // delete site + 'site_update', // ?only POST + 'cat_list', // delete cat + 'cat_modify', // delete cat; public/private; lock/unlock + 'cat_move', // ?only POST + 'cat_options', // ?only POST; public/private; lock/unlock + 'cat_perm', // ?only POST + 'element_set', // ?only POST; associate/dissociate + 'picture_modify', // ?only POST; associate/dissociate + 'user_list', // ?only POST; group assoc + 'user_perm', + 'group_perm', + 'group_list', // delete group + ) + ) + ) +{ + invalidate_user_cache(); +} + +include(PHPWG_ROOT_PATH.'include/page_tail.php'); +?> 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 @@ + 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 @@ + $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 = ''; +$navigation.= l10n('home'); +$navigation.= ''; + +// +-----------------------------------------------------------------------+ +// | 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 @@ + $_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'), + '' + ) + ); + } +} +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'), + '' + ) + ); +} + +$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 = ''; + } + } + + 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 @@ + 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 @@ +'; +// print_r($_POST); +// print ''; +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 @@ + 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 @@ + 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 @@ + 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 '
'; print_r($_POST); echo '
'; + $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 @@ + 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 @@ +'; +// print_r($_POST); +// echo ''; +// 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 '
'; print_r($datas); echo '
'; + 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 '
'.$query.'
'; + $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 @@ + 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 '
'; print_r($row); echo '
'; + 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 = + '

'. + l10n('No tag defined. Use Administration>Pictures>Tags'). + '

'; + } + + $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 @@ +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 @@ + 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 @@ +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 @@ +'; print_r($search); echo ''; + + 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 '
'; print_r($high_filesize_of_image); echo '
'; + } + + 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.= ' +'; + + $tags_string = ''; + if (isset($line['tag_ids'])) + { + $tags_string = preg_replace( + '/(\d+)/e', + '$name_of_tag["$1"]', + str_replace( + ',', + ', ', + $line['tag_ids'] + ) + ); + } + + $image_string = ''; + if (isset($line['image_id'])) + { + $picture_url = make_picture_url( + array( + 'image_id' => $line['image_id'], + ) + ); + + $element = array( + 'id' => $line['image_id'], + 'file' => $file_of_image[$line['image_id']], + 'path' => $path_of_image[$line['image_id']], + 'tn_ext' => $tn_ext_of_image[$line['image_id']], + ); + + $image_title = '('.$line['image_id'].')'; + + if (isset($label_of_image[$line['image_id']])) + { + $image_title.= ' '.$label_of_image[$line['image_id']]; + } + else + { + $image_title.= ' unknown filename'; + } + + $image_string = ''; + + switch ($page['search']['fields']['display_thumbnail']) + { + case 'no_display_thumbnail': + { + $image_string= ''.$image_title.''; + break; + } + case 'display_thumbnail_classic': + { + $image_string = + '' + .''.$image_title.'' + .''; + break; + } + case 'display_thumbnail_hoverbox': + { + $image_string = + '' + .''.$image_title.'' + .''.$image_title.''; + break; + } + } + } + + $template->append( + 'search_results', + array( + 'DATE' => $line['date'], + 'TIME' => $line['time'], + 'USER' => $user_string, + 'IP' => $line['IP'], + 'IMAGE' => $image_string, + 'TYPE' => $line['image_type'], + 'SECTION' => $line['section'], + 'CATEGORY' => isset($line['category_id']) + ? ( isset($name_of_category[$line['category_id']]) + ? $name_of_category[$line['category_id']] + : 'deleted '.$line['category_id'] ) + : '', + 'TAGS' => $tags_string, + ) + ); + } + + $summary['nb_guests'] = 0; + if (count(array_keys($summary['guests_IP'])) > 0) + { + $summary['nb_guests'] = count(array_keys($summary['guests_IP'])); + + // we delete the "guest" from the $username_of hash so that it is + // avoided in next steps + unset($username_of[ $conf['guest_id'] ]); + } + + $summary['nb_members'] = count($username_of); + + $member_strings = array(); + foreach ($username_of as $user_id => $user_name) + { + $member_string = $user_name.' +'; + + $member_strings[] = $member_string; + } + + $template->assign( + 'search_summary', + array( + 'NB_LINES' => l10n_dec( + '%d line filtered', '%d lines filtered', + $page['nb_lines'] + ), + 'FILESIZE' => $summary['total_filesize'].' KB', + 'USERS' => l10n_dec( + '%d user', '%d users', + $summary['nb_members'] + $summary['nb_guests'] + ), + 'MEMBERS' => sprintf( + l10n_dec('%d member', '%d members', $summary['nb_members']).': %s', + implode( + ', ', + $member_strings + ) + ), + 'GUESTS' => l10n_dec( + '%d guest', '%d guests', + $summary['nb_guests'] + ), + ) + ); +} + +// +-----------------------------------------------------------------------+ +// | navigation bar | +// +-----------------------------------------------------------------------+ + +if (isset($page['search_id'])) +{ + $navbar = create_navigation_bar( + get_root_url().'admin.php'.get_query_string_diff(array('start')), + $page['nb_lines'], + $page['start'], + $conf['nb_logs_page'] + ); + + $template->assign('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 @@ + 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', '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') + .'
'. + $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.'\']') + .'
'. + $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 @@ +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 = '%s'; + 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 @@ + 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 = ''."\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.= " \n"; + $xml_string.= " ".$row['id']."\n"; + $xml_string.= " ".$row['path']."\n"; + + foreach ($tags_of[ $row['id'] ] as $tag_id) + { + $xml_string.= " ".$tag_name_of[$tag_id]."\n"; + } + + $xml_string.= " \n"; + } + + $xml_string.= ''; + 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 @@ +add('stats', l10n('Statistics'), $link_start.'stats'); + $tabsheet->add('history', l10n('Search'), $link_start.'history'); + // TabSheet selection + $tabsheet->select($page['page']); + // Assign tabsheet to template + $tabsheet->assign(); +} + +function history_compare($a, $b) +{ + return strcmp($a['date'].$a['time'], $b['date'].$b['time']); +} + +function get_history($data, $search, $types) +{ + if (isset($search['fields']['filename'])) + { + $query = ' +SELECT + id + FROM '.IMAGES_TABLE.' + WHERE file LIKE \''.$search['fields']['filename'].'\' +;'; + $search['image_ids'] = array_from_query($query, 'id'); + } + + // echo '
'; print_r($search); echo '
'; + + $clauses = array(); + + if (isset($search['fields']['date-after'])) + { + array_push( + $clauses, + "date >= '".$search['fields']['date-after']."'" + ); + } + + if (isset($search['fields']['date-before'])) + { + array_push( + $clauses, + "date <= '".$search['fields']['date-before']."'" + ); + } + + if (isset($search['fields']['types'])) + { + $local_clauses = array(); + + foreach ($types as $type) { + if (in_array($type, $search['fields']['types'])) { + $clause = 'image_type '; + if ($type == 'none') + { + $clause.= 'IS NULL'; + } + else + { + $clause.= "= '".$type."'"; + } + + array_push($local_clauses, $clause); + } + } + + if (count($local_clauses) > 0) + { + array_push( + $clauses, + implode(' OR ', $local_clauses) + ); + } + } + + if (isset($search['fields']['user']) + and $search['fields']['user'] != -1) + { + array_push( + $clauses, + 'user_id = '.$search['fields']['user'] + ); + } + + if (isset($search['fields']['image_id'])) + { + array_push( + $clauses, + 'image_id = '.$search['fields']['image_id'] + ); + } + + if (isset($search['fields']['filename'])) + { + if (count($search['image_ids']) == 0) + { + // a clause that is always false + array_push($clauses, '1 = 2 '); + } + else + { + array_push( + $clauses, + 'image_id IN ('.implode(', ', $search['image_ids']).')' + ); + } + } + + $clauses = prepend_append_array_items($clauses, '(', ')'); + + $where_separator = + implode( + "\n AND ", + $clauses + ); + + $query = ' +SELECT + date, + time, + user_id, + IP, + section, + category_id, + tag_ids, + image_id, + image_type + FROM '.HISTORY_TABLE.' + WHERE '.$where_separator.' +;'; + + // LIMIT '.$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 @@ + $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 @@ + 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 @@ + 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 @@ +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 @@ + +define(\'PHPWG_IN_UPGRADE\', true); + +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 @@ +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 @@ + 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 @@ +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= $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; $iprivCalculateStoredFilename($v_descr, $p_options); + + // ----- Add the descriptor in result list + $v_result_list[sizeof($v_result_list)] = $v_descr; + + // ----- Look for folder + if ($v_descr['type'] == 'folder') { + // ----- List of items in folder + $v_dirlist_descr = array(); + $v_dirlist_nb = 0; + if ($v_folder_handler = @opendir($v_descr['filename'])) { + while (($v_item_handler = @readdir($v_folder_handler)) !== false) { + //--(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; $iprivWriteCentralFileHeader($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; $iprivWriteCentralFileHeader($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; ($jprivAddFile($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 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=$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 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=$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; $izip_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; $iprivWriteCentralFileHeader($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 @@ +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 @@ +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 @@ + 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 @@ + 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 @@ +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 @@ + 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 $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 @@ + $value) + { + if (!in_array($key, $get_rejects) and $key!=$get_param) + { + $base_url .= $is_first ? '?' : '&'; + $is_first = false; + $base_url .= $key.'='.urlencode($value); + } + } + + $ret = array(); + foreach( $sortable_by as $field) + { + $url = $base_url; + $disp = '⇓'; // TODO: an small image is better + + if ( $field !== @$_GET[$get_param] ) + { + if ( !isset($default_field) or $default_field!=$field ) + { // the first should be the default + $url = add_url_params($url, array($get_param=>$field) ); + } + elseif (isset($default_field) and !isset($_GET[$get_param]) ) + { + array_push($ret, $field); + $disp = ''.$disp.''; + } + } + else + { + array_push($ret, $field); + $disp = ''.$disp.''; + } + if ( isset($template_var) ) + { + $template->assign( $template_var.strtoupper($field), + ''.$disp.'' + ); + } + } + return $ret; +} + +if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!'); + +include_once(PHPWG_ROOT_PATH.'admin/include/functions_permalinks.php'); + +$selected_cat = array(); +if ( isset($_POST['set_permalink']) and $_POST['cat_id']>0 and !is_adviser() ) +{ + $permalink = $_POST['permalink']; + if ( empty($permalink) ) + delete_cat_permalink($_POST['cat_id'], isset($_POST['save']) ); + else + set_cat_permalink($_POST['cat_id'], $permalink, isset($_POST['save']) ); + $selected_cat = array( $_POST['cat_id'] ); +} +elseif ( isset($_GET['delete_permanent']) and !is_adviser() ) +{ + $query = ' +DELETE FROM '.OLD_PERMALINKS_TABLE.' + WHERE permalink="'.$_GET['delete_permanent'].'" + LIMIT 1'; + 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 @@ + $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 = + '

'. + l10n('No tag defined. Use Administration>Pictures>Tags'). + '

'; +} + +$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 @@ + \ 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 @@ +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 = '' + . $display_name . ''; + } + $desc = $fs_plugin['description']; + if (!empty($fs_plugin['author'])) + { + $desc .= ' ('; + if (!empty($fs_plugin['author uri'])) + { + $desc .= '' + . $fs_plugin['author'] . ''; + } + else + { + $desc .= $fs_plugin['author']; + } + $desc .= ')'; + } + $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 @@ +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 @@ +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 @@ +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 @@ + '.$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; $iappend( + '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 @@ +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 @@ +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 @@ +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 @@ + 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', '' ); +} +// +-----------------------------------------------------------------------+ +// | 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', '' ); + + $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', '' ); + + // 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', '' ); + $start = get_moment(); + update_global_rank(); + $template->append('footer_elements', ''); + } + + 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', ''); + $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', ''); + }// 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', ''); + + $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', ''); + + $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 @@ + $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, + ''.l10n('Overall').'' + ); + +$period_label = l10n('Year'); + +if (isset($page['year'])) +{ + $url.= '&year='.$page['year']; + + array_push( + $title_parts, + ''.$page['year'].'' + ); + + $period_label = l10n('Month'); +} + +if (isset($page['month'])) +{ + $url.= '&month='.$page['month']; + + array_push( + $title_parts, + ''.$lang['month'][$page['month']].'' + ); + + $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, + ''.$day_title.'' + ); + + $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 = ''.$value.''; + } + + $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 @@ + $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 @@ + 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 @@ + 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 @@ + 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'] + ? '
['.l10n('is_the_guest').']' : '') + .($local_user['id'] == $conf['default_user_id'] + ? '
['.l10n('is_the_default').']' : ''), + 'STATUS' => l10n('user_status_'. + $local_user['status']).(($local_user['adviser'] == 'true') + ? '
['.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 @@ + 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 @@ + $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'); +?> diff --git a/BSF/category.php b/BSF/category.php new file mode 100644 index 000000000..303cc903f --- /dev/null +++ b/BSF/category.php @@ -0,0 +1,65 @@ + diff --git a/BSF/comments.php b/BSF/comments.php new file mode 100644 index 000000000..555986328 --- /dev/null +++ b/BSF/comments.php @@ -0,0 +1,394 @@ + l10n('descending'), + 'ASC' => l10n('ascending') + ); + +// sort_by : database fields proposed for sorting comments list +$sort_by = array( + 'date' => l10n('comment date'), + 'image_id' => l10n('picture') + ); + +// items_number : list of number of items to display per page +$items_number = array(5,10,20,50,'all'); + +// since when display comments ? +// +$since_options = array( + 1 => array('label' => l10n('today'), + 'clause' => 'date > SUBDATE(CURDATE(), INTERVAL 1 DAY)'), + 2 => array('label' => sprintf(l10n('last %d days'), 7), + 'clause' => 'date > SUBDATE(CURDATE(), INTERVAL 7 DAY)'), + 3 => array('label' => sprintf(l10n('last %d days'), 30), + 'clause' => 'date > SUBDATE(CURDATE(), INTERVAL 30 DAY)'), + 4 => array('label' => l10n('the beginning'), + 'clause' => '1=1') // stupid but generic + ); + +$page['since'] = isset($_GET['since']) ? $_GET['since'] : 4; + +// on which field sorting +// +$page['sort_by'] = 'date'; +// if the form was submitted, it overloads default behaviour +if (isset($_GET['sort_by'])) +{ + $page['sort_by'] = $_GET['sort_by']; +} + +// order to sort +// +$page['sort_order'] = 'DESC'; +// if the form was submitted, it overloads default behaviour +if (isset($_GET['sort_order'])) +{ + $page['sort_order'] = $_GET['sort_order']; +} + +// number of items to display +// +$page['items_number'] = 10; +if (isset($_GET['items_number'])) +{ + $page['items_number'] = $_GET['items_number']; +} + +$page['where_clauses'] = array(); + +// which category to filter on ? +if (isset($_GET['cat']) and 0 != $_GET['cat']) +{ + $page['where_clauses'][] = + 'category_id IN ('.implode(',', get_subcat_ids(array($_GET['cat']))).')'; +} + +// search a particular author +if (isset($_GET['author']) and !empty($_GET['author'])) +{ + $page['where_clauses'][] = 'com.author = \''.$_GET['author'].'\''; +} + +// search a substring among comments content +if (isset($_GET['keyword']) and !empty($_GET['keyword'])) +{ + $page['where_clauses'][] = + '('. + implode(' AND ', + array_map( + create_function( + '$s', + 'return "content LIKE \'%$s%\'";' + ), + preg_split('/[\s,;]+/', $_GET['keyword'] ) + ) + ). + ')'; +} + +$page['where_clauses'][] = $since_options[$page['since']]['clause']; + +// which status to filter on ? +if ( !is_admin() ) +{ + $page['where_clauses'][] = 'validated="true"'; +} + +$page['where_clauses'][] = get_sql_condition_FandF + ( + array + ( + 'forbidden_categories' => 'category_id', + 'visible_categories' => 'category_id', + 'visible_images' => 'ic.image_id' + ), + '', true + ); + +// +-----------------------------------------------------------------------+ +// | comments management | +// +-----------------------------------------------------------------------+ +if (isset($_GET['delete']) and is_numeric($_GET['delete']) + and !is_adviser() ) +{// comments deletion + check_status(ACCESS_ADMINISTRATOR); + $query = ' +DELETE FROM '.COMMENTS_TABLE.' + WHERE id='.$_GET['delete'].' +;'; + pwg_query($query); +} + +if (isset($_GET['validate']) and is_numeric($_GET['validate']) + and !is_adviser() ) +{ // comments validation + check_status(ACCESS_ADMINISTRATOR); + $query = ' +UPDATE '.COMMENTS_TABLE.' + SET validated = \'true\' + , validation_date = NOW() + WHERE id='.$_GET['validate'].' +;'; + pwg_query($query); +} + +// +-----------------------------------------------------------------------+ +// | page header and options | +// +-----------------------------------------------------------------------+ + +$title= l10n('User comments'); +$page['body_id'] = 'theCommentsPage'; + +$template->set_filenames(array('comments'=>'comments.tpl')); +$template->assign( + array( + 'F_ACTION'=>PHPWG_ROOT_PATH.'comments.php', + 'F_KEYWORD'=>@htmlspecialchars(stripslashes($_GET['keyword'])), + 'F_AUTHOR'=>@htmlspecialchars(stripslashes($_GET['author'])), + ) + ); + +// +-----------------------------------------------------------------------+ +// | form construction | +// +-----------------------------------------------------------------------+ + +// Search in a particular category +$blockname = 'categories'; + +$query = ' +SELECT id, name, uppercats, global_rank + FROM '.CATEGORIES_TABLE.' +'.get_sql_condition_FandF + ( + array + ( + 'forbidden_categories' => 'id', + 'visible_categories' => 'id' + ), + 'WHERE' + ).' +;'; +display_select_cat_wrapper($query, array(@$_GET['cat']), $blockname, true); + +// Filter on recent comments... +$tpl_var=array(); +foreach ($since_options as $id => $option) +{ + $tpl_var[ $id ] = $option['label']; +} +$template->assign( 'since_options', $tpl_var); +$template->assign( 'since_options_selected', $page['since']); + +// Sort by +$template->assign( 'sort_by_options', $sort_by); +$template->assign( 'sort_by_options_selected', $page['sort_by']); + +// Sorting order +$template->assign( 'sort_order_options', $sort_order); +$template->assign( 'sort_order_options_selected', $page['sort_order']); + + +// Number of items +$blockname = 'items_number_option'; +$tpl_var=array(); +foreach ($items_number as $option) +{ + $tpl_var[ $option ] = is_numeric($option) ? $option : l10n($option); +} +$template->assign( 'item_number_options', $tpl_var); +$template->assign( 'item_number_options_selected', $page['items_number']); + + +// +-----------------------------------------------------------------------+ +// | navigation bar | +// +-----------------------------------------------------------------------+ + +if (isset($_GET['start']) and is_numeric($_GET['start'])) +{ + $start = $_GET['start']; +} +else +{ + $start = 0; +} + +$query = ' +SELECT COUNT(DISTINCT(id)) + FROM '.IMAGE_CATEGORY_TABLE.' AS ic + INNER JOIN '.COMMENTS_TABLE.' AS com + ON ic.image_id = com.image_id + WHERE '.implode(' + AND ', $page['where_clauses']).' +;'; +list($counter) = mysql_fetch_row(pwg_query($query)); + +$url = PHPWG_ROOT_PATH + .'comments.php' + .get_query_string_diff(array('start','delete','validate')); + +$navbar = create_navigation_bar($url, + $counter, + $start, + $page['items_number'], + ''); + +$template->assign('NAVBAR', $navbar); + +// +-----------------------------------------------------------------------+ +// | last comments display | +// +-----------------------------------------------------------------------+ + +$comments = array(); +$element_ids = array(); +$category_ids = array(); + +$query = ' +SELECT com.id AS comment_id + , com.image_id + , ic.category_id + , com.author + , com.date + , com.content + , com.id AS comment_id + , com.validated + FROM '.IMAGE_CATEGORY_TABLE.' AS ic + INNER JOIN '.COMMENTS_TABLE.' AS com + ON ic.image_id = com.image_id + WHERE '.implode(' + AND ', $page['where_clauses']).' + GROUP BY comment_id + ORDER BY '.$page['sort_by'].' '.$page['sort_order']; +if ('all' != $page['items_number']) +{ + $query.= ' + LIMIT '.$start.','.$page['items_number']; +} +$query.= ' +;'; +$result = pwg_query($query); +while ($row = mysql_fetch_assoc($result)) +{ + array_push($comments, $row); + array_push($element_ids, $row['image_id']); + array_push($category_ids, $row['category_id']); +} + +if (count($comments) > 0) +{ + // retrieving element informations + $elements = array(); + $query = ' +SELECT id, name, file, path, tn_ext + FROM '.IMAGES_TABLE.' + WHERE id IN ('.implode(',', $element_ids).') +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $elements[$row['id']] = $row; + } + + // retrieving category informations + $query = ' +SELECT id, name, permalink, uppercats + FROM '.CATEGORIES_TABLE.' + WHERE id IN ('.implode(',', $category_ids).') +;'; + $categories = hash_from_query($query, 'id'); + + foreach ($comments as $comment) + { + if (!empty($elements[$comment['image_id']]['name'])) + { + $name=$elements[$comment['image_id']]['name']; + } + else + { + $name=get_name_from_file($elements[$comment['image_id']]['file']); + } + + // source of the thumbnail picture + $thumbnail_src = get_thumbnail_url( $elements[$comment['image_id']] ); + + // link to the full size picture + $url = make_picture_url( + array( + 'category' => $categories[ $comment['category_id'] ], + 'image_id' => $comment['image_id'], + 'image_file' => $elements[$comment['image_id']]['file'], + ) + ); + + $author = $comment['author']; + if (empty($comment['author'])) + { + $author = l10n('guest'); + } + + $tpl_comment = + array( + 'U_PICTURE' => $url, + 'TN_SRC' => $thumbnail_src, + 'ALT' => $name, + 'AUTHOR' => trigger_event('render_comment_author', $author), + 'DATE'=>format_date($comment['date'],'mysql_datetime',true), + 'CONTENT'=>trigger_event('render_comment_content',$comment['content']), + ); + + if ( is_admin() ) + { + $url = get_root_url().'comments.php'.get_query_string_diff(array('delete','validate')); + $tpl_comment['U_DELETE'] = add_url_params($url, + array('delete'=>$comment['comment_id']) + ); + + if ($comment['validated'] != 'true') + { + $tpl_comment['U_VALIDATE'] = add_url_params($url, + array('validate'=>$comment['comment_id']) + ); + } + } + $template->append('comments', $tpl_comment); + } +} +// +-----------------------------------------------------------------------+ +// | html code display | +// +-----------------------------------------------------------------------+ +include(PHPWG_ROOT_PATH.'include/page_header.php'); +$template->pparse('comments'); +include(PHPWG_ROOT_PATH.'include/page_tail.php'); +?> \ No newline at end of file diff --git a/BSF/doc/COPYING b/BSF/doc/COPYING new file mode 100644 index 000000000..5b6e7c66c --- /dev/null +++ b/BSF/doc/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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; either version 2 of the License, or + (at your option) any later version. + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/BSF/doc/ChangeLog b/BSF/doc/ChangeLog new file mode 100644 index 000000000..7c9c084d7 --- /dev/null +++ b/BSF/doc/ChangeLog @@ -0,0 +1,822 @@ +2005-11-07 Pierrick LE GALL + + * bug 180 fixed: remote_site.tpl doesn't validate. + + * translation bug fixed: generate_file_listing.php doesn't exist, + it's create_listing_file.php ! + +2005-11-07 Pierrick LE GALL + + * bug 184 fixed: for the third time... + +2005-11-07 Pierrick LE GALL + + * improvement: use a "filter" form for adding user comments. + +2005-11-05 Pierrick LE GALL + + * bug 186 fixed: useless template theme icons deleted. Remaining + icons in GIF converted to PNG. + +2005-10-31 Pierrick LE GALL + + * bug 185 fixed: errors in language items. + +2005-10-31 Pierrick LE GALL + + * modification: use "filter" class for quickconnect box (with some + custom modifications) + + * bug fixed: the total number of pictures had disappeared + +2005-10-30 volcom + + * bug 190 fixed: issue in stats.tpl display + * bug fixed: labels of monthly, daily graph fixed + +2005-10-26 chrisaga + + * bug 177 fixed: for Safari (was fixed for Konqueror only) + +2005-10-25 Pierrick LE GALL + + * bug 183 fixed: Warning when trying to associate an image with an + already associated category. Just coded the TODO instructions I + had let some time ago. + +2005-10-23 chrisaga + + * bug 184 fixed: .png button left aligned in IE + +2005-10-23 Pierrick LE GALL + + * bug 182 fixed: newly created user is not displayed in the user + list. + +2005-10-23 Pierrick LE GALL + + * bug fixed: during file tree synchronization, warning on finding + the next rank of category which has no sub-categories yet. + +2005-10-23 chrisaga + + * bug fixed: cat-list.tpl validate now + + * improvement: removed some unnecessary css rules from old tests in + FROM design in file default-layout.css + +2005-10-23 Pierrick LE GALL + + * bug 181 fixed: "Parameters not created in phpwebgallery_config + during upgrade". gallery_title and gallery_description had not + been added to config table. (use|show)_(exif|iptc) and + authorize_remembering have also been removed... + +2005-10-22 chrisaga + + * bug 177 fixed: icon tools wrong position in Safari and Konqueror + Needed a little trick to fix it. Put the trick in a fix-khtml.css + Loading in header.tpl and protected from IE, Geko and Opera, + just in case (couldn't found a safari css-only filter wich validate) + + * bug fixed: issue in the FORM in remote_site.tpl which prevented + HTML validation (still something to do with the TABLE). + +2005-10-22 Pierrick LE GALL + + * bug fixed: link on a single day in + Administration>General>History was missing + +2005-10-22 Pierrick LE GALL + + * bug 173 fixed: due to phpBB user identifiers management, the + method to find the next user identifier has changer to MAX+1. + + * improvement: information message when new user added + + * bug fixed: language item "Username" used instead of "login". + +2005-10-20 chrisaga + + * bug 176 fixed: need a javascript to handle transparent PNG + background in IE (tribute to Bob Osola + http://homepage.ntlworld.com/bobosola/index.htm) + + * display: fixed another IE childselector bug in Categories + Management admin page and improved display of this page in all + browsers too. + +2005-10-18 Pierrick LE GALL + + * bug 174 fixed: use_exif_mapping configuration parameter was not + used to list database fields to update from EXIF values. + +2005-10-18 Pierrick LE GALL + + * bug 172 fixed: crash when changing password with an external + users table. The same kind of correction was also made in + picture.php and register.php. + +2005-10-18 Pierrick LE GALL + + * bug 159 and 166 fixed: parameter "options" for mail() function + disabled by default. + +2005-10-18 chrisaga + + * display : smaller font-size and, as requested, fonts more like 1.4 + + * bug 165 fixed : La largeur par dĂŠfaut en PIXELS pas en Kb + +2005-10-18 chrisaga + + * display : in group_list.tpl - wrong form class, mixed html tags, ... + + * display : suppress bullets in admin->synchronize and checkbox + under select + + * display : set standard font size to 12pt + +2005-10-17 Pierrick LE GALL + + * improvement: use new function get_language_filepath in about.php + (complement of bug 168 correction) + +2005-10-17 Pierrick LE GALL + + * bug 154 fixed: "Calendar category, too precise dates". Bug came + from the bigger precision of creation_date and available_date in + images tables. Need to retrieve only the year-month-day + information. + +2005-10-17 volcom + + * new: history details by month,day + +2005-10-15 Pierrick LE GALL + + * modification: localized labels in Administration>Pictures>Caddie + + * translation: bug fixed on special categories title in French + + * translation: all help pages were translated in french + +2005-10-09 Pierrick LE GALL + + * new: "quick start" section in Administration>General>Instructions + +2005-10-08 Pierrick LE GALL + + * translation: new items related to configuration parameters + gallery_title and gallery_description in GUI. + +2005-10-08 Pierrick LE GALL + + * modification: configuration parameters gallery_title and + gallery_description are GUI managed in + Administration>Configuration>General + + * bug fixed: configuration parameters (use|show)_(exif|iptc) and + authorize_remembering should have been deleted from config table + some time ago. + +2005-10-08 Pierrick LE GALL + + * new: mass virtual categories movement manager in + Administration>Categories>Move screen. + +2005-10-05 Pierrick LE GALL + + * bug 160 fixed: (part one of the bug) hard coded column name of + users table had to be replaced by the configurable column + name. This correction was made by a full rewrite of filtered users + list management. The other bug (not submited in bugtracker) that + needed this rewrite was that when you choose "all" as target for + mass users modification, you expected to apply modification on + filtered users, not all users. + + * bug 160 fixed: (part two of the bug) hard coded column name for + primary key in mass_updates function. + + * modification: configuration parameter users_page is now located + in the correct file (include/config_default.inc.php instead of + admin/user_list.php) + +2005-09-27 Pierrick LE GALL + + * bug 168 fixed: crash when language file does not + exists. Constant PHPWG_DEFAULT_LANGUAGE added. New function + get_language_filepath always used to find language files. + +2005-09-26 Pierrick LE GALL + + * bug 158 fixed: display error on "double selects" screens (with + MSIE, strange behavior). VDigital modification optimizes width + usage :-) + +2005-09-25 Pierrick LE GALL + + * bug 163 fixed: link error when cookies disabled in admin/stats + +2005-09-24 Pierrick LE GALL + + * bug fixed: HTML error on nested UL in categories menu. + + * bug 161 fixed: guest_id not taken into account for history table + insert. + + * bug 164 fixed: category inserted in history table becomes too + long if HTML tags are kept. + +2005-09-24 Pierrick LE GALL + + * bug 162 fixed: division by zero when trying to view "all" items + in admin/element_set_(global|unit) + + * bug 156 fixed: error when selection is empty was not catched. + +2005-09-21 Pierrick LE GALL + + * bug 151 fixed: default maxheight was not proposed as "set to" + option in admin/user_list + +2005-09-21 Pierrick LE GALL + + * bug 150 fixed: in category permissions management, wrong column + name when using an external users table. + +2005-09-20 Pierrick LE GALL + + * update: upgrade from 1.4.0 or 1.4.1. Upgrade from 1.3.x is not + available anymore. + + * update: README files updated for very near branch 1.5 :-) + + * new: file tools/config_local.inc.php as example for optional + include/config_local.inc.php + + * bug fixed: configuration parameter show_picture_name_on_title + was useless + +2005-09-18 Pierrick LE GALL + + * bug 111 fixed: "Can't add virtual category when cookie + disabled". Correction reported from branch 1.4. + + * bug 109 fixed : "disabled "best rated" menu item when rating is + not enabled". Correction reported from branch 1.4. + + * bug 95 fixed : "default maxwidth and maxheight not registered + ". Correction reported from branch 1.4. + +2005-09-18 Pierrick LE GALL + + * bug 107 fixed: crash when logging visit on a category containing + "'" character. Correction reported from branch 1.4 + + * bug fixed: in admin/stats, incorrect SQL queries gave no result. + +2005-09-18 Pierrick LE GALL + + * bug 101 fixed: "problem with IE search on keywords". correction + reported from branch 1.4 + +2005-09-17 Pierrick LE GALL + + * new: automatic new password sent by mail when requested by user + +2005-09-17 Pierrick LE GALL + + * improvement: add information about how to use an external table + for users + + * bug fixed: uses user configuration fields for filtering in + admin/user_list + + * bug fixed: don't try to create feeds automatically during + sync_users (when line in user_infos is missing) + + * bug fixed: create_user_infos function gives status admin if user + id matches $conf['webmaster_id'] + +2005-09-17 Pierrick LE GALL + + * new: the number of elements waiting for validation is notified + in RSS feed. + +2005-09-17 Pierrick LE GALL + + * translation: common and admin strings translated in french from + english files + +2005-09-14 Pierrick LE GALL + + * improvement: long localized messages are in HTML files instead + of $lang array. This is the case of admin/help and about pages. + + * deletion: of unused functions (ts_to_mysqldt, is_image, + TN_exists, check_date_format, date_convert, + get_category_directories, get_used_metadata_list, array_remove, + pwg_write_debug, get_group_restrictions, + get_all_group_restrictions, is_group_allowed, style_select, + deprecated_getAttribute). + + * new: many new contextual help pages to replace descriptions + previously included in pages. + + * modification: reorganisation of language files. Deletion of + unused language keys, alphabetical sort. No faq.lang.php anymore + (replaced by help.html). Only done for en_UK.iso-8859-1. + +2005-09-03 Pierrick LE GALL + + * bug fixed : no display of first added element date in + admin/intro if no element in the gallery. + +2005-09-03 Pierrick LE GALL + + * new : template yoga, made by yoDan, helped by chrisaga for + integration becomes the official template. + +2005-09-03 Pierrick LE GALL + + * modification : less configuration parameters in administration + screen. These parameters are move to + include/config_default.inc.php. + + * new : ability to add a single picture to caddie from picture.php + + * new : contextual help, only a few pages are available. + + * new : ability to delete users from admin/user_list + + * modification : reorganization of configuration file + + * new : configuration parameter use_exif_mapping + + * improvement : MOD hidemail added to standard + +2005-08-26 Pierrick LE GALL + + * new : HTML BODY identifier to let CSS stylesheets manage + specific behaviour. + + * deletion : admin/search useless + + * improvement : in admin/user_list, special behaviour for + true/false fields (expand, show_comments) + + * new : gallery_title and gallery_description are displayed at the + top of each page. + + * improvement : simplification in HTML for categories menu. + + * improvement : standardization of presentation in all public + pages (identification, registration, search, profile, + notification, comments, etc.) + +2005-08-25 Pierrick LE GALL + + * deletion : no mail notification anymore. Feature replaced by RSS + feed notification. + + * improvement : on waiting pictures management. Ability to + validate all or reject all in one clic. + +2005-08-21 Pierrick LE GALL + + * modification : adaptation of template variables and blocks in + comments page to display comment by comment instead of picture by + picture. + +2005-08-20 Pierrick LE GALL + + * improvement : dedicated page for user comments validation/reject + in administration. (screen is not shared with public part of the + gallery). Ability to validate all or reject all in one clic. + +2005-08-19 Pierrick LE GALL + + * improvement : less compact presentation of screen + admin/element_set_unit. + +2005-08-19 Pierrick LE GALL + + * improvement : standardization of categories navigation bar on + top of administration screen element_set_(global|unit), + cat_modify, cat_list, cat_perm. + + * new : direct link to admin/cat_modify from category.php. + +2005-08-19 Pierrick LE GALL + + * modification : RSS feed work only with a given feed + identifier. Thus we can avoid fixed frequency notification to + concentrate on variable frequency notification, which is much more + interesting. To do this, feeds have moved to a dedicated table + allowing each user (including guest user) to have more than on + feed. + +2005-08-18 Pierrick LE GALL + + * bug 133 fixed : (report from branch 1.4) Deleting user favorites + is too restrictive. Instead of deleting a favorite because it + belongs to at least one forbidden category, a favorite is deleted + if it belongs to no authorized category (which was the expected + behaviour). + +2005-08-18 Pierrick LE GALL + + * bug 134 fixed : "Nb of images incorectly rendered in "tool tip" + near category in category menu". Correction reported (and + improved) from branch 1.4 + +2005-08-18 Pierrick LE GALL + + * improvement : screen admin/picture_modify + rewritten. Presentation copied from admin/cat_modify : fieldsets + regroup fields. Ability to synchronize metadata for the displayed + item. + + * bug 110 fixed : "return to element view from element edition + fails depending on permissions". If a reachable (for the connected + admin) category is available, a "jump to" link is displayed, by + default, using the category given in URL. + + * bug fixed : in mass_updates function, the first item of + $fields['update'] has not always 0 for id (as in any array). + + * modification : get_keywords function understands spaces as + separator, allow less than 3 chars keywords, allow quotes. + + * new : ability to allow HTML in picture or category description + (false by default) + +2005-08-17 Pierrick LE GALL + + * improvement : in admin/user_perm, already authorized categories + thanks to group associations are displayed and not taken into + account for user specific permissions. + +2005-08-17 Pierrick LE GALL + + * modification : major simplification of admin.php. Titles are + managed by included page, localized items are managed directly in + the template. + + * new : sub template admin/double_select is included in templates + admin/cat_options, admin/user_perm and admin/group_perm. I haven't + been able to use it in admin/picture_modify because it seems + impossible to have two instance of the same sub-template without + interfering. + + * modification : bug 99, in profile manager, no auto submit when + changing language (useless and generate accessibility problem). + + * improvement : HTML semantically correct for administration menu, + simpler syntax, less tags, correct tags (dl/dt/dd instead of + div/div). + + * modification : number of waiting elements and unvalidated + comments are displayed in admin/intro instead of administration + menu (with a link to the dedicated pages). + + * deletion : no link to profile from admin/user_list anymore (no + need). + +2005-08-16 Pierrick LE GALL + + * modification : admin/group_list screen completely rewrite to + present the list of existing groups and a form to add a new + group. Here you can delete a group, go to permissions management + for a group, go to member list of a group (on admin/user_list with + a filter on group). + + * modification : admin/user_perm and admin/group_perm are not + directly reachable by the admin menu anymore. Only the user/group + list lets you reach user/group permissions management screen. + +2005-08-15 Pierrick LE GALL + + * new : introduction page to administration section. This page + gives informations about PhpWebGallery version, PHP version, MySQL + version, gallery database informations (number of categories, + elements, users, comments). Ability to request phpwebgallery.net + for upgrade. + + * deletion : of obsolete admin/admin_phpinfo.php page replaced by + a link in introduction page. + +2005-08-14 Pierrick LE GALL + + * modification : simplification of HTML/CSS code for double select + screen to manage categories properties (admin/cat_options) + +2005-08-14 Pierrick LE GALL + + * new : ability to set an element as representant of its category + directly from picture.php screen. + + * improvement : dedicated icon to add elements into caddie. Ths + icon is displayed in the category title bar. + +2005-08-14 Pierrick LE GALL + + * new : maintenance screen in administration. There you can update + categories informations (number of images, date of the last added + element), update images informations (path, average rate), purge + obsolete sessions, purge history. + + * new : ability to have random representative for categories. This + configuration parameter is set to false by default. + + * new : ability to set an element as representative of a category + without belonging to the category. Thus, administrator can choose + representative even for empty categories. + + * improvement : semantically superior design for category edition + screen by regrouping fields in fieldsets. The improved screen + contains action buttons as in category list screen. + + * new : ability to move a virtual category (ie change its parent + category). + + * bug fixed : the sync_users function checks all user children + tables (access, cache, group association). + +2005-08-08 Pierrick LE GALL + + * new : external authentication in another users table. Previous + users table is divided between users (common properties with any + web application) and user_infos (phpwebgallery specific + informations). External table and fields can be configured. + + * modification : profile.php is not reachable through + administration anymore (not useful). + + * modification : in profile.php, current password is mandatory + only if user tries to change his password. Username can't be + changed. + + * deletion : of obsolete functions get_user_restrictions, + update_user_restrictions, get_user_all_restrictions, + is_user_allowed, update_user + + * modification : $user['forbidden_categories'] equals at least + "-1" so that category_id NOT IN ($user['forbidden_categories']) + can always be used. + + * modification : user_forbidden table becomes user_cache so that + not only restriction informations can be stored in this table. + +2005-07-17 Pierrick LE GALL + + * improvement : in admin/element_set_global, javascript is not + used anymore to select an item with its thumbnail + +2005-07-17 Pierrick LE GALL + + * bug fixed : in admin/user_list, if target is "selection" and + that no user is selected, an error occurs + +2005-07-17 Pierrick LE GALL + + * new feature : use Apache authentication. If + $conf['apache_authentication'] is set true : if no user matches + $_SERVER['REMOTE_USER'] in "users" table, PWG automatically + creates one. This way, users can customize the behaviour of the + application. + + * template : new organisation of identification menu + (category.php). Simplification is required for Apache + authentication (no logout link even if user is externally logged + in) + + * new : usernames can contain quotes (required because Apache + authentication authorized quotes in usernames) + +2005-07-17 Pierrick LE GALL + + * new configuration parameter : hide thumbnail captions on main + page with $conf['show_thumbnail_caption'] + + * new configuration parameter : hide picture name in title on + picture presentation page with $conf['show_picture_name_on_title'] + + * template : new CSS classes to manage picture.php title + +2005-07-16 Pierrick LE GALL + + * new feature : RSS notification feed. Feed generator is an + external tool (FeedCreator class v1.7.2). New file feed.php + + * new database field : comments.validation_date (datetime). This + field is required for notification feed. + + * new database field : users.feed_id (varchar(50)). users.feed_id + is an alias of users.id but is much more complicated to find (50 + characters, figures or letters, case sensitive) : the purpose is + to keep it secret (as far as possible). + + * new database field : users.last_feed_check (datetime) + + * new database field : users.registration_date (datetime) + + * bug fixed : no need to add the (unavailable) session id to + install.php in the installation form. + + * modified database field : images.date_available become more + precise (date to datetime). This precision is needed for + notification feed. + + * new index : comments_i1 (validation_date). Might be useful for + feed queries. + + * new index : comments_i2 (image_id). Useful each time you want to + have informations about an element and its associated comments. + + * version 9.11 of mysqldump outputs database field names and table + names with backquote "`" (didn't find how to take them off) + +2005-06-30 Pierrick LE GALL + + * category permissions management comes back! (it disappeared in + branch 1.4) This time, it is designed to support better long users + list. On this screen, for a particular category, admin can say + which groups and users are permitted. + +2005-06-30 Pierrick LE GALL + + * users managment : change display of filter (according to filter + on user comments) + +2005-06-30 Pierrick LE GALL + + * categories management : new display with icon for actions + (delete, sub-categories, elements, edit, jump to, permissions) + + * categories management : semantic HTML layout (using common + lists) + + * categories management : new way to order categories of the same + level : a text field let the admin reorder all categories at once. + +2005-06-25 Pierrick LE GALL + + * new feature : ability to add links on the main page (see + include/config_default.inc.php) + +2005-06-21 Pierrick LE GALL + + * comments page rewritten : comments are displayed one by one, + with filters and display options available. The list of comments + is paginated. + +2005-06-21 Pierrick LE GALL + + * direct communication between templates and language items, + without needing a mapping in the PHP code. + +2005-06-21 Pierrick LE GALL + + * new function get_name_from_file to centralize the construction + of displayed name from the filename + + * new function l10n which returns the corresponding value from + $lang if existing. Else, the key is returned. This means that if a + language item is not translated, the key is displayed instead + (better than nothing). + +2005-06-11 Pierrick LE GALL + + * errors and informations boxes : management centralized in + admin.php, $errors and $infos arrays replaced by $page['errors'] + and $page['infos'], special management for admin/update.php (more + complex management) + +2005-06-11 Pierrick LE GALL + + * bug 96 (informations given by uploaders are lost) correction + reported from branch 1.4 + +2005-05-10 Pierrick LE GALL + + * user list : links to profile page and permissions page are + represented by icons (more compact) + + * user list : ability to associate to a group or to dissociate + from a group a list of selected users + + * user list : ability to set user properties in "batch" mode (a + selection of users at once) + + * user list : alternate background color for each line + +2005-04-30 Pierrick LE GALL + + * user list updated : ability to filter list on status. Function + get_enums comes back to retrieve the list of possible status in + the database. + +2005-04-28 Pierrick LE GALL + + * user list updated : ability to filter list on group + +2005-04-25 Pierrick LE GALL + + * include/config.inc.php becomes include/config_default.inc.php : + this file should not be modified. A new file + include/config_local.inc.php can be used for overwriting + configuration parameters + +2005-04-25 Pierrick LE GALL + + * come back to previous version of include/constants.php : + %PWGVERSION% was not a mistake + +2005-04-25 Pierrick LE GALL + + * profile.php is no longer used for listing users : + admin/user_list.php comes back (as in 1.3 branch) + + * user list updated : ability to filter list on username + +2005-04-25 Gweltas + + * ability to install even if file include/mysql.inc.php doesn't + exist + + * monthly statistics + + * installation labels updated (english only) + +2005-04-16 Pierrick LE GALL + + * elements batch management : element_set page becomes the + frontend to element_set_global and element_set_unit, infos_images + (after a long time of use) become deprecated : the more powerful + element_set is used instead. Consequently, batch management + concerns caddie but also "normal categories". + + * refactoring code in admin.php to include the sub-file (clearer) + + * caddie : function fill_caddie replaces the code in category.php + and can be used in admin/element_set.php + + * caddie : caddie table is added in delete_elements function + +2005-04-16 Pierrick LE GALL + + * elements batch management : in addition to global mode, a unit + mode is added : ability to manage a set of elements, element by + element. This screen is very close to the existing "infos_images" + (which will soon disappear). + + * elements batch management : in screen element_set_global, the + display options are displayed at the top as in element_set_unit + +2005-04-11 Pierrick LE GALL + + * functions get_day_list and get_month_list moved from search.php + to include/functions.inc.php : these functions are now also used + in admin/element_set_global.php + + * elements batch management improved : ability to set the number + of elements to display per line, ability to set {author, name, + creation date} fields, ability to add and remove keywords, ability + to take selected elements out of caddie + +2005-03-31 Pierrick LE GALL + + * apply category name and element name separation in calendar + special category + + * change method of counting total number of viewable pictures : + pictures linked to more than one category are not counted twice. + +2005-03-26 Pierrick LE GALL + + * "add to caddie" link is visible only when categories contains + elements. Only admin users can see this link + + * elements batch management : impossible to create a link between + category and element that already exists + + * logical separation of category name under thumbnail and element + name + +2005-03-25 Pierrick LE GALL + + * application version is defined at build or release + creation. This way, include/constants.php won't change at each + build. + +2005-03-25 Pierrick LE GALL + + * typo fixed : wrong block name closed in template + +2005-03-25 Pierrick LE GALL + + * new feature : caddie. The purpose is batch management, + especially concerning elements to categories associations.This is + the very first release, needs many improvements. diff --git a/BSF/doc/README_en.txt b/BSF/doc/README_en.txt new file mode 100644 index 000000000..91b5eecc8 --- /dev/null +++ b/BSF/doc/README_en.txt @@ -0,0 +1,105 @@ +============= +Piwigo +============= + +http://piwigo.org + + +Installation +============ + +1. extract files from the downloaded file (using tar or unzip command, or + softwares like 7-zip or winzip) + +2. place de source files on your website in the directory of your choice + ("gallery" for example) + +3. go to the URL http://your.domain/gallery/install.php and follow the + instructions of installation + +Upgrade +======= + +1. elements to save : + + - file "include/mysql.inc.php" + - file "include/config_local.inc.php" + - file "template-common/local-layout.css" + - file "template/yoga/local-layout.css" + - directory "galleries" + - any optional theme or extension you have intalled + - your database (create a dump, using PhpMyAdmin for instance) + +2. delete all files and directories of your previous installation (but not + the previous listed elements) + +3. extract files from the downloaded file (using tar or unzip command, or + softwares like 7-zip or winzip) + +4. upload all the new version files to your website but the previous listed + elements. The only elements coming from the previous installed version + are the elements listed above. + +5. go to the URL http://your.domain/gallery/upgrade.php and follow the + instructions + +How to start +============ + +Once installed or upgraded, your gallery is ready to run. Start by +displaying the installation directory in your browser : + +http://your.domain/gallery + +Then identify as an administrator. A new link in Identification menu of main +page will appear : Administration. Enter the administration panel. + +In the administration panel, take all your time for reading instructions +explaining how to use your gallery. + +Communication +============= + +Newsletter +---------- + +https://gna.org/mail/?group=phpwebgallery + +It is *highly* recommended to subscribe to Piwigo newsletter. This is +extremely low-traffic, but will provide you with announcements of new +Piwigo releases and serious bug notification. You will find available +mailing lists at this URL : + +No spam, no commercial use. + +Freshmeat +--------- + +http://freshmeat.net/projects/phpwebgallery + +Want to stay informed at each release, stable and development +release. Development releases notification are not send in the newsletter. + +Bugtracker +---------- + +http://bugs.phpwebgallery.net + +Bugs and change requests tracking. The best way to have your bug corrected: +it won't be forgotten (as in the forum). + +Wiki +---- + +http://phpwebgallery.net/doc + +Wiki documentation: everyone can participate to improve documentation +content. + +Message board +------------- + +http://forum.phpwebgallery.net + +All communications (installation help, technical discussions) that can't be +done in other channels. diff --git a/BSF/doc/README_fr.txt b/BSF/doc/README_fr.txt new file mode 100644 index 000000000..2915c1253 --- /dev/null +++ b/BSF/doc/README_fr.txt @@ -0,0 +1,116 @@ +============= +Piwigo +============= + +http://piwigo.org + +Installation +============ + +1. décompresser ŕ l'aide de winzip par exemple (winrar, winace et beaucoup + d'autres le permettent également) le fichier téléchargé. + +2. placer les fichiers décompressés sur votre serveur web dans le répertoire + de votre choix ("galerie" par exemple) + +3. se rendre ŕ l'URL http://votre.domaine/galerie/install.php et suivre les + instructions + +Mise ŕ jour +=========== + +1. éléments ŕ sauvegarder : + + - fichier "include/mysql.inc.php" + - fichier "include/config_local.inc.php" + - fichier "template-common/local-layout.css" + - fichier "template/yoga/local-layout.css" + - répertoire "galleries" + - éventuellement thčmes supplémentaires et extensions + - votre base de données (en créant un dump, avec PhpMyAdmin par exemple) + +2. supprimer tous les fichiers et répertoires de la précédente installation + (sauf les éléments listés ci-dessus) + +3. décompresser ŕ l'aide de winzip par exemple (winrar, winace et beaucoup + d'autres le permettent également) le fichier téléchargé. + +4. placer tous les fichiers de la nouvelle version sur votre site web sauf + pour les élements listés ci-dessus. Les seuls éléments venant de la + précédente installation sont ceux listés ci-dessus. + +5. se rendre ŕ l'URL http://votre.domaine/galerie/upgrade.php et suivre les + instructions + +Comment commencer +================= + +Une fois installée ou mise ŕ jour, votre galerie est pręte ŕ +fonctionner. Commencez par vous rendre sur le répertoire d'installation dans +votre navigateur : + +http://votre.domaine/galerie + +Ensuite, identifiez-vous en tant qu'un administrateur. Un nouveau lien dans +le menu d'identification de la page principale va apparaître : +Administration. Suivre ce lien :-) + +Dans la zone d'administration, prenez tout le temps nécessaire pour +consulter les instructions, expliquant comment utiliser votre galerie. + +Communication +============= + +Newsletter +---------- + +https://gna.org/mail/?group=phpwebgallery + +Il est *fortement* recommandé de souscrire ŕ la newsletter de +Piwigo. Trčs peu de mails sont envoyés, mais les informations sont +importantes : nouvelles versions de l'application, notification de bugs +importants (relatifs ŕ la sécurité). Vous trouverez les listes de +discussions disponibles sur la page suivante : + +Pas de spam, pas d'utilisation commerciale. + +Freshmeat +--------- + +http://freshmeat.net/projects/phpwebgallery + +Permet d'ętre au courant des sorties de toutes les releases, et en +exclusivité les builds de la branche de développement (ce qui n'est pas +prévu sur les mailing lists "announce"). + +Outil de suivi de bogues +------------------------ + +http://bugs.phpwebgallery.net + +Gestion des bugs, mais aussi demande de nouvelles fonctionnalités. Rien de +plus efficace pour qu'un bug soit corrigé : tant qu'il ne l'est pas, la +"fiche" reste lŕ ŕ attendre, on ne l'oublie pas comme un topic sur le +forum. + +Les demandes d'évolutions sont également gérées dans cet outil. Ce n'est pas +forcément idéal car il ne s'agit pas de la męme chose, mais le suivi du dev +d'une nouvelle fonctionnalité peut se modéliser de la męme façon que le +suivi de la correction d'un bug. + +Wiki +---- + +http://phpwebgallery.net/doc + +Documentation suivant le systčme du wiki. Chacun peut participer ŕ +l'amélioration de la doc. + +Forum de discussion +------------------- + +http://forum.phpwebgallery.net + +Un forum est disponible et recommandé pour toutes les questions autres que +les demandes d'évolution et rapport de bogue (installation, discussions +techniques). diff --git a/BSF/doc/index.php b/BSF/doc/index.php new file mode 100644 index 000000000..c15b15795 --- /dev/null +++ b/BSF/doc/index.php @@ -0,0 +1,30 @@ + diff --git a/BSF/feed.php b/BSF/feed.php new file mode 100644 index 000000000..3c435cff1 --- /dev/null +++ b/BSF/feed.php @@ -0,0 +1,202 @@ +'.generate_key(50).''; +if ( !empty($feed_id) ) +{ + $query = ' +SELECT user_id, + last_check + FROM '.USER_FEED_TABLE.' + WHERE id = \''.$feed_id.'\' +;'; + $feed_row = mysql_fetch_assoc(pwg_query($query)); + if ( empty($feed_row) ) + { + page_not_found('Unknown/missing feed identifier'); + } + if ($feed_row['user_id']!=$user['id']) + { // new user + $user = build_user( $feed_row['user_id'], true ); + } +} +else +{ + $image_only = true; + if (!is_a_guest()) + {// auto session was created - so switch to guest + $user = build_user( $conf['guest_id'], true ); + } +} + +// Check the status now after the user has been loaded +check_status(ACCESS_GUEST); + +list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();')); + +include_once(PHPWG_ROOT_PATH.'include/feedcreator.class.php'); + +set_make_full_url(); + +$rss = new UniversalFeedCreator(); +$rss->encoding=get_pwg_charset(); +$rss->title = $conf['gallery_title']; +$rss->title.= ' (as '.$user['username'].')'; + +$rss->link = $conf['gallery_url']; + +// +-----------------------------------------------------------------------+ +// | Feed creation | +// +-----------------------------------------------------------------------+ + +$news = array(); +if (!$image_only) +{ + $news = news($feed_row['last_check'], $dbnow, true, true); + + if (count($news) > 0) + { + $item = new FeedItem(); + $item->title = sprintf(l10n('New on %s'), + format_date($dbnow, 'mysql_datetime') ); + $item->link = $conf['gallery_url']; + + // content creation + $item->description = '
    '; + foreach ($news as $line) + { + $item->description.= '
  • '.$line.'
  • '; + } + $item->description.= '
'; + $item->descriptionHtmlSyndicated = true; + + $item->date = mysqldt_to_ts($dbnow); + $item->author = 'Piwigo notifier'; + $item->guid= sprintf('%s', $dbnow);; + + $rss->addItem($item); + + $query = ' +UPDATE '.USER_FEED_TABLE.' + SET last_check = \''.$dbnow.'\' + WHERE id = \''.$feed_id.'\' +;'; + pwg_query($query); + } +} + +if ( !empty($feed_id) and empty($news) ) +{// update the last check from time to time to avoid deletion by maintenance tasks + if ( !isset($feed_row['last_check']) + or time()-mysqldt_to_ts($feed_row['last_check']) > 30*24*3600 ) + { + $query = ' +UPDATE '.USER_FEED_TABLE.' + SET last_check = DATE_ADD(\''.$dbnow.'\', INTERVAL -15 DAY ) + WHERE id = \''.$feed_id.'\' +;'; + pwg_query($query); + } +} + +$dates = get_recent_post_dates_array($conf['recent_post_dates']['RSS']); + +foreach($dates as $date_detail) +{ // for each recent post date we create a feed item + $item = new FeedItem(); + $date = $date_detail['date_available']; + $item->title = get_title_recent_post_date($date_detail); + $item->link = make_index_url( + array( + 'chronology_field' => 'posted', + 'chronology_style'=> 'monthly', + 'chronology_view' => 'calendar', + 'chronology_date' => explode('-', substr($date,0,10) ) + ) + ); + + $item->description .= + ''.$conf['gallery_title'].'
'; + + $item->description .= get_html_description_recent_post_date($date_detail); + + $item->descriptionHtmlSyndicated = true; + + $item->date = mysqldt_to_ts($date); + $item->author = 'Piwigo notifier'; + $item->guid= sprintf('%s', 'pics-'.$date);; + + $rss->addItem($item); +} + +$fileName= $conf['local_data_dir'].'/tmp'; +@mkdir($fileName); // just in case +$fileName.='/feed.xml'; +// send XML feed +echo $rss->saveFeed('RSS2.0', $fileName, true); +?> \ No newline at end of file diff --git a/BSF/galleries/.cvsignore b/BSF/galleries/.cvsignore new file mode 100644 index 000000000..72e8ffc0d --- /dev/null +++ b/BSF/galleries/.cvsignore @@ -0,0 +1 @@ +* diff --git a/BSF/galleries/index.php b/BSF/galleries/index.php new file mode 100644 index 000000000..c15b15795 --- /dev/null +++ b/BSF/galleries/index.php @@ -0,0 +1,30 @@ + diff --git a/BSF/identification.php b/BSF/identification.php new file mode 100644 index 000000000..877e51a65 --- /dev/null +++ b/BSF/identification.php @@ -0,0 +1,93 @@ +set_filenames( array('identification'=>'identification.tpl') ); + +$template->assign( + array( + 'U_LOST_PASSWORD' => get_root_url().'password.php', + 'U_REDIRECT' => $redirect_to, + + 'F_LOGIN_ACTION' => get_root_url().'identification.php', + 'authorize_remembering' => $conf['authorize_remembering'], + )); + +if ($conf['allow_user_registration']) +{ + $template->assign('U_REGISTER', get_root_url().'register.php' ); +} + +//-------------------------------------------------------------- errors display +if ( sizeof( $errors ) != 0 ) +{ + $template->assign('errors', $errors); +} + +//----------------------------------------------------------- html code display +$template->pparse('identification'); +include(PHPWG_ROOT_PATH.'include/page_tail.php'); +?> diff --git a/BSF/include/calendar_base.class.php b/BSF/include/calendar_base.class.php new file mode 100644 index 000000000..bd3d2b180 --- /dev/null +++ b/BSF/include/calendar_base.class.php @@ -0,0 +1,351 @@ +date_field = 'date_available'; + } + else + { + $this->date_field = 'date_creation'; + } + $this->inner_sql = $inner_sql; + } + + function get_display_name() + { + global $conf, $page; + $res = ''; + + for ($i=0; $i$chronology_date ), + array( 'start' ) + ); + $res .= + '' + .$this->get_date_component_label($i, $page['chronology_date'][$i]) + .''; + } + else + { + $res .= + '' + .$this->get_date_component_label($i, $page['chronology_date'][$i]) + .''; + } + } + return $res; + } + +//--------------------------------------------------------- private members --- + /** + * Returns a display name for a date component optionally using labels + */ + function get_date_component_label($level, $date_component) + { + $label = $date_component; + if (isset($this->calendar_levels[$level]['labels'][$date_component])) + { + $label = $this->calendar_levels[$level]['labels'][$date_component]; + } + elseif ('any' === $date_component ) + { + $label = l10n('calendar_any'); + } + return $label; + } + + /** + * Gets a nice display name for a date to be shown in previos/next links. + */ + function get_date_nice_name($date) + { + $date_components = explode('-', $date); + $res = ''; + for ($i=count($date_components)-1; $i>=0; $i--) + { + if ('any' !== $date_components[$i]) + { + $label = $this->get_date_component_label($i, $date_components[$i] ); + if ( $res!='' ) + { + $res .= ' '; + } + $res .= $label; + } + } + return $res; + } + + /** + * Creates a calendar navigation bar. + * + * @param array date_components + * @param array items - hash of items to put in the bar (e.g. 2005,2006) + * @param string class_prefix - html class attribute prefix for span elements + * @param bool show_any - adds any link to the end of the bar + * @param bool show_empty - shows all labels even those without items + * @param array labels - optional labels for items (e.g. Jan,Feb,...) + * @return string the navigation bar + */ + function get_nav_bar_from_items($date_components, $items, + $class_prefix, $show_any, + $show_empty=false, $labels=null) + { + global $conf, $page; + + $nav_bar = ''; + + if ($conf['calendar_show_empty'] and $show_empty and !empty($labels) ) + { + foreach ($labels as $item => $label) + { + if ( ! isset($items[$item]) ) + { + $items[$item] = -1; + } + } + ksort($items); + } + + foreach ($items as $item => $nb_images) + { + $label = $item; + if (isset($labels[$item])) + { + $label = $labels[$item]; + } + if ($nb_images==-1) + { + $nav_bar .= ''; + $nav_bar .= $label; + } + else + { + $nav_bar .= ''; + $url = duplicate_index_url( + array('chronology_date'=>array_merge($date_components,array($item))), + array( 'start' ) + ); + $nav_bar .= ''; + $nav_bar .= $label; + $nav_bar .= ''; + } + if ($nb_images > 0) + { + $nav_bar .= '('.$nb_images.')'; + } + $nav_bar.= ''; + } + + if ($conf['calendar_show_any'] and $show_any and count($items)>1 and + count($date_components)calendar_levels)-1 ) + { + $label = l10n('calendar_any'); + $nav_bar .= ''; + $url = duplicate_index_url( + array('chronology_date'=>array_merge($date_components,array('any'))), + array( 'start' ) + ); + $nav_bar .= ''; + $nav_bar .= $label; + $nav_bar .= ''; + $nav_bar.= ''; + } + return $nav_bar; + } + + /** + * Creates a calendar navigation bar for a given level. + * + * @param int level - the level (0-year,1-month/week,2-day) + * @return void + */ + function build_nav_bar($level, $labels=null) + { + global $template, $conf, $page; + + $query = ' +SELECT DISTINCT('.$this->calendar_levels[$level]['sql'] + .') as period'; + $query.= $this->inner_sql; + $query.= $this->get_date_where($level); + $query.= ' + GROUP BY period +;'; + + $level_items = array(); + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $level_items[$row['period']] = 0; + } + + if ( count($level_items)==1 and + count($page['chronology_date'])calendar_levels)-1) + { + if ( ! isset($page['chronology_date'][$level]) ) + { + list($key) = array_keys($level_items); + $page['chronology_date'][$level] = (int)$key; + + if ( $levelcalendar_levels)-1 ) + { + return; + } + } + } + + $dates = $page['chronology_date']; + while ($levelget_nav_bar_from_items( + $dates, + $level_items, + 'calItem', + true, + true, + isset($labels) ? $labels : $this->calendar_levels[$level]['labels'] + ); + + $template->append( + 'chronology_navigation_bars', + array( + 'CONTENT' => $nav_bar, + ) + ); + } + + /** + * Assigns the next/previous link to the template with regards to + * the currently choosen date. + */ + function build_next_prev() + { + global $template, $page; + $prev = $next =null; + if ( empty($page['chronology_date']) ) + return; + $query = 'SELECT CONCAT_WS("-"'; + for ($i=0; $icalendar_levels[$i]['sql']; + } + } + $current = implode('-', $page['chronology_date'] ); + + $query.=') as period' . $this->inner_sql .' +AND ' . $this->date_field . ' IS NOT NULL +GROUP BY period'; + + $upper_items = array_from_query( $query, 'period'); + + usort($upper_items, 'version_compare'); + $upper_items_rank = array_flip($upper_items); + if ( !isset($upper_items_rank[$current]) ) + { + array_push($upper_items, $current);// just in case (external link) + usort($upper_items, 'version_compare'); + $upper_items_rank = array_flip($upper_items); + } + $current_rank = $upper_items_rank[$current]; + + $tpl_var = array(); + + if ( $current_rank>0 ) + { // has previous + $prev = $upper_items[$current_rank-1]; + $chronology_date = explode('-', $prev); + $tpl_var['previous'] = + array( + 'LABEL' => $this->get_date_nice_name($prev), + 'URL' => duplicate_index_url( + array('chronology_date'=>$chronology_date), array('start') + ) + ); + } + + if ( $current_rank < count($upper_items)-1 ) + { // has next + $next = $upper_items[$current_rank+1]; + $chronology_date = explode('-', $next); + $tpl_var['next'] = + array( + 'LABEL' => $this->get_date_nice_name($next), + 'URL' => duplicate_index_url( + array('chronology_date'=>$chronology_date), array('start') + ) + ); + } + + if ( !empty($tpl_var) ) + { + $existing = & $template->get_template_vars('chronology_navigation_bars'); + if ( !empty($existing) ) + { + $existing[ sizeof($existing)-1 ] = + array_merge( $existing[ sizeof($existing)-1 ], $tpl_var); + } + else + { + $template->append( 'chronology_navigation_bars', $tpl_var ); + } + } + } +} +?> diff --git a/BSF/include/calendar_monthly.class.php b/BSF/include/calendar_monthly.class.php new file mode 100644 index 000000000..b29997cef --- /dev/null +++ b/BSF/include/calendar_monthly.class.php @@ -0,0 +1,515 @@ +calendar_levels = array( + array( + 'sql'=> 'YEAR('.$this->date_field.')', + 'labels' => null + ), + array( + 'sql'=> 'MONTH('.$this->date_field.')', + 'labels' => $lang['month'] + ), + array( + 'sql'=> 'DAYOFMONTH('.$this->date_field.')', + 'labels' => null + ), + ); + } + +/** + * Generate navigation bars for category page + * @return boolean false to indicate that thumbnails + * where not included here, true otherwise + */ +function generate_category_content() +{ + global $conf, $page; + + $view_type = $page['chronology_view']; + if ($view_type==CAL_VIEW_CALENDAR) + { + global $template; + $tpl_var = array(); + if ( count($page['chronology_date'])==0 ) + {//case A: no year given - display all years+months + if ($this->build_global_calendar($tpl_var)) + { + $template->assign('chronology_calendar', $tpl_var); + return true; + } + } + + if ( count($page['chronology_date'])==1 ) + {//case B: year given - display all days in given year + if ($this->build_year_calendar($tpl_var)) + { + $template->assign('chronology_calendar', $tpl_var); + $this->build_nav_bar(CYEAR); // years + return true; + } + } + + if ( count($page['chronology_date'])==2 ) + {//case C: year+month given - display a nice month calendar + if ( $this->build_month_calendar($tpl_var) ) + { + $template->assign('chronology_calendar', $tpl_var); + } + $this->build_next_prev(); + return true; + } + } + + if ($view_type==CAL_VIEW_LIST or count($page['chronology_date'])==3) + { + if ( count($page['chronology_date'])==0 ) + { + $this->build_nav_bar(CYEAR); // years + } + if ( count($page['chronology_date'])==1) + { + $this->build_nav_bar(CMONTH); // month + } + if ( count($page['chronology_date'])==2 ) + { + $day_labels = range( 1, $this->get_all_days_in_month( + $page['chronology_date'][CYEAR] ,$page['chronology_date'][CMONTH] ) ); + array_unshift($day_labels, 0); + unset( $day_labels[0] ); + $this->build_nav_bar( CDAY, $day_labels ); // days + } + $this->build_next_prev(); + } + return false; +} + + +/** + * Returns a sql where subquery for the date field + * @param int max_levels return the where up to this level + * (e.g. 2=only year and month) + * @return string + */ +function get_date_where($max_levels=3) +{ + global $page; + $date = $page['chronology_date']; + while (count($date)>$max_levels) + { + array_pop($date); + } + $res = ''; + if (isset($date[CYEAR]) and $date[CYEAR]!=='any') + { + $b = $date[CYEAR] . '-'; + $e = $date[CYEAR] . '-'; + if (isset($date[CMONTH]) and $date[CMONTH]!=='any') + { + $b .= $date[CMONTH] . '-'; + $e .= $date[CMONTH] . '-'; + if (isset($date[CDAY]) and $date[CDAY]!=='any') + { + $b .= $date[CDAY]; + $e .= $date[CDAY]; + } + else + { + $b .= '01'; + $e .= '31'; + } + } + else + { + $b .= '01-01'; + $e .= '12-31'; + if (isset($date[CMONTH]) and $date[CMONTH]!=='any') + { + $res .= ' AND '.$this->calendar_levels[CMONTH]['sql'].'='.$date[CMONTH]; + } + if (isset($date[CDAY]) and $date[CDAY]!=='any') + { + $res .= ' AND '.$this->calendar_levels[CDAY]['sql'].'='.$date[CDAY]; + } + } + $res = " AND $this->date_field BETWEEN '$b' AND '$e 23:59:59'" . $res; + } + else + { + $res = ' AND '.$this->date_field.' IS NOT NULL'; + if (isset($date[CMONTH]) and $date[CMONTH]!=='any') + { + $res .= ' AND '.$this->calendar_levels[CMONTH]['sql'].'='.$date[CMONTH]; + } + if (isset($date[CDAY]) and $date[CDAY]!=='any') + { + $res .= ' AND '.$this->calendar_levels[CDAY]['sql'].'='.$date[CDAY]; + } + } + return $res; +} + + + +//--------------------------------------------------------- private members --- + +// returns an array with alll the days in a given month +function get_all_days_in_month($year, $month) +{ + $md= array(1=>31,28,31,30,31,30,31,31,30,31,30,31); + + if ( is_numeric($year) and $month==2) + { + $nb_days = $md[2]; + if ( ($year%4==0) and ( ($year%100!=0) or ($year%400!=0) ) ) + { + $nb_days++; + } + } + elseif ( is_numeric($month) ) + { + $nb_days = $md[ $month ]; + } + else + { + $nb_days = 31; + } + return $nb_days; +} + +function build_global_calendar(&$tpl_var) +{ + global $page; + assert( count($page['chronology_date']) == 0 ); + $query='SELECT DISTINCT(DATE_FORMAT('.$this->date_field.',"%Y%m")) as period, + COUNT( DISTINCT(id) ) as count'; + $query.= $this->inner_sql; + $query.= $this->get_date_where(); + $query.= ' + GROUP BY period + ORDER BY YEAR('.$this->date_field.') DESC, MONTH('.$this->date_field.')'; + + $result = pwg_query($query); + $items=array(); + while ($row = mysql_fetch_array($result)) + { + $y = substr($row['period'], 0, 4); + $m = (int)substr($row['period'], 4, 2); + if ( ! isset($items[$y]) ) + { + $items[$y] = array('nb_images'=>0, 'children'=>array() ); + } + $items[$y]['children'][$m] = $row['count']; + $items[$y]['nb_images'] += $row['count']; + } + //echo ('
'. var_export($items, true) . '
'); + if (count($items)==1) + {// only one year exists so bail out to year view + list($y) = array_keys($items); + $page['chronology_date'][CYEAR] = $y; + return false; + } + + global $lang; + foreach ( $items as $year=>$year_data) + { + $chronology_date = array( $year ); + $url = duplicate_index_url( array('chronology_date'=>$chronology_date) ); + + $nav_bar = $this->get_nav_bar_from_items( $chronology_date, + $year_data['children'], 'calCal', false, false, $lang['month'] ); + + $tpl_var['calendar_bars'][] = + array( + 'U_HEAD' => $url, + 'NB_IMAGES' => $year_data['nb_images'], + 'HEAD_LABEL' => $year, + 'NAV_BAR' => $nav_bar, + ); + } + return true; +} + +function build_year_calendar(&$tpl_var) +{ + global $page; + assert( count($page['chronology_date']) == 1 ); + $query='SELECT DISTINCT(DATE_FORMAT('.$this->date_field.',"%m%d")) as period, + COUNT( DISTINCT(id) ) as count'; + $query.= $this->inner_sql; + $query.= $this->get_date_where(); + $query.= ' + GROUP BY period'; + + $result = pwg_query($query); + $items=array(); + while ($row = mysql_fetch_array($result)) + { + $m = (int)substr($row['period'], 0, 2); + $d = substr($row['period'], 2, 2); + if ( ! isset($items[$m]) ) + { + $items[$m] = array('nb_images'=>0, 'children'=>array() ); + } + $items[$m]['children'][$d] = $row['count']; + $items[$m]['nb_images'] += $row['count']; + } + if (count($items)==1) + { // only one month exists so bail out to month view + list($m) = array_keys($items); + $page['chronology_date'][CMONTH] = $m; + return false; + } + global $lang; + foreach ( $items as $month=>$month_data) + { + $chronology_date = array( $page['chronology_date'][CYEAR], $month ); + $url = duplicate_index_url( array('chronology_date'=>$chronology_date) ); + + $nav_bar = $this->get_nav_bar_from_items( $chronology_date, + $month_data['children'], 'calCal', false ); + + $tpl_var['calendar_bars'][] = + array( + 'U_HEAD' => $url, + 'NB_IMAGES' => $month_data['nb_images'], + 'HEAD_LABEL' => $lang['month'][$month], + 'NAV_BAR' => $nav_bar, + ); + } + return true; + +} + +function build_month_calendar(&$tpl_var) +{ + global $page; + $query='SELECT DISTINCT(DAYOFMONTH('.$this->date_field.')) as period, + COUNT( DISTINCT(id) ) as count'; + $query.= $this->inner_sql; + $query.= $this->get_date_where(); + $query.= ' + GROUP BY period'; + + $items=array(); + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $d = (int)$row['period']; + $items[$d] = array('nb_images'=>$row['count']); + } + + foreach ( $items as $day=>$data) + { + $page['chronology_date'][CDAY]=$day; + $query = ' +SELECT id, file,tn_ext,path, width, height, DAYOFWEEK('.$this->date_field.')-1 as dow'; + $query.= $this->inner_sql; + $query.= $this->get_date_where(); + $query.= ' + ORDER BY RAND() + LIMIT 0,1'; + unset ( $page['chronology_date'][CDAY] ); + + $row = mysql_fetch_assoc(pwg_query($query)); + $items[$day]['tn_url'] = get_thumbnail_url($row); + $items[$day]['file'] = $row['file']; + $items[$day]['path'] = $row['path']; + $items[$day]['tn_ext'] = @$row['tn_ext']; + $items[$day]['width'] = $row['width']; + $items[$day]['height'] = $row['height']; + $items[$day]['dow'] = $row['dow']; + } + + global $lang, $conf; + + if ( !empty($items) + and $conf['calendar_month_cell_width']>0 + and $conf['calendar_month_cell_height']>0) + { + list($known_day) = array_keys($items); + $known_dow = $items[$known_day]['dow']; + $first_day_dow = ($known_dow-($known_day-1))%7; + if ($first_day_dow<0) + { + $first_day_dow += 7; + } + //first_day_dow = week day corresponding to the first day of this month + $wday_labels = $lang['day']; + + // BEGIN - pass now in week starting Monday + if ($first_day_dow==0) + { + $first_day_dow = 6; + } + else + { + $first_day_dow -= 1; + } + array_push( $wday_labels, array_shift($wday_labels) ); + // END - pass now in week starting Monday + + $cell_width = $conf['calendar_month_cell_width']; + $cell_height = $conf['calendar_month_cell_height']; + + $tpl_weeks = array(); + $tpl_crt_week = array(); + + //fill the empty days in the week before first day of this month + for ($i=0; $i<$first_day_dow; $i++) + { + $tpl_crt_week[] = array(); + } + + for ( $day = 1; + $day <= $this->get_all_days_in_month( + $page['chronology_date'][CYEAR], $page['chronology_date'][CMONTH] + ); + $day++) + { + $dow = ($first_day_dow + $day-1)%7; + if ($dow==0 and $day!=1) + { + $tpl_weeks[] = $tpl_crt_week; // add finished week to week list + $tpl_crt_week = array(); // start new week + } + + if ( !isset($items[$day]) ) + {// empty day + $tpl_crt_week[] = + array( + 'DAY' => $day + ); + } + else + { + $thumb = get_thumbnail_path($items[$day]); + $tn_size = @getimagesize($thumb); + + $tn_width = $tn_size[0]; + $tn_height = $tn_size[1]; + + // now need to fit the thumbnail of size tn_size within + // a cell of size cell_size by playing with CSS position (left/top) + // and the width and height of . + $ratio_w = $tn_width/$cell_width; + $ratio_h = $tn_height/$cell_height; + + $pos_top=$pos_left=0; + $css_style = ''; + + if ( $ratio_w>1 and $ratio_h>1) + {// cell completely smaller than the thumbnail so we will let the browser + // resize the thumbnail + if ($ratio_w > $ratio_h ) + {// thumbnail ratio compared to cell -> wide format + $css_style = 'height:'.$cell_height.'px;'; + $browser_img_width = $cell_height*$tn_width/$tn_height; + $pos_left = ($browser_img_width-$cell_width)/2; + } + else + { + $css_style = 'width:'.$cell_width.'px;'; + $browser_img_height = $cell_width*$tn_height/$tn_width; + $pos_top = ($browser_img_height-$cell_height)/2; + } + } + else + { + $pos_left = ($tn_width-$cell_width)/2; + $pos_top = ($tn_height-$cell_height)/2; + } + + if ( round($pos_left)!=0) + { + $css_style.='left:'.round(-$pos_left).'px;'; + } + if ( round($pos_top)!=0) + { + $css_style.='top:'.round(-$pos_top).'px;'; + } + $url = duplicate_index_url( + array( + 'chronology_date' => + array( + $page['chronology_date'][CYEAR], + $page['chronology_date'][CMONTH], + $day + ) + ) + ); + + $tpl_crt_week[] = + array( + 'DAY' => $day, + 'DOW' => $dow, + 'NB_ELEMENTS' => $items[$day]['nb_images'], + 'IMAGE' => $items[$day]['tn_url'], + 'U_IMG_LINK' => $url, + 'IMAGE_STYLE' => $css_style, + 'IMAGE_ALT' => $items[$day]['file'], + ); + } + } + //fill the empty days in the week after the last day of this month + while ( $dow<6 ) + { + $tpl_crt_week[] = array(); + $dow++; + } + $tpl_weeks[] = $tpl_crt_week; + + $tpl_var['month_view'] = + array( + 'CELL_WIDTH' => $cell_width, + 'CELL_HEIGHT' => $cell_height, + 'wday_labels' => $wday_labels, + 'weeks' => $tpl_weeks, + ); + } + + return true; +} + +} +?> diff --git a/BSF/include/calendar_weekly.class.php b/BSF/include/calendar_weekly.class.php new file mode 100644 index 000000000..2077bc594 --- /dev/null +++ b/BSF/include/calendar_weekly.class.php @@ -0,0 +1,136 @@ +calendar_levels = array( + array( + 'sql'=> 'YEAR('.$this->date_field.')', + 'labels' => null + ), + array( + 'sql'=> 'WEEK('.$this->date_field.')+1', + 'labels' => $week_no_labels, + ), + array( + 'sql'=> 'DAYOFWEEK('.$this->date_field.')-1', + 'labels' => $lang['day'] + ), + ); + //Comment next lines for week starting on Sunday or if MySQL version<4.0.17 + //WEEK(date,5) = "0-53 - Week 1=the first week with a Monday in this year" + $this->calendar_levels[CWEEK]['sql'] = 'WEEK('.$this->date_field.',5)+1'; + $this->calendar_levels[CDAY]['sql'] = 'WEEKDAY('.$this->date_field.')'; + array_push( $this->calendar_levels[CDAY]['labels'], + array_shift( $this->calendar_levels[CDAY]['labels'] ) ); + } + +/** + * Generate navigation bars for category page + * @return boolean false to indicate that thumbnails where not included here + */ +function generate_category_content() +{ + global $conf, $page; + + if ( count($page['chronology_date'])==0 ) + { + $this->build_nav_bar(CYEAR); // years + } + if ( count($page['chronology_date'])==1 ) + { + $this->build_nav_bar(CWEEK, array()); // week nav bar 1-53 + } + if ( count($page['chronology_date'])==2 ) + { + $this->build_nav_bar(CDAY); // days nav bar Mon-Sun + } + $this->build_next_prev(); + return false; +} + + +/** + * Returns a sql where subquery for the date field + * @param int max_levels return the where up to this level + * (e.g. 2=only year and week in year) + * @return string + */ +function get_date_where($max_levels=3) +{ + global $page; + $date = $page['chronology_date']; + while (count($date)>$max_levels) + { + array_pop($date); + } + $res = ''; + if (isset($date[CYEAR]) and $date[CYEAR]!=='any') + { + $y = $date[CYEAR]; + $res = " AND $this->date_field BETWEEN '$y-01-01' AND '$y-12-31 23:59:59'"; + } + + if (isset($date[CWEEK]) and $date[CWEEK]!=='any') + { + $res .= ' AND '.$this->calendar_levels[CWEEK]['sql'].'='.$date[CWEEK]; + } + if (isset($date[CDAY]) and $date[CDAY]!=='any') + { + $res .= ' AND '.$this->calendar_levels[CDAY]['sql'].'='.$date[CDAY]; + } + if (empty($res)) + { + $res = ' AND '.$this->date_field.' IS NOT NULL'; + } + return $res; +} + +} + +?> diff --git a/BSF/include/category_cats.inc.php b/BSF/include/category_cats.inc.php new file mode 100644 index 000000000..e7f9a168a --- /dev/null +++ b/BSF/include/category_cats.inc.php @@ -0,0 +1,298 @@ += SUBDATE( + CURRENT_DATE,INTERVAL '.$user['recent_period'].' DAY + ) +'.get_sql_condition_FandF + ( + array + ( + 'visible_categories' => 'id', + ), + 'AND' + ).' +;'; +} +else +{ + // $user['forbidden_categories'] including with USER_CACHE_CATEGORIES_TABLE + $query = ' +SELECT + id, name, permalink, representative_picture_id, comment, nb_images, uppercats, + date_last, max_date_last, count_images, count_categories + FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' + ON id = cat_id and user_id = '.$user['id'].' + WHERE id_uppercat '. + (!isset($page['category']) ? 'is NULL' : '= '.$page['category']['id']).' +'.get_sql_condition_FandF + ( + array + ( + 'visible_categories' => 'id', + ), + 'AND' + ).' + ORDER BY rank +;'; +} + +$result = pwg_query($query); +$categories = array(); +$category_ids = array(); +$image_ids = array(); + +while ($row = mysql_fetch_assoc($result)) +{ + $row['is_child_date_last'] = @$row['max_date_last']>@$row['date_last']; + + if (isset($row['representative_picture_id']) + and is_numeric($row['representative_picture_id'])) + { // if a representative picture is set, it has priority + $image_id = $row['representative_picture_id']; + } + else if ($conf['allow_random_representative']) + {// searching a random representant among elements in sub-categories + $query = ' +SELECT image_id + FROM '.CATEGORIES_TABLE.' AS c INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic + ON ic.category_id = c.id'; + $query.= ' + WHERE (c.id='.$row['id'].' OR uppercats LIKE \''.$row['uppercats'].',%\')' + .get_sql_condition_FandF + ( + array + ( + 'forbidden_categories' => 'c.id', + 'visible_categories' => 'c.id', + 'visible_images' => 'image_id' + ), + "\n AND" + ).' + ORDER BY RAND() + LIMIT 0,1 +;'; + $subresult = pwg_query($query); + if (mysql_num_rows($subresult) > 0) + { + list($image_id) = mysql_fetch_row($subresult); + } + } + else + { // searching a random representant among representant of sub-categories + $query = ' +SELECT representative_picture_id + FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' + ON id = cat_id and user_id = '.$user['id'].' + WHERE uppercats LIKE \''.$row['uppercats'].',%\' + AND representative_picture_id IS NOT NULL' + .get_sql_condition_FandF + ( + array + ( + 'visible_categories' => 'id', + ), + "\n AND" + ).' + ORDER BY RAND() + LIMIT 0,1 +;'; + $subresult = pwg_query($query); + if (mysql_num_rows($subresult) > 0) + { + list($image_id) = mysql_fetch_row($subresult); + } + } + + if (isset($image_id)) + { + $row['representative_picture_id'] = $image_id; + array_push($image_ids, $image_id); + array_push($categories, $row); + array_push($category_ids, $row['id']); + } + unset($image_id); +} + +if ($conf['display_fromto']) +{ + $dates_of_category = array(); + if (count($category_ids) > 0) + { + $query = ' +SELECT + category_id, + MIN(date_creation) AS date_creation_min, + MAX(date_creation) AS date_creation_max + FROM '.IMAGE_CATEGORY_TABLE.' + INNER JOIN '.IMAGES_TABLE.' ON image_id = id + WHERE category_id IN ('.implode(',', $category_ids).') +'.get_sql_condition_FandF + ( + array + ( + 'visible_categories' => 'category_id', + 'visible_images' => 'id' + ), + 'AND' + ).' + GROUP BY category_id +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $dates_of_category[ $row['category_id'] ] = array( + 'from' => $row['date_creation_min'], + 'to' => $row['date_creation_max'], + ); + } + } +} + +if ($page['section']=='recent_cats') +{ + usort($categories, 'global_rank_compare'); +} +if (count($categories) > 0) +{ + $thumbnail_src_of = array(); + + $query = ' +SELECT id, path, tn_ext + FROM '.IMAGES_TABLE.' + WHERE id IN ('.implode(',', $image_ids).') +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $thumbnail_src_of[$row['id']] = get_thumbnail_url($row); + } +} + +if (count($categories) > 0) +{ + // Update filtered data + if (function_exists('update_cats_with_filtered_data')) + { + update_cats_with_filtered_data($categories); + } + + $template->set_filename('index_category_thumbnails', 'mainpage_categories.tpl'); + + trigger_action('loc_begin_index_category_thumbnails', $categories); + + foreach ($categories as $category) + { + if ($page['section']=='recent_cats') + { + $name = get_cat_display_name_cache($category['uppercats'], null, false); + } + else + { + $name = $category['name']; + } + + $icon_ts = get_icon($category['max_date_last'], $category['is_child_date_last']); + + $tpl_var = + array( + 'ID' => $category['id'], + 'TN_SRC' => $thumbnail_src_of[$category['representative_picture_id']], + 'ALT' => $category['name'], + 'ICON' => $icon_ts, + + 'URL' => make_index_url( + array( + 'category' => $category + ) + ), + 'CAPTION_NB_IMAGES' => get_display_images_count + ( + $category['nb_images'], + $category['count_images'], + $category['count_categories'], + true, + '
' + ), + 'DESCRIPTION' => + trigger_event('render_category_literal_description', + trigger_event('render_category_description', + @$category['comment'], + 'subcatify_category_description')), + 'NAME' => $name, + ); + + if ($conf['display_fromto']) + { + if (isset($dates_of_category[ $category['id'] ])) + { + $from = $dates_of_category[ $category['id'] ]['from']; + $to = $dates_of_category[ $category['id'] ]['to']; + + if (!empty($from)) + { + $info = ''; + + if ($from == $to) + { + $info = format_date($from); + } + else + { + $info = sprintf( + l10n('from %s to %s'), + format_date($from), + format_date($to) + ); + } + $tpl_var['INFO_DATES'] = $info; + } + } + }//fromto + + //plugins need to add/modify sth in this loop ? + $tpl_var = trigger_event('loc_index_category_thumbnail', + $tpl_var, $category ); + + $template->append( 'category_thumbnails', $tpl_var); + } + + trigger_action('loc_end_index_category_thumbnails', $categories); + $template->assign_var_from_handle('CATEGORIES', 'index_category_thumbnails'); +} +?> diff --git a/BSF/include/category_default.inc.php b/BSF/include/category_default.inc.php new file mode 100644 index 000000000..8dad04d90 --- /dev/null +++ b/BSF/include/category_default.inc.php @@ -0,0 +1,170 @@ + 0) +{ + $query = ' +SELECT * + FROM '.IMAGES_TABLE.' + WHERE id IN ('.implode(',', $selection).') +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $row['rank'] = $page['rank_of'][ $row['id'] ]; + + array_push($pictures, $row); + } + + usort($pictures, 'rank_compare'); +} + +if (count($pictures) > 0) +{ + // define category slideshow url + $row = reset($pictures); + $page['cat_slideshow_url'] = + add_url_params( + duplicate_picture_url( + array( + 'image_id' => $row['id'], + 'image_file' => $row['file'] + ), + array('start') + ), + array('slideshow' => + (isset($_GET['slideshow']) ? $_GET['slideshow'] + : '' )) + ); + + if ($user['show_nb_comments']) + { + $query = ' +SELECT image_id, COUNT(*) AS nb_comments + FROM '.COMMENTS_TABLE.' + WHERE validated = \'true\' + AND image_id IN ('.implode(',', $selection).') + GROUP BY image_id +;'; + $nb_comments_of = simple_hash_from_query($query, 'image_id', 'nb_comments'); + } +} + +// template thumbnail initialization +$template->set_filenames( array( 'index_thumbnails' => 'thumbnails.tpl',)); + +trigger_action('loc_begin_index_thumbnails', $pictures); + +foreach ($pictures as $row) +{ + $thumbnail_url = get_thumbnail_url($row); + + // link on picture.php page + $url = duplicate_picture_url( + array( + 'image_id' => $row['id'], + 'image_file' => $row['file'] + ), + array('start') + ); + + $tpl_var = + array( + 'ID' => $row['id'], + 'IMAGE' => $thumbnail_url, + 'IMAGE_ALT' => $row['file'], + 'IMAGE_TITLE' => get_thumbnail_title($row), + 'IMAGE_TS' => get_icon($row['date_available']), + 'U_IMG_LINK' => $url, + ); + + if ($user['show_nb_hits']) + { + $tpl_var['NB_HITS'] = $row['hit']; + } + + if ($conf['show_thumbnail_caption']) + { + // name of the picture + if (isset($row['name']) and $row['name'] != '') + { + $name = $row['name']; + } + else + { + $name = str_replace('_', ' ', get_filename_wo_extension($row['file'])); + } + + switch ($page['section']) + { + case 'best_rated' : + { + $name = '('.$row['average_rate'].') '.$name; + break; + } + case 'most_visited' : + { + if ( !$user['show_nb_hits']) { + $name = '('.$row['hit'].') '.$name; + } + break; + } + } + + $tpl_var['ELEMENT_NAME'] = $name; + } + + if ( isset($nb_comments_of) ) + { + $row['nb_comments'] = isset($nb_comments_of[$row['id']]) + ? (int)$nb_comments_of[$row['id']] : 0; + $tpl_var['NB_COMMENTS'] = $row['nb_comments']; + } + + //plugins need to add/modify sth in this loop ? + $tpl_var = trigger_event('loc_index_thumbnail', $tpl_var, $row); + + $template->append('thumbnails', $tpl_var); +} + +trigger_action('loc_end_index_thumbnails', $pictures); +$template->assign_var_from_handle('THUMBNAILS', 'index_thumbnails'); + +pwg_debug('end include/category_default.inc.php'); +?> diff --git a/BSF/include/class_smtp_mail.inc.php b/BSF/include/class_smtp_mail.inc.php new file mode 100644 index 000000000..06ef69efd --- /dev/null +++ b/BSF/include/class_smtp_mail.inc.php @@ -0,0 +1,157 @@ +host = $host; + $this->user = $user; + $this->password = $password; + $this->email_webmaster = $email_webmaster; + } + + // Adaptation of server_parse + function server_parse($expected_response) + { + if ($this->no_error) + { + $server_response = ''; + while (substr($server_response, 3, 1) != ' ') + { + if (!($server_response = fgets($this->socket, 256))) + { + trigger_error('Couldn\'t get mail server response codes.', E_USER_WARNING); + $this->no_error = false; + } + } + } + + if ($this->no_error) + { + if (!(substr($server_response, 0, 3) == $expected_response)) + { + trigger_error('Unable to send e-mail. Error message reported by the SMTP server: "'.$server_response.'"', E_USER_WARNING); + $this->no_error = false; + } + } + return $this->no_error; + } + + function server_write($s) + { + $this->no_error = $this->no_error && (fwrite($this->socket, $s) !== false); + return $this->no_error; + } + + // Adaptation of pun_mail + function mail($to, $subject, $message, $headers = '') + { + $this->no_error = true; + + $recipients = explode(',', $to); + + // Are we using port 25 or a custom port? + if (strpos($this->host, ':') !== false) + { + list($smtp_host, $smtp_port) = explode(':', $this->host); + } + else + { + $smtp_host = $this->host; + $smtp_port = 25; + } + + if ($this->socket = fsockopen($smtp_host, $smtp_port, $errno, $errstr, 15)) + { + $this->server_parse('220'); + + if (!empty($this->user) && !empty($this->password)) + { + $this->server_write('EHLO '.$smtp_host."\r\n"); + $this->server_parse('250'); + + $this->server_write('AUTH LOGIN'."\r\n"); + $this->server_parse('334'); + + $this->server_write(base64_encode($this->user)."\r\n"); + $this->no_error = $this->no_error && $this->no_error = $this->server_parse('334'); + + $this->server_write(base64_encode($this->password)."\r\n"); + $this->server_parse('235'); + } + else + { + $this->server_write('HELO '.$smtp_host."\r\n"); + $this->server_parse('250'); + } + + $this->server_write('MAIL FROM: <'.$this->email_webmaster.'>'."\r\n"); + $this->server_parse('250'); + + if (preg_match('/^\s*to\s*:.*/mi', $headers) === 0) + { + $to_header = 'To: '.implode(',', array_map(create_function('$email','return "<".$email.">";'), $recipients)); + } + else + { + $to_header = ''; + } + + @reset($recipients); + while (list(, $email) = @each($recipients)) + { + $this->server_write('RCPT TO: <'.$email.'>'."\r\n"); + $this->server_parse('250'); + } + + $this->server_write('DATA'."\r\n"); + $this->server_parse('354'); + + $this->server_write('Subject: '.$subject."\r\n".(empty($to_header) ? "" : $to_header."\r\n").$headers."\r\n\r\n".$message."\r\n"); + $this->server_write('.'."\r\n"); + $this->server_parse('250'); + + $this->server_write('QUIT'."\r\n"); + fclose($this->socket); + } + else + { + trigger_error('Could not connect to smtp host "'.$this->host.'" ('.$errno.') ('.$errstr.')', E_USER_WARNING); + $this->no_error = false;; + } + + return $this->no_error; + } +} + +?> diff --git a/BSF/include/common.inc.php b/BSF/include/common.inc.php new file mode 100644 index 000000000..45c6a3845 --- /dev/null +++ b/BSF/include/common.inc.php @@ -0,0 +1,283 @@ += 5.1.0RC1 + 'hash_hmac', //(hash) - enabled by default as of PHP 5.1.2 + 'preg_last_error', // PHP 5 >= 5.2.0 + 'file_put_contents', //PHP5 + ) as $func) +{ + if (!function_exists($func)) + { + include_once(PHPWG_ROOT_PATH . 'include/php_compat/'.$func.'.php'); + } +} + +include(PHPWG_ROOT_PATH . 'include/config_default.inc.php'); +@include(PHPWG_ROOT_PATH. 'include/config_local.inc.php'); +include(PHPWG_ROOT_PATH . 'include/constants.php'); +include(PHPWG_ROOT_PATH . 'include/functions.inc.php'); +include(PHPWG_ROOT_PATH . 'include/template.class.php'); + +// Database connection +mysql_connect( $cfgHote, $cfgUser, $cfgPassword ) +or die ( "Could not connect to database server" ); +mysql_select_db( $cfgBase ) +or die ( "Could not connect to database" ); + +defined('PWG_CHARSET') and defined('DB_CHARSET') + or die('PWG_CHARSET and/or DB_CHARSET is not defined'); +if ( version_compare(mysql_get_server_info(), '4.1.0', '>=') ) +{ + if (DB_CHARSET!='') + { + pwg_query('SET NAMES "'.DB_CHARSET.'"'); + } +} +else +{ + if ( strtolower(PWG_CHARSET)!='iso-8859-1' ) + { + die('PWG supports only iso-8859-1 charset on MySql version '.mysql_get_server_info()); + } +} + +// +// Setup gallery wide options, if this fails then we output a CRITICAL_ERROR +// since basic gallery information is not available +// +load_conf_from_db(); +load_plugins(); + +include(PHPWG_ROOT_PATH.'include/user.inc.php'); + + +// language files +load_language('common.lang'); +if (defined('IN_ADMIN') and IN_ADMIN) +{ + load_language('admin.lang'); +} +trigger_action('loading_lang'); +load_language('local.lang'); + +// only now we can set the localized username of the guest user (and not in +// include/user.inc.php) +if (is_a_guest()) +{ + $user['username'] = l10n('guest'); +} + +// template instance +if + ( + defined('IN_ADMIN') and IN_ADMIN and + isset($user['admin_template']) and + isset($user['admin_theme']) + ) +{ + // Admin template + $template = new Template(PHPWG_ROOT_PATH.'template/'.$user['admin_template'], $user['admin_theme'] ); +} +else +{ + // Classic template + $template = new Template(PHPWG_ROOT_PATH.'template/'.$user['template'], $user['theme'] ); +} + +if (isset($user['internal_status']['guest_must_be_guest']) + and + $user['internal_status']['guest_must_be_guest'] === true) +{ + $header_msgs[] = l10n('guest_must_be_guest'); +} + +if ($conf['gallery_locked']) +{ + $header_msgs[] = l10n('gallery_locked_message'); + + if ( script_basename() != 'identification' and !is_admin() ) + { + set_status_header(503, 'Service Unavailable'); + @header('Retry-After: 900'); + echo l10n('gallery_locked_message') + .'.'; + exit(); + } +} + +if ($conf['check_upgrade_feed'] + and defined('PHPWG_IN_UPGRADE') + and PHPWG_IN_UPGRADE) +{ + + // retrieve already applied upgrades + $query = ' +SELECT id + FROM '.UPGRADE_TABLE.' +;'; + $applied = array_from_query($query, 'id'); + + // retrieve existing upgrades + $existing = get_available_upgrade_ids(); + + // which upgrades need to be applied? + if (count(array_diff($existing, $applied)) > 0) + { + $header_msgs[] = 'Some database upgrades are missing, ' + .'upgrade now'; + } +} + +if (is_adviser()) +{ + $header_msgs[] = l10n('adviser_mode_enabled'); +} + +if (count($header_msgs) > 0) +{ + $template->assign('header_msgs', $header_msgs); + $header_msgs=array(); +} + +if (!empty($conf['filter_pages']) and get_filter_page_value('used')) +{ + include(PHPWG_ROOT_PATH.'include/functions_filter.inc.php'); + include(PHPWG_ROOT_PATH.'include/filter.inc.php'); +} +else +{ + $filter['enabled'] = false; +} + +if (isset($conf['header_notes'])) +{ + $header_notes = array_merge($header_notes, $conf['header_notes']); +} + +// default event handlers +add_event_handler('render_category_literal_description', 'render_category_literal_description'); +add_event_handler('render_category_description', 'render_category_description'); +add_event_handler('render_comment_content', 'htmlspecialchars'); +add_event_handler('render_comment_content', 'parse_comment_content'); +add_event_handler('render_comment_author', 'strip_tags'); +trigger_action('init'); +?> diff --git a/BSF/include/config_default.inc.php b/BSF/include/config_default.inc.php new file mode 100644 index 000000000..cb78729ef --- /dev/null +++ b/BSF/include/config_default.inc.php @@ -0,0 +1,700 @@ + 'PWG website', +// 'http://forum.phpwebgallery.net' => 'PWG forum', +// 'http://phpwebgallery.net/doc' => 'PWG wiki' +// ); +// +// Advenced use: +// You can also used special options. Instead to pass a string like parameter value +// you can pass a array with different optional parameter values +// $conf['links'] = array( +// 'http://piwigo.org' => array('label' => 'PWG website', 'new_window' => false, 'eval_visible' => 'return true;'), +// 'http://forum.phpwebgallery.net' => array('label' => 'For ADMIN', 'new_window' => true, 'eval_visible' => 'return is_admin();'), +// 'http://phpwebgallery.net/doc' => array('label' => 'For Guest', 'new_window' => true, 'eval_visible' => 'return is_a_guest();'), +// 'http://download.gna.org/phpwebgallery/' => +// array('label' => 'PopUp', 'new_window' => true, +// 'nw_name' => 'PopUp', 'nw_features' => 'width=800,height=450,location=no,status=no,toolbar=no,scrollbars=no,menubar=no'), +// ); +// Parameters: +// 'label': +// Label to display for the link, must be defined +// 'new_window': +// If true open link on tab/window +// [Default value is true if it's not defined] +// 'nw_name': +// Name use when new_window is true +// [Default value is '' if it's not defined] +// 'nw_features': +// features use when new_window is true +// [Default value is '' if it's not defined] +// 'eval_visible': +// It's php code witch must return if the link is visible or not +// [Default value is true if it's not defined] +// +// Equivalence: +// $conf['links'] = array( +// 'http://piwigo.org' => 'PWG website', +// ); +// $conf['links'] = array( +// 'http://piwigo.org' => array('label' => 'PWG website', 'new_window' => false, 'visible' => 'return true;'), +// ); +// +// If the array is empty, the "Links" box won't be displayed on the main +// page. +$conf['links'] = array(); + +// random_index_redirect: list of 'internal' links to use when no section is defined on index.php. +// An example is the best than a long explanation : +// +// for each link is associated a php condition +// '' condition is equivalent to 'return true;' +// $conf['random_index_redirect'] = array( +// PHPWG_ROOT_PATH.'index.php?/best_rated' => 'return true;', +// PHPWG_ROOT_PATH.'index.php?/recent_pics' => 'return is_a_guest();', +// PHPWG_ROOT_PATH.'random.php' => '', +// PHPWG_ROOT_PATH.'index.php?/categories' => '', +// ); +$conf['random_index_redirect'] = array(); + +// List of notes to display on all header page +// example $conf['header_notes'] = array('Test', 'Hello'); +$conf['header_notes'] = array(); + +// show_thumbnail_caption : on thumbnails page, show thumbnail captions ? +$conf['show_thumbnail_caption'] = true; + +// show_picture_name_on_title : on picture presentation page, show picture +// name ? +$conf['show_picture_name_on_title'] = true; + +// display_fromto: in subcatify mode, display the date creation bounds of a +// category. +$conf['display_fromto'] = false; + +// allow_random_representative : do you wish Piwigo to search among +// categories elements a new representative at each reload ? +// +// If false, an element is randomly or manually chosen to represent its +// category and remains the representative as long as an admin does not +// change it. +// +// Warning : setting this parameter to true is CPU consuming. Each time you +// change the value of this parameter from false to true, an administrator +// must update categories informations in screen [Admin > General > +// Maintenance]. +$conf['allow_random_representative'] = false; + +// allow_html_descriptions : authorize administrators to use HTML in +// category and element description. +$conf['allow_html_descriptions'] = true; + +// prefix_thumbnail : string before filename. Thumbnail's prefix must only +// contain characters among : a to z (case insensitive), "-" or "_". +$conf['prefix_thumbnail'] = 'TN-'; + +// users_page: how many users to display in screen +// Administration>Identification>Users? +$conf['users_page'] = 20; + +// image level permissions available in the admin interface +$conf['available_permission_levels'] = array(0,1,2,4,8); + +// mail_options: only set it true if you have a send mail warning with +// "options" parameter missing on mail() function execution. +$conf['mail_options'] = false; + +// send_bcc_mail_webmaster: send bcc mail to webmaster. Set true for debug +// or test. +$conf['send_bcc_mail_webmaster'] = false; + +// default_email_format: +// Define the default email format use to send email +// Value could be text/plain or text/html +$conf['default_email_format'] = 'text/html'; + +// define the name of sender mail: +// If value is empty, gallery title is used +$conf['mail_sender_name'] = ''; + +// smtp configuration +// (work if fsockopen function is allowed for smtp port) +// smtp_host: smtp server host +// if null, regular mail function is used +// format: hoststring[:port] +// exemple: smtp.pwg.net:21 +// smtp_user/smtp_password: user & password for smtp identication +$conf['smtp_host'] = ''; +$conf['smtp_user'] = ''; +$conf['smtp_password'] = ''; + + +// check_upgrade_feed: check if there are database upgrade required. Set to +// true, a message will strongly encourage you to upgrade your database if +// needed. +// +// This configuration parameter is set to true in BSF branch and to false +// elsewhere. +$conf['check_upgrade_feed'] = true; + +// rate_items: available rates for a picture +$conf['rate_items'] = array(0,1,2,3,4,5); + +// Define default method to use ('http' or 'html' in order to do redirect) +$conf['default_redirect_method'] = 'http'; + +// +-----------------------------------------------------------------------+ +// | metadata | +// +-----------------------------------------------------------------------+ + +// show_iptc: Show IPTC metadata on picture.php if asked by user +$conf['show_iptc'] = false; + +// show_iptc_mapping : is used for showing IPTC metadata on picture.php +// page. For each key of the array, you need to have the same key in the +// $lang array. For example, if my first key is 'iptc_keywords' (associated +// to '2#025') then you need to have $lang['iptc_keywords'] set in +// language/$user['language']/common.lang.php. If you don't have the lang +// var set, the key will be simply displayed +// +// To know how to associated iptc_field with their meaning, use +// tools/metadata.php +$conf['show_iptc_mapping'] = array( + 'iptc_keywords' => '2#025', + 'iptc_caption_writer' => '2#122', + 'iptc_byline_title' => '2#085', + 'iptc_caption' => '2#120' + ); + +// use_iptc: Use IPTC data during database synchronization with files +// metadata +$conf['use_iptc'] = false; + +// use_iptc_mapping : in which IPTC fields will Piwigo find image +// information ? This setting is used during metadata synchronisation. It +// associates a piwigo_images column name to a IPTC key +$conf['use_iptc_mapping'] = array( + 'keywords' => '2#025', + 'date_creation' => '2#055', + 'author' => '2#122', + 'name' => '2#005', + 'comment' => '2#120' + ); + +// show_exif: Show EXIF metadata on picture.php (table or line presentation +// avalaible) +$conf['show_exif'] = true; + +// show_exif_fields : in EXIF fields, you can choose to display fields in +// sub-arrays, for example ['COMPUTED']['ApertureFNumber']. for this, add +// 'COMPUTED;ApertureFNumber' in $conf['show_exif_fields'] +// +// The key displayed in picture.php will be $lang['exif_field_Make'] for +// example and if it exists. For compound fields, only take into account the +// last part : for key 'COMPUTED;ApertureFNumber', you need +// $lang['exif_field_ApertureFNumber'] +// +// for PHP version newer than 4.1.2 : +// $conf['show_exif_fields'] = array('CameraMake','CameraModel','DateTime'); +// +$conf['show_exif_fields'] = array( + 'Make', + 'Model', + 'DateTimeOriginal', + 'COMPUTED;ApertureFNumber' + ); + +// use_exif: Use EXIF data during database synchronization with files +// metadata +$conf['use_exif'] = true; + +// use_exif_mapping: same behaviour as use_iptc_mapping +$conf['use_exif_mapping'] = array( + 'date_creation' => 'DateTimeOriginal' + ); + +// +-----------------------------------------------------------------------+ +// | sessions | +// +-----------------------------------------------------------------------+ + +// session_use_cookies: specifies to use cookie to store +// the session id on client side +$conf['session_use_cookies'] = true; + +// session_use_only_cookies: specifies to only use cookie to store +// the session id on client side +$conf['session_use_only_cookies'] = true; + +// session_use_trans_sid: do not use transparent session id support +$conf['session_use_trans_sid'] = false; + +// session_name: specifies the name of the session which is used as cookie name +$conf['session_name'] = 'pwg_id'; + +// session_save_handler: comment the line below +// to use file handler for sessions. +$conf['session_save_handler'] = 'db'; + +// authorize_remembering : permits user to stay logged for a long time. It +// creates a cookie on client side. +$conf['authorize_remembering'] = true; + +// remember_me_name: specifies the name of the cookie used to stay logged +$conf['remember_me_name'] = 'pwg_remember'; + +// remember_me_length : time of validity for "remember me" cookies, in +// seconds. +$conf['remember_me_length'] = 5184000; + +// session_length : time of validity for normal session, in seconds. +$conf['session_length'] = 3600; + +// +-----------------------------------------------------------------------+ +// | debug | +// +-----------------------------------------------------------------------+ + +// show_queries : for debug purpose, show queries and execution times +$conf['show_queries'] = false; + +// show_gt : display generation time at the bottom of each page +$conf['show_gt'] = true; + +// debug_l10n : display a warning message each time an unset language key is +// accessed +$conf['debug_l10n'] = false; + +// activate template debugging - a new window will appear +$conf['debug_template'] = false; + +// die_on_sql_error: if an SQL query fails, should everything stop? +$conf['die_on_sql_error'] = true; + +// +-----------------------------------------------------------------------+ +// | authentication | +// +-----------------------------------------------------------------------+ + +// apache_authentication : use Apache authentication as reference instead of +// users table ? +$conf['apache_authentication'] = false; + +// users_table: which table is the reference for users? Can be a different +// table than Piwigo table +// +// If you decide to use another table than the default one, you need to +// prepare your database by deleting some datas : +// +// delete from piwigo_user_access; +// delete from piwigo_user_cache; +// delete from piwigo_user_feed; +// delete from piwigo_user_group; +// delete from piwigo_user_infos; +// delete from piwigo_sessions; +// delete from piwigo_rate; +// update piwigo_images set average_rate = null; +// delete from piwigo_caddie; +// delete from piwigo_favorites; +// +// All informations contained in these tables and column are related to +// piwigo_users table. +$conf['users_table'] = $prefixeTable.'users'; + +// Other tables can be changed, if you define associated constants +// Example: +// define('USER_INFOS_TABLE', 'pwg_main'.'user_infos'); + + +// user_fields : mapping between generic field names and table specific +// field names. For example, in PWG, the mail address is names +// "mail_address" and in punbb, it's called "email". +$conf['user_fields'] = array( + 'id' => 'id', + 'username' => 'username', + 'password' => 'password', + 'email' => 'mail_address' + ); + +// pass_convert : function to crypt or hash the clear user password to store +// it in the database +$conf['pass_convert'] = create_function('$s', 'return md5($s);'); + +// guest_id : id of the anonymous user +$conf['guest_id'] = 2; +// default_user_id : id of user used for default value +$conf['default_user_id'] = $conf['guest_id']; + +// webmaster_id : webmaster'id. +$conf['webmaster_id'] = 1; + +// allow to use adviser mode +$conf['allow_adviser'] = false; + +// does the guest have access ? +// (not a security feature, set your categories "private" too) +// If false it'll be redirected from index.php to identification.php +$conf['guest_access'] = true; + +// +-----------------------------------------------------------------------+ +// | upload | +// +-----------------------------------------------------------------------+ + +// upload_maxfilesize: maximum filesize for the uploaded pictures. In +// kilobytes. +$conf['upload_maxfilesize'] = 200; + +// upload_maxheight: maximum height authorized for the uploaded images. In +// pixels. +$conf['upload_maxheight'] = 800; + +// upload_maxwidth: maximum width authorized for the uploaded images. In +// pixels. +$conf['upload_maxwidth'] = 800; + +// upload_maxheight_thumbnail: maximum height authorized for the uploaded +// thumbnails +$conf['upload_maxheight_thumbnail'] = 128; + +// upload_maxwidth_thumbnail: maximum width authorized for the uploaded +// thumbnails +$conf['upload_maxwidth_thumbnail'] = 128; + +// +-----------------------------------------------------------------------+ +// | history | +// +-----------------------------------------------------------------------+ + +// nb_logs_page : how many logs to display on a page +$conf['nb_logs_page'] = 300; + +// +-----------------------------------------------------------------------+ +// | urls | +// +-----------------------------------------------------------------------+ + +// question_mark_in_urls : the generated urls contain a ? sign. This can be +// changed to false only if the server translates PATH_INFO variable +// (depends on the server AcceptPathInfo directive configuration) +$conf['question_mark_in_urls'] = true; + +// php_extension_in_urls : if true, the urls generated for picture and +// category will not contain the .php extension. This will work only if +// .htaccess defines Options +MultiViews parameter or url rewriting rules +// are active. +$conf['php_extension_in_urls'] = true; + +// category_url_style : one of 'id' (default) or 'id-name'. 'id-name' +// means that an simplified ascii represntation of the category name will +// appear in the url +$conf['category_url_style'] = 'id'; + +// picture_url_style : one of 'id' (default), 'id-file' or 'file'. 'id-file' +// or 'file' mean that the file name (without extension will appear in the +// url). Note that one aditionnal sql query will occur if 'file' is choosen. +// Note that you might experience navigation issues if you choose 'file' +// and your file names are not unique +$conf['picture_url_style'] = 'id'; + +// tag_url_style : one of 'id-tag' (default), 'id' or 'tag'. +// Note that if you choose 'tag' and the url (ascii) representation of your +// tags is not unique, all tags with the same url representation will be shown +$conf['tag_url_style'] = 'id-tag'; + +// +-----------------------------------------------------------------------+ +// | tags | +// +-----------------------------------------------------------------------+ + +// full_tag_cloud_items_number: number of tags to show in the full tag +// cloud. Only the most represented tags will be shown +$conf['full_tag_cloud_items_number'] = 200; + +// menubar_tag_cloud_items_number: number of tags to show in the tag +// cloud in the menubar. Only the most represented tags will be shown +$conf['menubar_tag_cloud_items_number'] = 100; + +// content_tag_cloud_items_number: number of tags to show in the tag +// cloud on the content page. Only the most represented tags will be shown +$conf['content_tag_cloud_items_number'] = 12; + +// tags_levels: number of levels to use for display. Each level is bind to a +// CSS class tagLevelX. +$conf['tags_levels'] = 5; + +// +-----------------------------------------------------------------------+ +// | Notification by mail | +// +-----------------------------------------------------------------------+ + +// Default Value for nbm user +$conf['nbm_default_value_user_enabled'] = false; + +// Search list user to send quickly (List all without to check news) +// More quickly but less fun to use +$conf['nbm_list_all_enabled_users_to_send'] = false; + +// Max time used on one pass in order to send mails. +// Timeout delay ratio. +$conf['nbm_max_treatment_timeout_percent'] = 0.8; + +// If timeout cannot be compite with nbm_max_treatment_timeout_percent, +// nbm_treatment_timeout_default is used by default +$conf['nbm_treatment_timeout_default'] = 20; + +// Parameters used in get_recent_post_dates for the 2 kind of notification +$conf['recent_post_dates'] = array( + 'RSS' => array('max_dates' => 5, 'max_elements' => 6, 'max_cats' => 6), + 'NBM' => array('max_dates' => 7, 'max_elements' => 3, 'max_cats' => 9) + ); + +// +-----------------------------------------------------------------------+ +// | Set admin layout | +// +-----------------------------------------------------------------------+ + +$conf['admin_layout'] = 'yoga/admin'; + +// should we load the active plugins ? true=Yes, false=No +$conf['enable_plugins']=true; + +// Web services are allowed (true) or completely forbidden (false) +$conf['allow_web_services'] = true; + +// Maximum number of images to be returned foreach call to the web service +$conf['ws_max_images_per_page'] = 500; + +// On Access control false / Admim Web Service need Php cURL extension +// Controls are done on public basis or +// if connected on member authorization basis +$conf['ws_access_control'] = false; + +// Additionnal controls are made based on Web Service Access Table +// Max returned rows number ( > 0 ) +$conf['ws_allowed_limit'] = array(1,2,3,5,10,25); + +// By default can be delayed by 0, 1, 2, 3, 5, 7, 14 or 30 days +// 0 it's Now(), don't remove that one +$conf['ws_postponed_start'] = array(0,1,2,3,5,7,14,30); /* In days */ + +// By default 10, 5, 2, 1 year(s) or 6, 3, 1 month(s) +// or 15, 10, 7, 5, 1, 0 day(s) +// 0 it's temporary closed (Useful for one access) +$conf['ws_durations'] = array(3650,1825,730,365,182,91,30,15,10,7,5,1,0); + +// +-----------------------------------------------------------------------+ +// | Filter | +// +-----------------------------------------------------------------------+ +// $conf['filter_pages'] contains configuration for each pages +// o If values are not defined for a specific page, default value are used +// o Array is composed by the basename of each page without extention +// o List of value names: +// - used: filter function are used +// (if false nothing is done [start, cancel, stop, ...] +// - cancel: cancel current started filter +// - add_notes: add notes about current started filter on the header +// o Empty configuration in order to disable completely filter functions +// No filter, No icon,... +// $conf['filter_pages'] = array(); +$conf['filter_pages'] = array + ( + // Default page + 'default' => array( + 'used' => true, 'cancel' => false, 'add_notes' => false), + // Real pages + 'index' => array('add_notes' => true), + 'tags' => array('add_notes' => true), + 'search' => array('add_notes' => true), + 'comments' => array('add_notes' => true), + 'admin' => array('used' => false), + 'feed' => array('used' => false), + 'notification' => array('used' => false), + 'nbm' => array('used' => false), + 'popuphelp' => array('used' => false), + 'profile' => array('used' => false), + 'web_service' => array('used' => false), + 'ws' => array('used' => false), + 'identification' => array('cancel' => true), + 'install' => array('cancel' => true), + 'password' => array('cancel' => true), + 'register' => array('cancel' => true), + 'upgrade_feed' => array('cancel' => true), + ); + +// +-----------------------------------------------------------------------+ +// | Slideshow | +// +-----------------------------------------------------------------------+ +// slideshow_period : waiting time in seconds before loading a new page +// during automated slideshow +// slideshow_period_min, slideshow_period_max are bounds of slideshow_period +// slideshow_period_step is the step of navigation between min and max +$conf['slideshow_period_min'] = 1; +$conf['slideshow_period_max'] = 10; +$conf['slideshow_period_step'] = 1; +$conf['slideshow_period'] = 4; + +// slideshow_repeat : slideshow loops on pictures +$conf['slideshow_repeat'] = true; + +// $conf['light_slideshow'] indicates to use slideshow.tpl in state of +// picture.tpl for slideshow +// Take care to have slideshow.tpl in all available templates +// Or set it false. +// Check if Picture's plugins are compliant with it +// Every plugin from 1.7 would be design to manage light_slideshow case. +$conf['light_slideshow'] = true; + +// the local data directory is used to store data such as compiled templates +// or other plugin variables etc +$conf['local_data_dir'] = dirname(dirname(__FILE__)).'/_data'; + +// if true, some language strings are replaced during template compilation +// (insted of template output). this results in better performance. however +// any change in the language file will not be propagated until you purge +// the compiled templates from the admin / maintenance menu +$conf['compiled_template_cache_language'] = false; + +?> \ No newline at end of file diff --git a/BSF/include/constants.php b/BSF/include/constants.php new file mode 100644 index 000000000..42854a9d4 --- /dev/null +++ b/BSF/include/constants.php @@ -0,0 +1,112 @@ + diff --git a/BSF/include/feedcreator.class.php b/BSF/include/feedcreator.class.php new file mode 100644 index 000000000..f274b8417 --- /dev/null +++ b/BSF/include/feedcreator.class.php @@ -0,0 +1,1541 @@ +useCached(); // use cached version if age<1 hour +$rss->title = "PHP news"; +$rss->description = "daily news from the PHP scripting world"; + +//optional +$rss->descriptionTruncSize = 500; +$rss->descriptionHtmlSyndicated = true; + +$rss->link = "http://www.dailyphp.net/news"; +$rss->syndicationURL = "http://www.dailyphp.net/".$_SERVER["PHP_SELF"]; + +$image = new FeedImage(); +$image->title = "dailyphp.net logo"; +$image->url = "http://www.dailyphp.net/images/logo.gif"; +$image->link = "http://www.dailyphp.net"; +$image->description = "Feed provided by dailyphp.net. Click to visit."; + +//optional +$image->descriptionTruncSize = 500; +$image->descriptionHtmlSyndicated = true; + +$rss->image = $image; + +// get your news items from somewhere, e.g. your database: +mysql_select_db($dbHost, $dbUser, $dbPass); +$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); +while ($data = mysql_fetch_object($res)) { + $item = new FeedItem(); + $item->title = $data->title; + $item->link = $data->url; + $item->description = $data->short; + + //optional + item->descriptionTruncSize = 500; + item->descriptionHtmlSyndicated = true; + + $item->date = $data->newsdate; + $item->source = "http://www.dailyphp.net"; + $item->author = "John Doe"; + + $rss->addItem($item); +} + +// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1 (deprecated), +// MBOX, OPML, ATOM, ATOM0.3, HTML, JS +echo $rss->saveFeed("RSS1.0", "news/feed.xml"); + + +*************************************************************************** +* A little setup * +**************************************************************************/ + +// your local timezone, set to "" to disable or for GMT +define("TIME_ZONE","+00:00"); + + + + +/** + * Version string. + **/ +define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2"); + + + +/** + * A FeedItem is a part of a FeedCreator feed. + * + * @author Kai Blankenhorn + * @since 1.3 + */ +class FeedItem extends HtmlDescribable { + /** + * Mandatory attributes of an item. + */ + var $title, $description, $link; + + /** + * Optional attributes of an item. + */ + var $author, $authorEmail, $image, $category, $comments, $guid, $source, $creator; + + /** + * Publishing date of an item. May be in one of the following formats: + * + * RFC 822: + * "Mon, 20 Jan 03 18:05:41 +0400" + * "20 Jan 03 18:05:41 +0000" + * + * ISO 8601: + * "2003-01-20T18:05:41+04:00" + * + * Unix: + * 1043082341 + */ + var $date; + + /** + * Any additional elements to include as an assiciated array. All $key => $value pairs + * will be included unencoded in the feed item in the form + * <$key>$value + * Again: No encoding will be used! This means you can invalidate or enhance the feed + * if $value contains markup. This may be abused to embed tags not implemented by + * the FeedCreator class used. + */ + var $additionalElements = Array(); + + // on hold + // var $source; +} + + + +/** + * An FeedImage may be added to a FeedCreator feed. + * @author Kai Blankenhorn + * @since 1.3 + */ +class FeedImage extends HtmlDescribable { + /** + * Mandatory attributes of an image. + */ + var $title, $url, $link; + + /** + * Optional attributes of an image. + */ + var $width, $height, $description; +} + + + +/** + * An HtmlDescribable is an item within a feed that can have a description that may + * include HTML markup. + */ +class HtmlDescribable { + /** + * Indicates whether the description field should be rendered in HTML. + */ + var $descriptionHtmlSyndicated; + + /** + * Indicates whether and to how many characters a description should be truncated. + */ + var $descriptionTruncSize; + + /** + * Returns a formatted description field, depending on descriptionHtmlSyndicated and + * $descriptionTruncSize properties + * @return string the formatted description + */ + function getDescription() { + $descriptionField = new FeedHtmlField($this->description); + $descriptionField->syndicateHtml = $this->descriptionHtmlSyndicated; + $descriptionField->truncSize = $this->descriptionTruncSize; + return $descriptionField->output(); + } + +} + + +/** + * An FeedHtmlField describes and generates + * a feed, item or image html field (probably a description). Output is + * generated based on $truncSize, $syndicateHtml properties. + * @author Pascal Van Hecke + * @version 1.6 + */ +class FeedHtmlField { + /** + * Mandatory attributes of a FeedHtmlField. + */ + var $rawFieldContent; + + /** + * Optional attributes of a FeedHtmlField. + * + */ + var $truncSize, $syndicateHtml; + + /** + * Creates a new instance of FeedHtmlField. + * @param $string: if given, sets the rawFieldContent property + */ + function FeedHtmlField($parFieldContent) { + if ($parFieldContent) { + $this->rawFieldContent = $parFieldContent; + } + } + + + /** + * Creates the right output, depending on $truncSize, $syndicateHtml properties. + * @return string the formatted field + */ + function output() { + // when field available and syndicated in html we assume + // - valid html in $rawFieldContent and we enclose in CDATA tags + // - no truncation (truncating risks producing invalid html) + if (!$this->rawFieldContent) { + $result = ""; + } elseif ($this->syndicateHtml) { + $result = "rawFieldContent."]]>"; + } else { + if ($this->truncSize and is_int($this->truncSize)) { + $result = FeedCreator::iTrunc(htmlspecialchars($this->rawFieldContent),$this->truncSize); + } else { + $result = htmlspecialchars($this->rawFieldContent); + } + } + return $result; + } + +} + + + +/** + * UniversalFeedCreator lets you choose during runtime which + * format to build. + * For general usage of a feed class, see the FeedCreator class + * below or the example above. + * + * @since 1.3 + * @author Kai Blankenhorn + */ +class UniversalFeedCreator extends FeedCreator { + var $_feed; + + function _setFormat($format) { + switch (strtoupper($format)) { + + case "2.0": + // fall through + case "RSS2.0": + $this->_feed = new RSSCreator20(); + break; + + case "1.0": + // fall through + case "RSS1.0": + $this->_feed = new RSSCreator10(); + break; + + case "0.91": + // fall through + case "RSS0.91": + $this->_feed = new RSSCreator091(); + break; + + case "PIE0.1": + $this->_feed = new PIECreator01(); + break; + + case "MBOX": + $this->_feed = new MBOXCreator(); + break; + + case "OPML": + $this->_feed = new OPMLCreator(); + break; + + case "ATOM": + // fall through: always the latest ATOM version + + case "ATOM0.3": + $this->_feed = new AtomCreator03(); + break; + + case "HTML": + $this->_feed = new HTMLCreator(); + break; + + case "JS": + // fall through + case "JAVASCRIPT": + $this->_feed = new JSCreator(); + break; + + default: + $this->_feed = new RSSCreator091(); + break; + } + + $vars = get_object_vars($this); + foreach ($vars as $key => $value) { + // prevent overwriting of properties "contentType", "encoding"; do not copy "_feed" itself + if (!in_array($key, array("_feed", "contentType"/*PWG, "encoding"*/))) { + $this->_feed->{$key} = $this->{$key}; + } + } + } + + /** + * Creates a syndication feed based on the items previously added. + * + * @see FeedCreator::addItem() + * @param string format format the feed should comply to. Valid values are: + * "PIE0.1", "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3", "HTML", "JS" + * @return string the contents of the feed. + */ + function createFeed($format = "RSS0.91") { + $this->_setFormat($format); + return $this->_feed->createFeed(); + } + + + + /** + * Saves this feed as a file on the local disk. After the file is saved, an HTTP redirect + * header may be sent to redirect the use to the newly created file. + * @since 1.4 + * + * @param string format format the feed should comply to. Valid values are: + * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM", "ATOM0.3", "HTML", "JS" + * @param string filename optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). + * @param boolean displayContents optional send the content of the file or not. If true, the file will be sent in the body of the response. + */ + function saveFeed($format="RSS0.91", $filename="", $displayContents=true) { + $this->_setFormat($format); + $this->_feed->saveFeed($filename, $displayContents); + } + + + /** + * Turns on caching and checks if there is a recent version of this feed in the cache. + * If there is, an HTTP redirect header is sent. + * To effectively use caching, you should create the FeedCreator object and call this method + * before anything else, especially before you do the time consuming task to build the feed + * (web fetching, for example). + * + * @param string format format the feed should comply to. Valid values are: + * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3". + * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). + * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour) + */ + function useCached($format="RSS0.91", $filename="", $timeout=3600) { + $this->_setFormat($format); + $this->_feed->useCached($filename, $timeout); + } + +} + + +/** + * FeedCreator is the abstract base implementation for concrete + * implementations that implement a specific format of syndication. + * + * @abstract + * @author Kai Blankenhorn + * @since 1.4 + */ +class FeedCreator extends HtmlDescribable { + + /** + * Mandatory attributes of a feed. + */ + var $title, $description, $link; + + + /** + * Optional attributes of a feed. + */ + var $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays; + + /** + * The url of the external xsl stylesheet used to format the naked rss feed. + * Ignored in the output when empty. + */ + var $xslStyleSheet = ""; + + + /** + * @access private + */ + var $items = Array(); + + + /** + * This feed's MIME content type. + * @since 1.4 + * @access private + */ + var $contentType = "application/xml"; + + + /** + * This feed's character encoding. + * @since 1.6.1 + **/ + var $encoding = "ISO-8859-1"; + + + /** + * Any additional elements to include as an assiciated array. All $key => $value pairs + * will be included unencoded in the feed in the form + * <$key>$value + * Again: No encoding will be used! This means you can invalidate or enhance the feed + * if $value contains markup. This may be abused to embed tags not implemented by + * the FeedCreator class used. + */ + var $additionalElements = Array(); + + + /** + * Adds an FeedItem to the feed. + * + * @param object FeedItem $item The FeedItem to add to the feed. + * @access public + */ + function addItem($item) { + $this->items[] = $item; + } + + + /** + * Truncates a string to a certain length at the most sensible point. + * First, if there's a '.' character near the end of the string, the string is truncated after this character. + * If there is no '.', the string is truncated after the last ' ' character. + * If the string is truncated, " ..." is appended. + * If the string is already shorter than $length, it is returned unchanged. + * + * @static + * @param string string A string to be truncated. + * @param int length the maximum length the string should be truncated to + * @return string the truncated string + */ + function iTrunc($string, $length) { + if (strlen($string)<=$length) { + return $string; + } + + $pos = strrpos($string,"."); + if ($pos>=$length-4) { + $string = substr($string,0,$length-4); + $pos = strrpos($string,"."); + } + if ($pos>=$length*0.4) { + return substr($string,0,$pos+1)." ..."; + } + + $pos = strrpos($string," "); + if ($pos>=$length-4) { + $string = substr($string,0,$length-4); + $pos = strrpos($string," "); + } + if ($pos>=$length*0.4) { + return substr($string,0,$pos)." ..."; + } + + return substr($string,0,$length-4)." ..."; + + } + + + /** + * Creates a comment indicating the generator of this feed. + * The format of this comment seems to be recognized by + * Syndic8.com. + */ + function _createGeneratorComment() { + return "\n"; + } + + + /** + * Creates a string containing all additional elements specified in + * $additionalElements. + * @param elements array an associative array containing key => value pairs + * @param indentString string a string that will be inserted before every generated line + * @return string the XML tags corresponding to $additionalElements + */ + function _createAdditionalElements($elements, $indentString="") { + $ae = ""; + if (is_array($elements)) { + foreach($elements AS $key => $value) { + $ae.= $indentString."<$key>$value\n"; + } + } + return $ae; + } + + function _createStylesheetReferences() { + $xml = ""; + if (isset($this->cssStyleSheet)) $xml .= "cssStyleSheet."\" type=\"text/css\"?>\n"; + if ($this->xslStyleSheet) $xml .= "xslStyleSheet."\" type=\"text/xsl\"?>\n"; + return $xml; + } + + + /** + * Builds the feed's text. + * @abstract + * @return string the feed's complete text + */ + function createFeed() { + } + + /** + * Generate a filename for the feed cache file. The result will be $_SERVER["PHP_SELF"] with the extension changed to .xml. + * For example: + * + * echo $_SERVER["PHP_SELF"]."\n"; + * echo FeedCreator::_generateFilename(); + * + * would produce: + * + * /rss/latestnews.php + * latestnews.xml + * + * @return string the feed cache filename + * @since 1.4 + * @access private + */ + function _generateFilename() { + $fileInfo = pathinfo($_SERVER["PHP_SELF"]); + return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml"; + } + + + /** + * @since 1.4 + * @access private + */ + function _redirect($filename) { + // attention, heavily-commented-out-area + + // maybe use this in addition to file time checking + //Header("Expires: ".date("r",time()+$this->_timeout)); + + /* no caching at all, doesn't seem to work as good: + Header("Cache-Control: no-cache"); + Header("Pragma: no-cache"); + */ + + // HTTP redirect, some feed readers' simple HTTP implementations don't follow it + //Header("Location: ".$filename); + + Header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename)); + Header("Content-Disposition: inline; filename=".basename($filename)); + readfile($filename, "r"); + die(); + } + + /** + * Turns on caching and checks if there is a recent version of this feed in the cache. + * If there is, an HTTP redirect header is sent. + * To effectively use caching, you should create the FeedCreator object and call this method + * before anything else, especially before you do the time consuming task to build the feed + * (web fetching, for example). + * @since 1.4 + * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). + * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour) + */ + function useCached($filename="", $timeout=3600) { + $this->_timeout = $timeout; + if ($filename=="") { + $filename = $this->_generateFilename(); + } + if (file_exists($filename) AND (time()-filemtime($filename) < $timeout)) { + $this->_redirect($filename); + } + } + + + /** + * Saves this feed as a file on the local disk. After the file is saved, a redirect + * header may be sent to redirect the user to the newly created file. + * @since 1.4 + * + * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). + * @param redirect boolean optional send an HTTP redirect header or not. If true, the user will be automatically redirected to the created file. + */ + function saveFeed($filename="", $displayContents=true) { + if ($filename=="") { + $filename = $this->_generateFilename(); + } + $feedFile = fopen($filename, "w+"); + if ($feedFile) { + fputs($feedFile,$this->createFeed()); + fclose($feedFile); + if ($displayContents) { + $this->_redirect($filename); + } + } else { + echo "
Error creating feed file, please check write permissions.
"; + } + } + +} + + +/** + * FeedDate is an internal class that stores a date for a feed or feed item. + * Usually, you won't need to use this. + */ +class FeedDate { + var $unix; + + /** + * Creates a new instance of FeedDate representing a given date. + * Accepts RFC 822, ISO 8601 date formats as well as unix time stamps. + * @param mixed $dateString optional the date this FeedDate will represent. If not specified, the current date and time is used. + */ + function FeedDate($dateString="") { + if ($dateString=="") $dateString = date("r"); + + if (is_integer($dateString)) { + $this->unix = $dateString; + return; + } + if (preg_match("~(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\\s+)?(\\d{1,2})\\s+([a-zA-Z]{3})\\s+(\\d{4})\\s+(\\d{2}):(\\d{2}):(\\d{2})\\s+(.*)~",$dateString,$matches)) { + $months = Array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12); + $this->unix = mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]); + if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') { + $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60; + } else { + if (strlen($matches[7])==1) { + $oneHour = 3600; + $ord = ord($matches[7]); + if ($ord < ord("M")) { + $tzOffset = (ord("A") - $ord - 1) * $oneHour; + } elseif ($ord >= ord("M") AND $matches[7]!="Z") { + $tzOffset = ($ord - ord("M")) * $oneHour; + } elseif ($matches[7]=="Z") { + $tzOffset = 0; + } + } + switch ($matches[7]) { + case "UT": + case "GMT": $tzOffset = 0; + } + } + $this->unix += $tzOffset; + return; + } + if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) { + $this->unix = mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]); + if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') { + $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60; + } else { + if ($matches[7]=="Z") { + $tzOffset = 0; + } + } + $this->unix += $tzOffset; + return; + } + $this->unix = 0; + } + + /** + * Gets the date stored in this FeedDate as an RFC 822 date. + * + * @return a date in RFC 822 format + */ + function rfc822() { + //return gmdate("r",$this->unix); + $date = gmdate("D, d M Y H:i:s", $this->unix); + if (TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE); + return $date; + } + + /** + * Gets the date stored in this FeedDate as an ISO 8601 date. + * + * @return a date in ISO 8601 format + */ + function iso8601() { + $date = gmdate("Y-m-d\TH:i:sO",$this->unix); + $date = substr($date,0,22) . ':' . substr($date,-2); + if (TIME_ZONE!="") $date = str_replace("+00:00",TIME_ZONE,$date); + return $date; + } + + /** + * Gets the date stored in this FeedDate as unix time stamp. + * + * @return a date as a unix time stamp + */ + function unix() { + return $this->unix; + } +} + + +/** + * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0. + * + * @see http://www.purl.org/rss/1.0/ + * @since 1.3 + * @author Kai Blankenhorn + */ +class RSSCreator10 extends FeedCreator { + + /** + * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0. + * The feed will contain all items previously added in the same order. + * @return string the feed's complete text + */ + function createFeed() { + $feed = "encoding."\"?>\n"; + $feed.= $this->_createGeneratorComment(); + if ($this->cssStyleSheet=="") { + $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css"; + } + $feed.= $this->_createStylesheetReferences(); + $feed.= "\n"; + $feed.= " syndicationURL."\">\n"; + $feed.= " ".htmlspecialchars($this->title)."\n"; + $feed.= " ".htmlspecialchars($this->description)."\n"; + $feed.= " ".$this->link."\n"; + if ($this->image!=null) { + $feed.= " image->url."\" />\n"; + } + $now = new FeedDate(); + $feed.= " ".htmlspecialchars($now->iso8601())."\n"; + $feed.= " \n"; + $feed.= " \n"; + for ($i=0;$iitems);$i++) { + $feed.= " items[$i]->link)."\"/>\n"; + } + $feed.= " \n"; + $feed.= " \n"; + $feed.= " \n"; + if ($this->image!=null) { + $feed.= " image->url."\">\n"; + $feed.= " ".$this->image->title."\n"; + $feed.= " ".$this->image->link."\n"; + $feed.= " ".$this->image->url."\n"; + $feed.= " \n"; + } + $feed.= $this->_createAdditionalElements($this->additionalElements, " "); + + for ($i=0;$iitems);$i++) { + $feed.= " items[$i]->link)."\">\n"; + //$feed.= " Posting\n"; + $feed.= " text/html\n"; + if ($this->items[$i]->date!=null) { + $itemDate = new FeedDate($this->items[$i]->date); + $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; + } + if ($this->items[$i]->source!="") { + $feed.= " ".htmlspecialchars($this->items[$i]->source)."\n"; + } + if ($this->items[$i]->author!="") { + $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; + } + $feed.= " ".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r"," ")))."\n"; + $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; + $feed.= " ".htmlspecialchars($this->items[$i]->description)."\n"; + $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); + $feed.= " \n"; + } + $feed.= "\n"; + return $feed; + } +} + + + +/** + * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3. + * + * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html + * @since 1.3 + * @author Kai Blankenhorn + */ +class RSSCreator091 extends FeedCreator { + + /** + * Stores this RSS feed's version number. + * @access private + */ + var $RSSVersion; + + function RSSCreator091() { + $this->_setRSSVersion("0.91"); + $this->contentType = "application/rss+xml"; + } + + /** + * Sets this RSS feed's version number. + * @access private + */ + function _setRSSVersion($version) { + $this->RSSVersion = $version; + } + + /** + * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0. + * The feed will contain all items previously added in the same order. + * @return string the feed's complete text + */ + function createFeed() { + $feed = "encoding."\"?>\n"; + $feed.= $this->_createGeneratorComment(); + $feed.= $this->_createStylesheetReferences(); + $feed.= "RSSVersion."\">\n"; + $feed.= " \n"; + $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."\n"; + $this->descriptionTruncSize = 500; + $feed.= " ".$this->getDescription()."\n"; + $feed.= " ".$this->link."\n"; + $now = new FeedDate(); + $feed.= " ".htmlspecialchars($now->rfc822())."\n"; + $feed.= " ".FEEDCREATOR_VERSION."\n"; + + if ($this->image!=null) { + $feed.= " \n"; + $feed.= " ".$this->image->url."\n"; + $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->image->title),100)."\n"; + $feed.= " ".$this->image->link."\n"; + if ($this->image->width!="") { + $feed.= " ".$this->image->width."\n"; + } + if ($this->image->height!="") { + $feed.= " ".$this->image->height."\n"; + } + if ($this->image->description!="") { + $feed.= " ".$this->image->getDescription()."\n"; + } + $feed.= " \n"; + } + if ($this->language!="") { + $feed.= " ".$this->language."\n"; + } + if ($this->copyright!="") { + $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."\n"; + } + if ($this->editor!="") { + $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->editor),100)."\n"; + } + if ($this->webmaster!="") { + $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->webmaster),100)."\n"; + } + if ($this->pubDate!="") { + $pubDate = new FeedDate($this->pubDate); + $feed.= " ".htmlspecialchars($pubDate->rfc822())."\n"; + } + if ($this->category!="") { + $feed.= " ".htmlspecialchars($this->category)."\n"; + } + if ($this->docs!="") { + $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->docs),500)."\n"; + } + if ($this->ttl!="") { + $feed.= " ".htmlspecialchars($this->ttl)."\n"; + } + if ($this->rating!="") { + $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->rating),500)."\n"; + } + if ($this->skipHours!="") { + $feed.= " ".htmlspecialchars($this->skipHours)."\n"; + } + if ($this->skipDays!="") { + $feed.= " ".htmlspecialchars($this->skipDays)."\n"; + } + $feed.= $this->_createAdditionalElements($this->additionalElements, " "); + + for ($i=0;$iitems);$i++) { + $feed.= " \n"; + $feed.= " ".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."\n"; + $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; + $feed.= " ".$this->items[$i]->getDescription()."\n"; + + if ($this->items[$i]->author!="") { + $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; + } + /* + // on hold + if ($this->items[$i]->source!="") { + $feed.= " ".htmlspecialchars($this->items[$i]->source)."\n"; + } + */ + if ($this->items[$i]->category!="") { + $feed.= " ".htmlspecialchars($this->items[$i]->category)."\n"; + } + if ($this->items[$i]->comments!="") { + $feed.= " ".htmlspecialchars($this->items[$i]->comments)."\n"; + } + if ($this->items[$i]->date!="") { + $itemDate = new FeedDate($this->items[$i]->date); + $feed.= " ".htmlspecialchars($itemDate->rfc822())."\n"; + } + if ($this->items[$i]->guid!="") { + $feed.= " ".htmlspecialchars($this->items[$i]->guid)."\n"; + } + $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); + $feed.= " \n"; + } + $feed.= " \n"; + $feed.= "\n"; + return $feed; + } +} + + + +/** + * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0. + * + * @see http://backend.userland.com/rss + * @since 1.3 + * @author Kai Blankenhorn + */ +class RSSCreator20 extends RSSCreator091 { + + function RSSCreator20() { + parent::_setRSSVersion("2.0"); + } + +} + + +/** + * PIECreator01 is a FeedCreator that implements the emerging PIE specification, + * as in http://intertwingly.net/wiki/pie/Syntax. + * + * @deprecated + * @since 1.3 + * @author Scott Reynen and Kai Blankenhorn + */ +class PIECreator01 extends FeedCreator { + + function PIECreator01() { + $this->encoding = "utf-8"; + } + + function createFeed() { + $feed = "encoding."\"?>\n"; + $feed.= $this->_createStylesheetReferences(); + $feed.= "\n"; + $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."\n"; + $this->truncSize = 500; + $feed.= " ".$this->getDescription()."\n"; + $feed.= " ".$this->link."\n"; + for ($i=0;$iitems);$i++) { + $feed.= " \n"; + $feed.= " ".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."\n"; + $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; + $itemDate = new FeedDate($this->items[$i]->date); + $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; + $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; + $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; + $feed.= " ".htmlspecialchars($this->items[$i]->guid)."\n"; + if ($this->items[$i]->author!="") { + $feed.= " \n"; + $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; + if ($this->items[$i]->authorEmail!="") { + $feed.= " ".$this->items[$i]->authorEmail."\n"; + } + $feed.=" \n"; + } + $feed.= " \n"; + $feed.= "
".$this->items[$i]->getDescription()."
\n"; + $feed.= "
\n"; + $feed.= "
\n"; + } + $feed.= "
\n"; + return $feed; + } +} + + +/** + * AtomCreator03 is a FeedCreator that implements the atom specification, + * as in http://www.intertwingly.net/wiki/pie/FrontPage. + * Please note that just by using AtomCreator03 you won't automatically + * produce valid atom files. For example, you have to specify either an editor + * for the feed or an author for every single feed item. + * + * Some elements have not been implemented yet. These are (incomplete list): + * author URL, item author's email and URL, item contents, alternate links, + * other link content types than text/html. Some of them may be created with + * AtomCreator03::additionalElements. + * + * @see FeedCreator#additionalElements + * @since 1.6 + * @author Kai Blankenhorn , Scott Reynen + */ +class AtomCreator03 extends FeedCreator { + + function AtomCreator03() { + $this->contentType = "application/atom+xml"; + $this->encoding = "utf-8"; + } + + function createFeed() { + $feed = "encoding."\"?>\n"; + $feed.= $this->_createGeneratorComment(); + $feed.= $this->_createStylesheetReferences(); + $feed.= "language!="") { + $feed.= " xml:lang=\"".$this->language."\""; + } + $feed.= ">\n"; + $feed.= " ".htmlspecialchars($this->title)."\n"; + $feed.= " ".htmlspecialchars($this->description)."\n"; + $feed.= " link)."\"/>\n"; + $feed.= " ".htmlspecialchars($this->link)."\n"; + $now = new FeedDate(); + $feed.= " ".htmlspecialchars($now->iso8601())."\n"; + if ($this->editor!="") { + $feed.= " \n"; + $feed.= " ".$this->editor."\n"; + if ($this->editorEmail!="") { + $feed.= " ".$this->editorEmail."\n"; + } + $feed.= " \n"; + } + $feed.= " ".FEEDCREATOR_VERSION."\n"; + $feed.= $this->_createAdditionalElements($this->additionalElements, " "); + for ($i=0;$iitems);$i++) { + $feed.= " \n"; + $feed.= " ".htmlspecialchars(strip_tags($this->items[$i]->title))."\n"; + $feed.= " items[$i]->link)."\"/>\n"; + if ($this->items[$i]->date=="") { + $this->items[$i]->date = time(); + } + $itemDate = new FeedDate($this->items[$i]->date); + $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; + $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; + $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; + $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; + $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); + if ($this->items[$i]->author!="") { + $feed.= " \n"; + $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; + $feed.= " \n"; + } + if ($this->items[$i]->description!="") { + $feed.= " ".htmlspecialchars($this->items[$i]->description)."\n"; + } + $feed.= " \n"; + } + $feed.= "\n"; + return $feed; + } +} + + +/** + * MBOXCreator is a FeedCreator that implements the mbox format + * as described in http://www.qmail.org/man/man5/mbox.html + * + * @since 1.3 + * @author Kai Blankenhorn + */ +class MBOXCreator extends FeedCreator { + + function MBOXCreator() { + $this->contentType = "text/plain"; + $this->encoding = "ISO-8859-15"; + } + + function qp_enc($input = "", $line_max = 76) { + $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); + $lines = preg_split("/(?:\r\n|\r|\n)/", $input); + $eol = "\r\n"; + $escape = "="; + $output = ""; + while( list(, $line) = each($lines) ) { + //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary + $linlen = strlen($line); + $newline = ""; + for($i = 0; $i < $linlen; $i++) { + $c = substr($line, $i, 1); + $dec = ord($c); + if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only + $c = "=20"; + } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required + $h2 = floor($dec/16); $h1 = floor($dec%16); + $c = $escape.$hex["$h2"].$hex["$h1"]; + } + if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted + $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay + $newline = ""; + } + $newline .= $c; + } // end of for + $output .= $newline.$eol; + } + return trim($output); + } + + + /** + * Builds the MBOX contents. + * @return string the feed's complete text + */ + function createFeed() { + for ($i=0;$iitems);$i++) { + if ($this->items[$i]->author!="") { + $from = $this->items[$i]->author; + } else { + $from = $this->title; + } + $itemDate = new FeedDate($this->items[$i]->date); + $feed.= "From ".strtr(MBOXCreator::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n"; + $feed.= "Content-Type: text/plain;\n"; + $feed.= " charset=\"".$this->encoding."\"\n"; + $feed.= "Content-Transfer-Encoding: quoted-printable\n"; + $feed.= "Content-Type: text/plain\n"; + $feed.= "From: \"".MBOXCreator::qp_enc($from)."\"\n"; + $feed.= "Date: ".$itemDate->rfc822()."\n"; + $feed.= "Subject: ".MBOXCreator::qp_enc(FeedCreator::iTrunc($this->items[$i]->title,100))."\n"; + $feed.= "\n"; + $body = chunk_split(MBOXCreator::qp_enc($this->items[$i]->description)); + $feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body); + $feed.= "\n"; + $feed.= "\n"; + } + return $feed; + } + + /** + * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types. + * @return string the feed cache filename + * @since 1.4 + * @access private + */ + function _generateFilename() { + $fileInfo = pathinfo($_SERVER["PHP_SELF"]); + return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox"; + } +} + + +/** + * OPMLCreator is a FeedCreator that implements OPML 1.0. + * + * @see http://opml.scripting.com/spec + * @author Dirk Clemens, Kai Blankenhorn + * @since 1.5 + */ +class OPMLCreator extends FeedCreator { + + function OPMLCreator() { + $this->encoding = "utf-8"; + } + + function createFeed() { + $feed = "encoding."\"?>\n"; + $feed.= $this->_createGeneratorComment(); + $feed.= $this->_createStylesheetReferences(); + $feed.= "\n"; + $feed.= " \n"; + $feed.= " ".htmlspecialchars($this->title)."\n"; + if ($this->pubDate!="") { + $date = new FeedDate($this->pubDate); + $feed.= " ".$date->rfc822()."\n"; + } + if ($this->lastBuildDate!="") { + $date = new FeedDate($this->lastBuildDate); + $feed.= " ".$date->rfc822()."\n"; + } + if ($this->editor!="") { + $feed.= " ".$this->editor."\n"; + } + if ($this->editorEmail!="") { + $feed.= " ".$this->editorEmail."\n"; + } + $feed.= " \n"; + $feed.= " \n"; + for ($i=0;$iitems);$i++) { + $feed.= " items[$i]->title,"\n\r"," "))); + $feed.= " title=\"".$title."\""; + $feed.= " text=\"".$title."\""; + //$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\""; + $feed.= " url=\"".htmlspecialchars($this->items[$i]->link)."\""; + $feed.= "/>\n"; + } + $feed.= " \n"; + $feed.= "\n"; + return $feed; + } +} + + + +/** + * HTMLCreator is a FeedCreator that writes an HTML feed file to a specific + * location, overriding the createFeed method of the parent FeedCreator. + * The HTML produced can be included over http by scripting languages, or serve + * as the source for an IFrame. + * All output by this class is embedded in
tags to enable formatting + * using CSS. + * + * @author Pascal Van Hecke + * @since 1.7 + */ +class HTMLCreator extends FeedCreator { + + var $contentType = "text/html"; + + /** + * Contains HTML to be output at the start of the feed's html representation. + */ + var $header; + + /** + * Contains HTML to be output at the end of the feed's html representation. + */ + var $footer ; + + /** + * Contains HTML to be output between entries. A separator is only used in + * case of multiple entries. + */ + var $separator; + + /** + * Used to prefix the stylenames to make sure they are unique + * and do not clash with stylenames on the users' page. + */ + var $stylePrefix; + + /** + * Determines whether the links open in a new window or not. + */ + var $openInNewWindow = true; + + var $imageAlign ="right"; + + /** + * In case of very simple output you may want to get rid of the style tags, + * hence this variable. There's no equivalent on item level, but of course you can + * add strings to it while iterating over the items ($this->stylelessOutput .= ...) + * and when it is non-empty, ONLY the styleless output is printed, the rest is ignored + * in the function createFeed(). + */ + var $stylelessOutput =""; + + /** + * Writes the HTML. + * @return string the scripts's complete text + */ + function createFeed() { + // if there is styleless output, use the content of this variable and ignore the rest + if ($this->stylelessOutput!="") { + return $this->stylelessOutput; + } + + //if no stylePrefix is set, generate it yourself depending on the script name + if ($this->stylePrefix=="") { + $this->stylePrefix = str_replace(".", "_", $this->_generateFilename())."_"; + } + + //set an openInNewWindow_token_to be inserted or not + if ($this->openInNewWindow) { + $targetInsert = " target='_blank'"; + } + + // use this array to put the lines in and implode later with "document.write" javascript + $feedArray = array(); + if ($this->image!=null) { + $imageStr = "". + "".
+							FeedCreator::iTrunc(htmlspecialchars($this->image->title),100).
+							"image->width) { + $imageStr .=" width='".$this->image->width. "' "; + } + if ($this->image->height) { + $imageStr .=" height='".$this->image->height."' "; + } + $imageStr .="/>"; + $feedArray[] = $imageStr; + } + + if ($this->title) { + $feedArray[] = ""; + } + if ($this->getDescription()) { + $feedArray[] = "
". + str_replace("]]>", "", str_replace("getDescription())). + "
"; + } + + if ($this->header) { + $feedArray[] = "
".$this->header."
"; + } + + for ($i=0;$iitems);$i++) { + if ($this->separator and $i > 0) { + $feedArray[] = "
".$this->separator."
"; + } + + if ($this->items[$i]->title) { + if ($this->items[$i]->link) { + $feedArray[] = + ""; + } else { + $feedArray[] = + "
". + FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100). + "
"; + } + } + if ($this->items[$i]->getDescription()) { + $feedArray[] = + "
". + str_replace("]]>", "", str_replace("items[$i]->getDescription())). + "
"; + } + } + if ($this->footer) { + $feedArray[] = "
".$this->footer."
"; + } + + $feed= "".join($feedArray, "\r\n"); + return $feed; + } + + /** + * Overrrides parent to produce .html extensions + * + * @return string the feed cache filename + * @since 1.4 + * @access private + */ + function _generateFilename() { + $fileInfo = pathinfo($_SERVER["PHP_SELF"]); + return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".html"; + } +} + + +/** + * JSCreator is a class that writes a js file to a specific + * location, overriding the createFeed method of the parent HTMLCreator. + * + * @author Pascal Van Hecke + */ +class JSCreator extends HTMLCreator { + var $contentType = "text/javascript"; + + /** + * writes the javascript + * @return string the scripts's complete text + */ + function createFeed() + { + $feed = parent::createFeed(); + $feedArray = explode("\n",$feed); + + $jsFeed = ""; + foreach ($feedArray as $value) { + $jsFeed .= "document.write('".trim(addslashes($value))."');\n"; + } + return $jsFeed; + } + + /** + * Overrrides parent to produce .js extensions + * + * @return string the feed cache filename + * @since 1.4 + * @access private + */ + function _generateFilename() { + $fileInfo = pathinfo($_SERVER["PHP_SELF"]); + return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".js"; + } + +} + + + +/*** TEST SCRIPT ********************************************************* + +//include("feedcreator.class.php"); + +$rss = new UniversalFeedCreator(); +$rss->useCached(); +$rss->title = "PHP news"; +$rss->description = "daily news from the PHP scripting world"; + +//optional +//$rss->descriptionTruncSize = 500; +//$rss->descriptionHtmlSyndicated = true; +//$rss->xslStyleSheet = "http://feedster.com/rss20.xsl"; + +$rss->link = "http://www.dailyphp.net/news"; +$rss->feedURL = "http://www.dailyphp.net/".$PHP_SELF; + +$image = new FeedImage(); +$image->title = "dailyphp.net logo"; +$image->url = "http://www.dailyphp.net/images/logo.gif"; +$image->link = "http://www.dailyphp.net"; +$image->description = "Feed provided by dailyphp.net. Click to visit."; + +//optional +$image->descriptionTruncSize = 500; +$image->descriptionHtmlSyndicated = true; + +$rss->image = $image; + +// get your news items from somewhere, e.g. your database: +//mysql_select_db($dbHost, $dbUser, $dbPass); +//$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); +//while ($data = mysql_fetch_object($res)) { + $item = new FeedItem(); + $item->title = "This is an the test title of an item"; + $item->link = "http://localhost/item/"; + $item->description = "description in
HTML"; + + //optional + //item->descriptionTruncSize = 500; + $item->descriptionHtmlSyndicated = true; + + $item->date = time(); + $item->source = "http://www.dailyphp.net"; + $item->author = "John Doe"; + + $rss->addItem($item); +//} + +// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1, MBOX, OPML, ATOM0.3, HTML, JS +echo $rss->saveFeed("RSS0.91", "feed.xml"); + + + +***************************************************************************/ + +?> diff --git a/BSF/include/filter.inc.php b/BSF/include/filter.inc.php new file mode 100644 index 000000000..b77ddca98 --- /dev/null +++ b/BSF/include/filter.inc.php @@ -0,0 +1,141 @@ += SUBDATE( + CURRENT_DATE,INTERVAL '.$filter['recent_period'].' DAY)'; + + $filter['visible_images'] = implode(',', array_from_query($query, 'image_id')); + + if (empty($filter['visible_images'])) + { + // Must be not empty + $filter['visible_images'] = -1; + } + + // Save filter data on session + pwg_set_session_var('filter_enabled', $filter['enabled']); + pwg_set_session_var('filter_check_key', $filter['check_key']); + pwg_set_session_var('filter_recent_period', $filter['recent_period']); + pwg_set_session_var('filter_categories', serialize($filter['categories'])); + pwg_set_session_var('filter_visible_categories', $filter['visible_categories']); + pwg_set_session_var('filter_visible_images', $filter['visible_images']); + + } + else + { + // Read only data + $filter['check_key'] = pwg_get_session_var('filter_check_key', ''); + $filter['categories'] = unserialize(pwg_get_session_var('filter_categories', serialize(array()))); + $filter['visible_categories'] = pwg_get_session_var('filter_visible_categories', ''); + $filter['visible_images'] = pwg_get_session_var('filter_visible_images', ''); + } + + if (get_filter_page_value('add_notes')) + { + $header_notes[] = l10n_dec('note_filter_day', 'note_filter_days', $filter['recent_period']); + } +} +else +{ + if (pwg_get_session_var('filter_enabled', false)) + { + pwg_unset_session_var('filter_enabled'); + pwg_unset_session_var('filter_check_key'); + pwg_unset_session_var('filter_recent_period'); + pwg_unset_session_var('filter_categories'); + pwg_unset_session_var('filter_visible_categories'); + pwg_unset_session_var('filter_visible_images'); + } +} + + +?> diff --git a/BSF/include/functions.inc.php b/BSF/include/functions.inc.php new file mode 100644 index 000000000..a1b589999 --- /dev/null +++ b/BSF/include/functions.inc.php @@ -0,0 +1,1557 @@ + $option) + { + $options[$i] = str_replace("'", '',$option); + } + } + } + mysql_free_result($result); + return $options; +} + +// get_boolean transforms a string to a boolean value. If the string is +// "false" (case insensitive), then the boolean value false is returned. In +// any other case, true is returned. +function get_boolean( $string ) +{ + $boolean = true; + if ( preg_match( '/^false$/i', $string ) ) + { + $boolean = false; + } + return $boolean; +} + +/** + * returns boolean string 'true' or 'false' if the given var is boolean + * + * @param mixed $var + * @return mixed + */ +function boolean_to_string($var) +{ + if (is_bool($var)) + { + if ($var) + { + return 'true'; + } + else + { + return 'false'; + } + } + else + { + return $var; + } +} + +// The function get_moment returns a float value coresponding to the number +// of seconds since the unix epoch (1st January 1970) and the microseconds +// are precised : e.g. 1052343429.89276600 +function get_moment() +{ + $t1 = explode( ' ', microtime() ); + $t2 = explode( '.', $t1[0] ); + $t2 = $t1[1].'.'.$t2[1]; + return $t2; +} + +// The function get_elapsed_time returns the number of seconds (with 3 +// decimals precision) between the start time and the end time given. +function get_elapsed_time( $start, $end ) +{ + return number_format( $end - $start, 3, '.', ' ').' s'; +} + +// - The replace_space function replaces space and '-' characters +// by their HTML equivalent &nbsb; and − +// - The function does not replace characters in HTML tags +// - This function was created because IE5 does not respect the +// CSS "white-space: nowrap;" property unless space and minus +// characters are replaced like this function does. +// - Example : +//
My friend
+// ( 01234567891111111111222222222233 ) +// ( 0123456789012345678901 ) +// becomes : +//
My friend
+function replace_space( $string ) +{ + //return $string; + $return_string = ''; + // $remaining is the rest of the string where to replace spaces characters + $remaining = $string; + // $start represents the position of the next '<' character + // $end represents the position of the next '>' character + $start = 0; + $end = 0; + $start = strpos ( $remaining, '<' ); // -> 0 + $end = strpos ( $remaining, '>' ); // -> 16 + // as long as a '<' and his friend '>' are found, we loop + while ( is_numeric( $start ) and is_numeric( $end ) ) + { + // $treatment is the part of the string to treat + // In the first loop of our example, this variable is empty, but in the + // second loop, it equals 'My friend' + $treatment = substr ( $remaining, 0, $start ); + // Replacement of ' ' by his equivalent ' ' + $treatment = str_replace( ' ', ' ', $treatment ); + $treatment = str_replace( '-', '−', $treatment ); + // composing the string to return by adding the treated string and the + // following HTML tag -> 'My friend' + $return_string.= $treatment.substr( $remaining, $start, $end-$start+1 ); + // the remaining string is deplaced to the part after the '>' of this + // loop + $remaining = substr ( $remaining, $end + 1, strlen( $remaining ) ); + $start = strpos ( $remaining, '<' ); + $end = strpos ( $remaining, '>' ); + } + $treatment = str_replace( ' ', ' ', $remaining ); + $treatment = str_replace( '-', '−', $treatment ); + $return_string.= $treatment; + + return $return_string; +} + +// get_extension returns the part of the string after the last "." +function get_extension( $filename ) +{ + return substr( strrchr( $filename, '.' ), 1, strlen ( $filename ) ); +} + +// get_filename_wo_extension returns the part of the string before the last +// ".". +// get_filename_wo_extension( 'test.tar.gz' ) -> 'test.tar' +function get_filename_wo_extension( $filename ) +{ + $pos = strrpos( $filename, '.' ); + return ($pos===false) ? $filename : substr( $filename, 0, $pos); +} + +/** + * returns an array contening sub-directories, excluding "CVS" + * + * @param string $dir + * @return array + */ +function get_dirs($directory) +{ + $sub_dirs = array(); + + if ($opendir = opendir($directory)) + { + while ($file = readdir($opendir)) + { + if ($file != '.' + and $file != '..' + and is_dir($directory.'/'.$file) + and $file != 'CVS' + and $file != '.svn') + { + array_push($sub_dirs, $file); + } + } + } + return $sub_dirs; +} + +/** + * returns thumbnail directory name of input diretoty name + * make thumbnail directory is necessary + * set error messages on array messages + * + * @param: + * string $dirname + * arrayy $errors + * @return bool false on error else string directory name + */ +function mkget_thumbnail_dir($dirname, &$errors) +{ + $tndir = $dirname.'/thumbnail'; + if (!is_dir($tndir)) + { + if (!is_writable($dirname)) + { + array_push($errors, + '['.$dirname.'] : '.l10n('no_write_access')); + return false; + } + umask(0000); + mkdir($tndir, 0777); + } + + return $tndir; +} + +// The get_picture_size function return an array containing : +// - $picture_size[0] : final width +// - $picture_size[1] : final height +// The final dimensions are calculated thanks to the original dimensions and +// the maximum dimensions given in parameters. get_picture_size respects +// the width/height ratio +function get_picture_size( $original_width, $original_height, + $max_width, $max_height ) +{ + $width = $original_width; + $height = $original_height; + $is_original_size = true; + + if ( $max_width != "" ) + { + if ( $original_width > $max_width ) + { + $width = $max_width; + $height = floor( ( $width * $original_height ) / $original_width ); + } + } + if ( $max_height != "" ) + { + if ( $original_height > $max_height ) + { + $height = $max_height; + $width = floor( ( $height * $original_width ) / $original_height ); + $is_original_size = false; + } + } + if ( is_numeric( $max_width ) and is_numeric( $max_height ) + and $max_width != 0 and $max_height != 0 ) + { + $ratioWidth = $original_width / $max_width; + $ratioHeight = $original_height / $max_height; + if ( ( $ratioWidth > 1 ) or ( $ratioHeight > 1 ) ) + { + if ( $ratioWidth < $ratioHeight ) + { + $width = floor( $original_width / $ratioHeight ); + $height = $max_height; + } + else + { + $width = $max_width; + $height = floor( $original_height / $ratioWidth ); + } + $is_original_size = false; + } + } + $picture_size = array(); + $picture_size[0] = $width; + $picture_size[1] = $height; + return $picture_size; +} + +/* Returns true if the string appears to be encoded in UTF-8. (from wordpress) + * @param string Str + */ +function seems_utf8($Str) { # by bmorel at ssi dot fr + for ($i=0; $i 'A', chr(195).chr(129) => 'A', + chr(195).chr(130) => 'A', chr(195).chr(131) => 'A', + chr(195).chr(132) => 'A', chr(195).chr(133) => 'A', + chr(195).chr(135) => 'C', chr(195).chr(136) => 'E', + chr(195).chr(137) => 'E', chr(195).chr(138) => 'E', + chr(195).chr(139) => 'E', chr(195).chr(140) => 'I', + chr(195).chr(141) => 'I', chr(195).chr(142) => 'I', + chr(195).chr(143) => 'I', chr(195).chr(145) => 'N', + chr(195).chr(146) => 'O', chr(195).chr(147) => 'O', + chr(195).chr(148) => 'O', chr(195).chr(149) => 'O', + chr(195).chr(150) => 'O', chr(195).chr(153) => 'U', + chr(195).chr(154) => 'U', chr(195).chr(155) => 'U', + chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y', + chr(195).chr(159) => 's', chr(195).chr(160) => 'a', + chr(195).chr(161) => 'a', chr(195).chr(162) => 'a', + chr(195).chr(163) => 'a', chr(195).chr(164) => 'a', + chr(195).chr(165) => 'a', chr(195).chr(167) => 'c', + chr(195).chr(168) => 'e', chr(195).chr(169) => 'e', + chr(195).chr(170) => 'e', chr(195).chr(171) => 'e', + chr(195).chr(172) => 'i', chr(195).chr(173) => 'i', + chr(195).chr(174) => 'i', chr(195).chr(175) => 'i', + chr(195).chr(177) => 'n', chr(195).chr(178) => 'o', + chr(195).chr(179) => 'o', chr(195).chr(180) => 'o', + chr(195).chr(181) => 'o', chr(195).chr(182) => 'o', + chr(195).chr(182) => 'o', chr(195).chr(185) => 'u', + chr(195).chr(186) => 'u', chr(195).chr(187) => 'u', + chr(195).chr(188) => 'u', chr(195).chr(189) => 'y', + chr(195).chr(191) => 'y', + // Decompositions for Latin Extended-A + chr(196).chr(128) => 'A', chr(196).chr(129) => 'a', + chr(196).chr(130) => 'A', chr(196).chr(131) => 'a', + chr(196).chr(132) => 'A', chr(196).chr(133) => 'a', + chr(196).chr(134) => 'C', chr(196).chr(135) => 'c', + chr(196).chr(136) => 'C', chr(196).chr(137) => 'c', + chr(196).chr(138) => 'C', chr(196).chr(139) => 'c', + chr(196).chr(140) => 'C', chr(196).chr(141) => 'c', + chr(196).chr(142) => 'D', chr(196).chr(143) => 'd', + chr(196).chr(144) => 'D', chr(196).chr(145) => 'd', + chr(196).chr(146) => 'E', chr(196).chr(147) => 'e', + chr(196).chr(148) => 'E', chr(196).chr(149) => 'e', + chr(196).chr(150) => 'E', chr(196).chr(151) => 'e', + chr(196).chr(152) => 'E', chr(196).chr(153) => 'e', + chr(196).chr(154) => 'E', chr(196).chr(155) => 'e', + chr(196).chr(156) => 'G', chr(196).chr(157) => 'g', + chr(196).chr(158) => 'G', chr(196).chr(159) => 'g', + chr(196).chr(160) => 'G', chr(196).chr(161) => 'g', + chr(196).chr(162) => 'G', chr(196).chr(163) => 'g', + chr(196).chr(164) => 'H', chr(196).chr(165) => 'h', + chr(196).chr(166) => 'H', chr(196).chr(167) => 'h', + chr(196).chr(168) => 'I', chr(196).chr(169) => 'i', + chr(196).chr(170) => 'I', chr(196).chr(171) => 'i', + chr(196).chr(172) => 'I', chr(196).chr(173) => 'i', + chr(196).chr(174) => 'I', chr(196).chr(175) => 'i', + chr(196).chr(176) => 'I', chr(196).chr(177) => 'i', + chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij', + chr(196).chr(180) => 'J', chr(196).chr(181) => 'j', + chr(196).chr(182) => 'K', chr(196).chr(183) => 'k', + chr(196).chr(184) => 'k', chr(196).chr(185) => 'L', + chr(196).chr(186) => 'l', chr(196).chr(187) => 'L', + chr(196).chr(188) => 'l', chr(196).chr(189) => 'L', + chr(196).chr(190) => 'l', chr(196).chr(191) => 'L', + chr(197).chr(128) => 'l', chr(197).chr(129) => 'L', + chr(197).chr(130) => 'l', chr(197).chr(131) => 'N', + chr(197).chr(132) => 'n', chr(197).chr(133) => 'N', + chr(197).chr(134) => 'n', chr(197).chr(135) => 'N', + chr(197).chr(136) => 'n', chr(197).chr(137) => 'N', + chr(197).chr(138) => 'n', chr(197).chr(139) => 'N', + chr(197).chr(140) => 'O', chr(197).chr(141) => 'o', + chr(197).chr(142) => 'O', chr(197).chr(143) => 'o', + chr(197).chr(144) => 'O', chr(197).chr(145) => 'o', + chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe', + chr(197).chr(148) => 'R',chr(197).chr(149) => 'r', + chr(197).chr(150) => 'R',chr(197).chr(151) => 'r', + chr(197).chr(152) => 'R',chr(197).chr(153) => 'r', + chr(197).chr(154) => 'S',chr(197).chr(155) => 's', + chr(197).chr(156) => 'S',chr(197).chr(157) => 's', + chr(197).chr(158) => 'S',chr(197).chr(159) => 's', + chr(197).chr(160) => 'S', chr(197).chr(161) => 's', + chr(197).chr(162) => 'T', chr(197).chr(163) => 't', + chr(197).chr(164) => 'T', chr(197).chr(165) => 't', + chr(197).chr(166) => 'T', chr(197).chr(167) => 't', + chr(197).chr(168) => 'U', chr(197).chr(169) => 'u', + chr(197).chr(170) => 'U', chr(197).chr(171) => 'u', + chr(197).chr(172) => 'U', chr(197).chr(173) => 'u', + chr(197).chr(174) => 'U', chr(197).chr(175) => 'u', + chr(197).chr(176) => 'U', chr(197).chr(177) => 'u', + chr(197).chr(178) => 'U', chr(197).chr(179) => 'u', + chr(197).chr(180) => 'W', chr(197).chr(181) => 'w', + chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y', + chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z', + chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z', + chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z', + chr(197).chr(190) => 'z', chr(197).chr(191) => 's', + // Euro Sign + chr(226).chr(130).chr(172) => 'E', + // GBP (Pound) Sign + chr(194).chr(163) => ''); + + $string = strtr($string, $chars); + } else { + // Assume ISO-8859-1 if not UTF-8 + $chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158) + .chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194) + .chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202) + .chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210) + .chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218) + .chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227) + .chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235) + .chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243) + .chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251) + .chr(252).chr(253).chr(255); + + $chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy"; + + $string = strtr($string, $chars['in'], $chars['out']); + $double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254)); + $double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th'); + $string = str_replace($double_chars['in'], $double_chars['out'], $string); + } + + return $string; +} + +/** + * simplify a string to insert it into an URL + * + * @param string + * @return string + */ +function str2url($str) +{ + $str = remove_accents($str); + $str = preg_replace('/[^a-z0-9_\s\'\:\/\[\],-]/','',strtolower($str)); + $str = preg_replace('/[\s\'\:\/\[\],-]+/',' ',trim($str)); + $res = str_replace(' ','_',$str); + + return $res; +} + +//-------------------------------------------- Piwigo specific functions + +/** + * returns an array with a list of {language_code => language_name} + * + * @returns array + */ +function get_languages($target_charset = null) +{ + if ( empty($target_charset) ) + { + $target_charset = get_pwg_charset(); + } + $target_charset = strtolower($target_charset); + + $dir = opendir(PHPWG_ROOT_PATH.'language'); + $languages = array(); + + while ($file = readdir($dir)) + { + $path = PHPWG_ROOT_PATH.'language/'.$file; + if (is_dir($path) and !is_link($path) and file_exists($path.'/iso.txt')) + { + list($language_name) = @file($path.'/iso.txt'); + + $langdef = explode('.',$file); + if (count($langdef)>1) // (langCode,encoding) + { + $langdef[1] = strtolower($langdef[1]); + + if ( + $target_charset==$langdef[1] + or + ($target_charset=='utf-8' and $langdef[1]=='iso-8859-1') + or + ($target_charset=='iso-8859-1' and + in_array( substr($langdef[0],2), array('en','fr','de','es','it','nl'))) + ) + { + $language_name = convert_charset($language_name, + $langdef[1], $target_charset); + $languages[ $langdef[0] ] = $language_name; + } + else + continue; // the language encoding is not compatible with our charset + } + else + { // UTF-8 + $language_name = convert_charset($language_name, + 'utf-8', $target_charset); + $languages[$file] = $language_name; + } + } + } + closedir($dir); + @asort($languages); + @reset($languages); + + return $languages; +} + +function pwg_log($image_id = null, $image_type = null) +{ + global $conf, $user, $page; + + $do_log = true; + if (!$conf['log']) + { + $do_log = false; + } + if (is_admin() and !$conf['history_admin']) + { + $do_log = false; + } + if (is_a_guest() and !$conf['history_guest']) + { + $do_log = false; + } + + $do_log = trigger_event('pwg_log_allowed', $do_log, $image_id, $image_type); + + if (!$do_log) + { + return false; + } + + $tags_string = null; + if (isset($page['section']) and $page['section'] == 'tags') + { + $tag_ids = array(); + foreach ($page['tags'] as $tag) + { + array_push($tag_ids, $tag['id']); + } + + $tags_string = implode(',', $tag_ids); + } + + $query = ' +INSERT INTO '.HISTORY_TABLE.' + ( + date, + time, + user_id, + IP, + section, + category_id, + image_id, + image_type, + tag_ids + ) + VALUES + ( + CURDATE(), + CURTIME(), + '.$user['id'].', + \''.$_SERVER['REMOTE_ADDR'].'\', + '.(isset($page['section']) ? "'".$page['section']."'" : 'NULL').', + '.(isset($page['category']['id']) ? $page['category']['id'] : 'NULL').', + '.(isset($image_id) ? $image_id : 'NULL').', + '.(isset($image_type) ? "'".$image_type."'" : 'NULL').', + '.(isset($tags_string) ? "'".$tags_string."'" : 'NULL').' + ) +;'; + pwg_query($query); + + return true; +} + +// format_date returns a formatted date for display. The date given in +// argument can be a unixdate (number of seconds since the 01.01.1970) or an +// american format (2003-09-15). By option, you can show the time. The +// output is internationalized. +// +// format_date( "2003-09-15", 'us', true ) -> "Monday 15 September 2003 21:52" +function format_date($date, $type = 'us', $show_time = false) +{ + global $lang; + + list($year,$month,$day,$hour,$minute,$second) = array(0,0,0,0,0,0); + + switch ( $type ) + { + case 'us' : + { + list($year,$month,$day) = explode('-', $date); + break; + } + case 'unix' : + { + list($year,$month,$day,$hour,$minute) = + explode('.', date('Y.n.j.G.i', $date)); + break; + } + case 'mysql_datetime' : + { + preg_match('/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/', + $date, $out); + list($year,$month,$day,$hour,$minute,$second) = + array($out[1],$out[2],$out[3],$out[4],$out[5],$out[6]); + break; + } + } + $formated_date = ''; + // before 1970, Microsoft Windows can't mktime + if ($year >= 1970) + { + // we ask midday because Windows think it's prior to midnight with a + // zero and refuse to work + $formated_date.= $lang['day'][date('w', mktime(12,0,0,$month,$day,$year))]; + } + $formated_date.= ' '.$day; + $formated_date.= ' '.$lang['month'][(int)$month]; + $formated_date.= ' '.$year; + if ($show_time) + { + $formated_date.= ' '.$hour.':'.$minute; + } + + return $formated_date; +} + +function pwg_query($query) +{ + global $conf,$page,$debug,$t2; + + $start = get_moment(); + $result = mysql_query($query) or my_error($query."\n"); + + $time = get_moment() - $start; + + if (!isset($page['count_queries'])) + { + $page['count_queries'] = 0; + $page['queries_time'] = 0; + } + + $page['count_queries']++; + $page['queries_time']+= $time; + + if ($conf['show_queries']) + { + $output = ''; + $output.= '
['.$page['count_queries'].'] ';
+    $output.= "\n".$query;
+    $output.= "\n".'(this query time : ';
+    $output.= ''.number_format($time, 3, '.', ' ').' s)';
+    $output.= "\n".'(total SQL time  : ';
+    $output.= number_format($page['queries_time'], 3, '.', ' ').' s)';
+    $output.= "\n".'(total time      : ';
+    $output.= number_format( ($time+$start-$t2), 3, '.', ' ').' s)';
+    if ( $result!=null and preg_match('/\s*SELECT\s+/i',$query) )
+    {
+      $output.= "\n".'(num rows        : ';
+      $output.= mysql_num_rows($result).' )';
+    }
+    elseif ( $result!=null
+      and preg_match('/\s*INSERT|UPDATE|REPLACE|DELETE\s+/i',$query) )
+    {
+      $output.= "\n".'(affected rows   : ';
+      $output.= mysql_affected_rows().' )';
+    }
+    $output.= "
\n"; + + $debug .= $output; + } + + return $result; +} + +function pwg_debug( $string ) +{ + global $debug,$t2,$page; + + $now = explode( ' ', microtime() ); + $now2 = explode( '.', $now[0] ); + $now2 = $now[1].'.'.$now2[1]; + $time = number_format( $now2 - $t2, 3, '.', ' ').' s'; + $debug .= '

'; + $debug.= '['.$time.', '; + $debug.= $page['count_queries'].' queries] : '.$string; + $debug.= "

\n"; +} + +/** + * Redirects to the given URL (HTTP method) + * + * Note : once this function called, the execution doesn't go further + * (presence of an exit() instruction. + * + * @param string $url + * @return void + */ +function redirect_http( $url ) +{ + if (ob_get_length () !== FALSE) + { + ob_clean(); + } + // default url is on html format + $url = html_entity_decode($url); + header('Request-URI: '.$url); + header('Content-Location: '.$url); + header('Location: '.$url); + exit(); +} + +/** + * Redirects to the given URL (HTML method) + * + * Note : once this function called, the execution doesn't go further + * (presence of an exit() instruction. + * + * @param string $url + * @param string $title_msg + * @param integer $refreh_time + * @return void + */ +function redirect_html( $url , $msg = '', $refresh_time = 0) +{ + global $user, $template, $lang_info, $conf, $lang, $t2, $page, $debug; + + if (!isset($lang_info)) + { + $user = build_user( $conf['guest_id'], true); + load_language('common.lang'); + trigger_action('loading_lang'); + load_language('local.lang'); + list($tmpl, $thm) = explode('/', get_default_template()); + $template = new Template(PHPWG_ROOT_PATH.'template/'.$tmpl, $thm); + } + else + { + $template = new Template(PHPWG_ROOT_PATH.'template/'.$user['template'], $user['theme']); + } + + if (empty($msg)) + { + $redirect_msg = l10n('redirect_msg'); + } + else + { + $redirect_msg = $msg; + } + $redirect_msg = nl2br($redirect_msg); + + $refresh = $refresh_time; + $url_link = $url; + $title = 'redirection'; + + $template->set_filenames( array( 'redirect' => 'redirect.tpl' ) ); + + include( PHPWG_ROOT_PATH.'include/page_header.php' ); + + $template->set_filenames( array( 'redirect' => 'redirect.tpl' ) ); + $template->parse('redirect'); + + include( PHPWG_ROOT_PATH.'include/page_tail.php' ); + + exit(); +} + +/** + * Redirects to the given URL (Switch to HTTP method or HTML method) + * + * Note : once this function called, the execution doesn't go further + * (presence of an exit() instruction. + * + * @param string $url + * @param string $title_msg + * @param integer $refreh_time + * @return void + */ +function redirect( $url , $msg = '', $refresh_time = 0) +{ + global $conf; + + // with RefeshTime <> 0, only html must be used + if ($conf['default_redirect_method']=='http' + and $refresh_time==0 + and !headers_sent() + ) + { + redirect_http($url); + } + else + { + redirect_html($url, $msg, $refresh_time); + } +} + +/** + * returns $_SERVER['QUERY_STRING'] whitout keys given in parameters + * + * @param array $rejects + * @param boolean $escape - if true escape & to & (for html) + * @returns string + */ +function get_query_string_diff($rejects=array(), $escape=true) +{ + $query_string = ''; + + $str = $_SERVER['QUERY_STRING']; + parse_str($str, $vars); + + $is_first = true; + foreach ($vars as $key => $value) + { + if (!in_array($key, $rejects)) + { + $query_string.= $is_first ? '?' : ($escape ? '&' : '&' ); + $is_first = false; + $query_string.= $key.'='.$value; + } + } + + return $query_string; +} + +function url_is_remote($url) +{ + if ( strncmp($url, 'http://', 7)==0 + or strncmp($url, 'https://', 8)==0 ) + { + return true; + } + return false; +} + +/** + * returns available template/theme + */ +function get_pwg_themes() +{ + global $conf; + $themes = array(); + + $template_dir = PHPWG_ROOT_PATH.'template'; + + foreach (get_dirs($template_dir) as $template) + { + foreach (get_dirs($template_dir.'/'.$template.'/theme') as $theme) + { + if ( ($template.'/'.$theme) != $conf['admin_layout'] ) + array_push($themes, $template.'/'.$theme); + } + } + + return $themes; +} + +/* Returns the PATH to the thumbnail to be displayed. If the element does not + * have a thumbnail, the default mime image path is returned. The PATH can be + * used in the php script, but not sent to the browser. + * @param array element_info assoc array containing element info from db + * at least 'path', 'tn_ext' and 'id' should be present + */ +function get_thumbnail_path($element_info) +{ + $path = get_thumbnail_location($element_info); + if ( !url_is_remote($path) ) + { + $path = PHPWG_ROOT_PATH.$path; + } + return $path; +} + +/* Returns the URL of the thumbnail to be displayed. If the element does not + * have a thumbnail, the default mime image url is returned. The URL can be + * sent to the browser, but not used in the php script. + * @param array element_info assoc array containing element info from db + * at least 'path', 'tn_ext' and 'id' should be present + */ +function get_thumbnail_url($element_info) +{ + $path = get_thumbnail_location($element_info); + if ( !url_is_remote($path) ) + { + $path = embellish_url(get_root_url().$path); + } + + // plugins want another url ? + $path = trigger_event('get_thumbnail_url', $path, $element_info); + return $path; +} + +/* returns the relative path of the thumnail with regards to to the root +of piwigo (not the current page!).This function is not intended to be +called directly from code.*/ +function get_thumbnail_location($element_info) +{ + global $conf; + if ( !empty( $element_info['tn_ext'] ) ) + { + $path = substr_replace( + get_filename_wo_extension($element_info['path']), + '/thumbnail/'.$conf['prefix_thumbnail'], + strrpos($element_info['path'],'/'), + 1 + ); + $path.= '.'.$element_info['tn_ext']; + } + else + { + $path = get_themeconf('mime_icon_dir') + .strtolower(get_extension($element_info['path'])).'.png'; + } + + // plugins want another location ? + $path = trigger_event( 'get_thumbnail_location', $path, $element_info); + return $path; +} + +/* returns the title of the thumnail */ +function get_thumbnail_title($element_info) +{ + // message in title for the thumbnail + if (isset($element_info['file'])) + { + $thumbnail_title = $element_info['file']; + } + else + { + $thumbnail_title = ''; + } + + if (!empty($element_info['filesize'])) + { + $thumbnail_title .= ' : '.l10n_dec('%d Kb', '%d Kb', $element_info['filesize']); + } + + return $thumbnail_title; +} + +// my_error returns (or send to standard output) the message concerning the +// error occured for the last mysql query. +function my_error($header) +{ + global $conf; + + $error = '
';
+  $error.= $header;
+  $error.= '[mysql error '.mysql_errno().'] ';
+  $error.= mysql_error();
+  $error.= '
'; + + if ($conf['die_on_sql_error']) + { + die($error); + } + else + { + echo $error; + } +} + +/** + * creates an array based on a query, this function is a very common pattern + * used here + * + * @param string $query + * @param string $fieldname + * @return array + */ +function array_from_query($query, $fieldname) +{ + $array = array(); + + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($array, $row[$fieldname]); + } + + return $array; +} + +/** + * fill the current user caddie with given elements, if not already in + * caddie + * + * @param array elements_id + */ +function fill_caddie($elements_id) +{ + global $user; + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + + $query = ' +SELECT element_id + FROM '.CADDIE_TABLE.' + WHERE user_id = '.$user['id'].' +;'; + $in_caddie = array_from_query($query, 'element_id'); + + $caddiables = array_diff($elements_id, $in_caddie); + + $datas = array(); + + foreach ($caddiables as $caddiable) + { + array_push($datas, array('element_id' => $caddiable, + 'user_id' => $user['id'])); + } + + if (count($caddiables) > 0) + { + mass_inserts(CADDIE_TABLE, array('element_id','user_id'), $datas); + } +} + +/** + * returns the element name from its filename + * + * @param string filename + * @return string name + */ +function get_name_from_file($filename) +{ + return str_replace('_',' ',get_filename_wo_extension($filename)); +} + +/** + * returns the corresponding value from $lang if existing. Else, the key is + * returned + * + * @param string key + * @return string + */ +function l10n($key) +{ + global $lang, $conf; + + if ($conf['debug_l10n'] and !isset($lang[$key]) and !empty($key)) + { + trigger_error('[l10n] language key "'.$key.'" is not defined', E_USER_NOTICE); + } + + return isset($lang[$key]) ? $lang[$key] : $key; +} + +/** + * returns the prinft value for strings including %d + * return is concorded with decimal value (singular, plural) + * + * @param singular string key + * @param plural string key + * @param decimal value + * @return string + */ +function l10n_dec($singular_fmt_key, $plural_fmt_key, $decimal) +{ + global $lang_info; + + return + sprintf( + l10n(( + (($decimal > 1) or ($decimal == 0 and $lang_info['zero_plural'])) + ? $plural_fmt_key + : $singular_fmt_key + )), $decimal); +} +/* + * returns a single element to use with l10n_args + * + * @param string key: translation key + * @param array/string/../number args: + * arguments to use on sprintf($key, args) + * if args is a array, each values are used on sprintf + * @return string + */ +function get_l10n_args($key, $args) +{ + if (is_array($args)) + { + $key_arg = array_merge(array($key), $args); + } + else + { + $key_arg = array($key, $args); + } + return array('key_args' => $key_arg); +} + +/* + * returns a string with formated with l10n_args elements + * + * @param element/array $key_args: element or array of l10n_args elements + * @param $sep: if $key_args is array, + * separator is used when translated l10n_args elements are concated + * @return string + */ +function l10n_args($key_args, $sep = "\n") +{ + if (is_array($key_args)) + { + foreach ($key_args as $key => $element) + { + if (isset($result)) + { + $result .= $sep; + } + else + { + $result = ''; + } + + if ($key === 'key_args') + { + array_unshift($element, l10n(array_shift($element))); + $result .= call_user_func_array('sprintf', $element); + } + else + { + $result .= l10n_args($element, $sep); + } + } + } + else + { + die('l10n_args: Invalid arguments'); + } + + return $result; +} + +/** + * returns the corresponding value from $themeconf if existing. Else, the + * key is returned + * + * @param string key + * @return string + */ +function get_themeconf($key) +{ + global $template; + + return $template->get_themeconf($key); +} + +/** + * Returns webmaster mail address depending on $conf['webmaster_id'] + * + * @return string + */ +function get_webmaster_mail_address() +{ + global $conf; + + $query = ' +SELECT '.$conf['user_fields']['email'].' + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['id'].' = '.$conf['webmaster_id'].' +;'; + list($email) = mysql_fetch_array(pwg_query($query)); + + return $email; +} + +/** + * which upgrades are available ? + * + * @return array + */ +function get_available_upgrade_ids() +{ + $upgrades_path = PHPWG_ROOT_PATH.'install/db'; + + $available_upgrade_ids = array(); + + if ($contents = opendir($upgrades_path)) + { + while (($node = readdir($contents)) !== false) + { + if (is_file($upgrades_path.'/'.$node) + and preg_match('/^(.*?)-database\.php$/', $node, $match)) + { + array_push($available_upgrade_ids, $match[1]); + } + } + } + natcasesort($available_upgrade_ids); + + return $available_upgrade_ids; +} + +/** + * Add configuration parameters from database to global $conf array + * + * @return void + */ +function load_conf_from_db($condition = '') +{ + global $conf; + + $query = ' +SELECT param, value + FROM '.CONFIG_TABLE.' + '.(!empty($condition) ? 'WHERE '.$condition : '').' +;'; + $result = pwg_query($query); + + if ((mysql_num_rows($result) == 0) and !empty($condition)) + { + die('No configuration data'); + } + + while ($row = mysql_fetch_array($result)) + { + $conf[ $row['param'] ] = isset($row['value']) ? $row['value'] : ''; + + // If the field is true or false, the variable is transformed into a + // boolean value. + if ($conf[$row['param']] == 'true' or $conf[$row['param']] == 'false') + { + $conf[ $row['param'] ] = get_boolean($conf[ $row['param'] ]); + } + } +} + +/** + * Prepends and appends a string at each value of the given array. + * + * @param array + * @param string prefix to each array values + * @param string suffix to each array values + */ +function prepend_append_array_items($array, $prepend_str, $append_str) +{ + array_walk( + $array, + create_function('&$s', '$s = "'.$prepend_str.'".$s."'.$append_str.'";') + ); + + return $array; +} + +/** + * creates an hashed based on a query, this function is a very common + * pattern used here. Among the selected columns fetched, choose one to be + * the key, another one to be the value. + * + * @param string $query + * @param string $keyname + * @param string $valuename + * @return array + */ +function simple_hash_from_query($query, $keyname, $valuename) +{ + $array = array(); + + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $array[ $row[$keyname] ] = $row[$valuename]; + } + + return $array; +} + +/** + * creates an hashed based on a query, this function is a very common + * pattern used here. The key is given as parameter, the value is an associative + * array. + * + * @param string $query + * @param string $keyname + * @return array + */ +function hash_from_query($query, $keyname) +{ + $array = array(); + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $array[ $row[$keyname] ] = $row; + } + return $array; +} + +/** + * Return basename of the current script + * Lower case convertion is applied on return value + * Return value is without file extention ".php" + * + * @param void + * + * @return script basename + */ +function script_basename() +{ + global $conf; + + foreach (array('SCRIPT_NAME', 'SCRIPT_FILENAME', 'PHP_SELF') as $value) + { + $continue = !empty($_SERVER[$value]); + if ($continue) + { + $filename = strtolower($_SERVER[$value]); + + if ($conf['php_extension_in_urls']) + { + $continue = get_extension($filename) === 'php'; + } + + if ($continue) + { + $basename = basename($filename, '.php'); + $continue = !empty($basename); + } + + if ($continue) + { + return $basename; + } + } + } + + return ''; +} + +/** + * Return value for the current page define on $conf['filter_pages'] + * Îf value is not defined, default value are returned + * + * @param value name + * + * @return filter page value + */ +function get_filter_page_value($value_name) +{ + global $conf; + + $page_name = script_basename(); + + if (isset($conf['filter_pages'][$page_name][$value_name])) + { + return $conf['filter_pages'][$page_name][$value_name]; + } + else if (isset($conf['filter_pages']['default'][$value_name])) + { + return $conf['filter_pages']['default'][$value_name]; + } + else + { + return null; + } +} + +/** + * returns the character set of data sent to browsers / received from forms + */ +function get_pwg_charset() +{ + defined('PWG_CHARSET') or die('load_language PWG_CHARSET undefined'); + return PWG_CHARSET; +} + +/** + * includes a language file or returns the content of a language file + * availability of the file + * + * in descending order of preference: + * param language, user language, default language + * Piwigo default language. + * + * @param string filename + * @param string dirname + * @param string language + * @param bool return_content - if true the file content is returned otherwise + * the file is evaluated as php + * @return boolean success status or a string if return_content is true + */ +function load_language($filename, $dirname = '', $language = '', + $return_content=false, $target_charset=null) +{ + global $user; + + if (!$return_content) + { + $filename .= '.php'; //MAYBE to do .. load .po and .mo localization files + } + if (empty($dirname)) + { + $dirname = PHPWG_ROOT_PATH; + } + $dirname .= 'language/'; + + $languages = array(); + if ( !empty($language) ) + { + $languages[] = $language; + } + if ( !empty($user['language']) ) + { + $languages[] = $user['language']; + } + if ( defined('PHPWG_INSTALLED') ) + { + $languages[] = get_default_language(); + } + $languages[] = PHPWG_DEFAULT_LANGUAGE; + $languages = array_unique($languages); + + if ( empty($target_charset) ) + { + $target_charset = get_pwg_charset(); + } + $target_charset = strtolower($target_charset); + $source_charset = ''; + $source_file = ''; + foreach ($languages as $language) + { + $dir = $dirname.$language; + + // exact charset match - no conversion required + $f = $dir.'.'.$target_charset.'/'.$filename; + if (file_exists($f)) + { + $source_file = $f; + break; + } + + // UTF-8 ? + $f = $dir.'/'.$filename; + if (file_exists($f)) + { + $source_charset = 'utf-8'; + $source_file = $f; + break; + } + + if ($target_charset=='utf-8') + { // we accept conversion from ISO-8859-1 to UTF-8 + $f = $dir.'.iso-8859-1/'.$filename; + if (file_exists($f)) + { + $source_charset = 'iso-8859-1'; + $source_file = $f; + break; + } + } + } + + if ( !empty($source_file) ) + { + if (!$return_content) + { + @include($source_file); + $load_lang = @$lang; + $load_lang_info = @$lang_info; + + global $lang, $lang_info; + if ( !isset($lang) ) $lang=array(); + if ( !isset($lang_info) ) $lang_info=array(); + + if ( !empty($source_charset) and $source_charset!=$target_charset) + { + if ( is_array($load_lang) ) + { + foreach ($load_lang as $k => $v) + { + if ( is_array($v) ) + { + $func = create_function('$v', 'return convert_charset($v, "'.$source_charset.'","'.$target_charset.'");' ); + $lang[$k] = array_map($func, $v); + } + else + $lang[$k] = convert_charset($v, $source_charset, $target_charset); + } + } + if ( is_array($load_lang_info) ) + { + foreach ($load_lang_info as $k => $v) + { + $lang_info[$k] = convert_charset($v, $source_charset, $target_charset); + } + } + } + else + { + $lang = array_merge( $lang, (array)$load_lang ); + $lang_info = array_merge( $lang_info, (array)$load_lang_info ); + } + return true; + } + else + { + $content = @file_get_contents($source_file); + if ( !empty($source_charset) and $source_charset!=$target_charset) + { + $content = convert_charset($content, $source_charset, $target_charset); + } + return $content; + } + } + return false; +} + +/** + * converts a string from a character set to another character set + * @param string str the string to be converted + * @param string source_charset the character set in which the string is encoded + * @param string dest_charset the destination character set + */ +function convert_charset($str, $source_charset, $dest_charset) +{ + if ($source_charset==$dest_charset) + return $str; + if ($source_charset=='iso-8859-1' and $dest_charset=='utf-8') + { + return utf8_encode($str); + } + if ($source_charset=='utf-8' and $dest_charset=='iso-8859-1') + { + return utf8_decode($str); + } + if (function_exists('iconv')) + { + return iconv($source_charset, $dest_charset, $str); + } + if (function_exists('mb_convert_encoding')) + { + return mb_convert_encoding( $str, $dest_charset, $source_charset ); + } + return $str; //??? +} +?> \ No newline at end of file diff --git a/BSF/include/functions_calendar.inc.php b/BSF/include/functions_calendar.inc.php new file mode 100644 index 000000000..baa72b927 --- /dev/null +++ b/BSF/include/functions_calendar.inc.php @@ -0,0 +1,295 @@ + 'id' + ), + 'AND', false + ); + } + else + { + $inner_sql .= ' + '.get_sql_condition_FandF + ( + array + ( + 'forbidden_categories' => 'category_id', + 'visible_categories' => 'category_id', + 'visible_images' => 'id' + ), + 'WHERE', true + ); + } + } + else + { + if ( empty($page['items']) ) + { + return; // nothing to do + } + $inner_sql .= ' +WHERE id IN (' . implode(',',$page['items']) .')'; + } + +//-------------------------------------- initialize the calendar parameters --- + pwg_debug('start initialize_calendar'); + + $fields = array( + // Created + 'created' => array( + 'label' => l10n('Creation date'), + ), + // Posted + 'posted' => array( + 'label' => l10n('Post date'), + ), + ); + + $styles = array( + // Monthly style + 'monthly' => array( + 'include' => 'calendar_monthly.class.php', + 'view_calendar' => true, + ), + // Weekly style + 'weekly' => array( + 'include' => 'calendar_weekly.class.php', + 'view_calendar' => false, + ), + ); + + $views = array(CAL_VIEW_LIST,CAL_VIEW_CALENDAR); + + // Retrieve calendar field + if ( !isset( $fields[ $page['chronology_field'] ] ) ) + { + die('bad chronology field'); + } + + // Retrieve style + if ( !isset( $styles[ $page['chronology_style'] ] ) ) + { + $page['chronology_style'] = 'monthly'; + } + $cal_style = $page['chronology_style']; + include(PHPWG_ROOT_PATH.'include/'. $styles[$cal_style]['include']); + $calendar = new Calendar(); + + // Retrieve view + + if ( !isset($page['chronology_view']) or + !in_array( $page['chronology_view'], $views ) ) + { + $page['chronology_view'] = CAL_VIEW_LIST; + } + + if ( CAL_VIEW_CALENDAR==$page['chronology_view'] and + !$styles[$cal_style]['view_calendar'] ) + { + + $page['chronology_view'] = CAL_VIEW_LIST; + } + + // perform a sanity check on $requested + if (!isset($page['chronology_date'])) + { + $page['chronology_date'] = array(); + } + while ( count($page['chronology_date']) > 3) + { + array_pop($page['chronology_date']); + } + + $any_count = 0; + for ($i = 0; $i < count($page['chronology_date']); $i++) + { + if ($page['chronology_date'][$i] == 'any') + { + if ($page['chronology_view'] == CAL_VIEW_CALENDAR) + {// we dont allow any in calendar view + while ($i < count($page['chronology_date'])) + { + array_pop($page['chronology_date']); + } + break; + } + $any_count++; + } + elseif ($page['chronology_date'][$i] == '') + { + while ($i < count($page['chronology_date'])) + { + array_pop($page['chronology_date']); + } + } + else + { + $page['chronology_date'][$i] = (int)$page['chronology_date'][$i]; + } + } + if ($any_count == 3) + { + array_pop($page['chronology_date']); + } + + $calendar->initialize($inner_sql); + + //echo ('
'. var_export($calendar, true) . '
'); + + $must_show_list = true; // true until calendar generates its own display + if (script_basename() != 'picture') // basename without file extention + { + if ($calendar->generate_category_content()) + { + $page['items'] = array(); + $must_show_list = false; + } + + $page['comment'] = ''; + $template->assign('FILE_CHRONOLOGY_VIEW', 'month_calendar.tpl'); + + foreach ($styles as $style => $style_data) + { + foreach ($views as $view) + { + if ( $style_data['view_calendar'] or $view != CAL_VIEW_CALENDAR) + { + $selected = false; + + if ($style!=$cal_style) + { + $chronology_date = array(); + if ( isset($page['chronology_date'][0]) ) + { + array_push($chronology_date, $page['chronology_date'][0]); + } + } + else + { + $chronology_date = $page['chronology_date']; + } + $url = duplicate_index_url( + array( + 'chronology_style' => $style, + 'chronology_view' => $view, + 'chronology_date' => $chronology_date, + ) + ); + + if ($style==$cal_style and $view==$page['chronology_view'] ) + { + $selected = true; + } + + $template->append( + 'chronology_views', + array( + 'VALUE' => $url, + 'CONTENT' => l10n('chronology_'.$style.'_'.$view), + 'SELECTED' => $selected, + ) + ); + } + } + } + $url = duplicate_index_url( + array(), array('start', 'chronology_date') + ); + $calendar_title = '' + .$fields[$page['chronology_field']]['label'].''; + $calendar_title.= $calendar->get_display_name(); + $template->assign('chronology', + array( + 'TITLE' => $calendar_title + ) + ); + } // end category calling + + if ($must_show_list) + { + $query = 'SELECT DISTINCT(id)'; + $query .= $calendar->inner_sql.' + '.$calendar->get_date_where(); + if ( isset($page['super_order_by']) ) + { + $query .= ' + '.$conf['order_by']; + } + else + { + if ( count($page['chronology_date'])==0 + or in_array('any', $page['chronology_date']) ) + {// selected period is very big so we show newest first + $order = ' DESC, '; + } + else + {// selected period is small (month,week) so we show oldest first + $order = ' ASC, '; + } + $order_by = str_replace( + 'ORDER BY ', + 'ORDER BY '.$calendar->date_field.$order, $conf['order_by'] + ); + $query .= ' + '.$order_by; + } + $page['items'] = array_from_query($query, 'id'); + } + pwg_debug('end initialize_calendar'); +} + +?> \ No newline at end of file diff --git a/BSF/include/functions_category.inc.php b/BSF/include/functions_category.inc.php new file mode 100644 index 000000000..721cc0038 --- /dev/null +++ b/BSF/include/functions_category.inc.php @@ -0,0 +1,509 @@ + restriction) + if (in_array($category_id, explode(',', $user['forbidden_categories']))) + { + access_denied(); + } +} + +function get_categories_menu() +{ + global $page, $user, $filter; + + $query = ' +SELECT '; + // From CATEGORIES_TABLE + $query.= ' + id, name, permalink, nb_images, global_rank,'; + // From USER_CACHE_CATEGORIES_TABLE + $query.= ' + date_last, max_date_last, count_images, count_categories'; + + // $user['forbidden_categories'] including with USER_CACHE_CATEGORIES_TABLE + $query.= ' +FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' + ON id = cat_id and user_id = '.$user['id']; + + // Always expand when filter is activated + if (!$user['expand'] and !$filter['enabled']) + { + $where = ' +(id_uppercat is NULL'; + if (isset($page['category'])) + { + $where .= ' OR id_uppercat IN ('.$page['category']['uppercats'].')'; + } + $where .= ')'; + } + else + { + $where = ' + '.get_sql_condition_FandF + ( + array + ( + 'visible_categories' => 'id', + ), + null, + true + ); + } + + $where = trigger_event('get_categories_menu_sql_where', + $where, $user['expand'], $filter['enabled'] ); + + $query.= ' +WHERE '.$where.' +;'; + + $result = pwg_query($query); + $cats = array(); + while ($row = mysql_fetch_assoc($result)) + { + array_push($cats, $row); + } + usort($cats, 'global_rank_compare'); + + // Update filtered data + if (function_exists('update_cats_with_filtered_data')) + { + update_cats_with_filtered_data($cats); + } + + return get_html_menu_category($cats, @$page['category'] ); +} + + +/** + * Retrieve informations about a category in the database + * + * Returns an array with following keys : + * + * - comment + * - dir : directory, might be empty for virtual categories + * - name : an array with indexes from 0 (lowest cat name) to n (most + * uppercat name findable) + * - nb_images + * - id_uppercat + * - site_id + * - + * + * @param int category id + * @return array + */ +function get_cat_info( $id ) +{ + $query = ' +SELECT * + FROM '.CATEGORIES_TABLE.' + WHERE id = '.$id.' +;'; + $cat = mysql_fetch_assoc(pwg_query($query)); + if (empty($cat)) + return null; + + foreach ($cat as $k => $v) + { + // If the field is true or false, the variable is transformed into a + // boolean value. + if ($cat[$k] == 'true' or $cat[$k] == 'false') + { + $cat[$k] = get_boolean( $cat[$k] ); + } + } + + $upper_ids = explode(',', $cat['uppercats']); + if ( count($upper_ids)==1 ) + {// no need to make a query for level 1 + $cat['upper_names'] = array( + array( + 'id' => $cat['id'], + 'name' => $cat['name'], + 'permalink' => $cat['permalink'], + ) + ); + } + else + { + $names = array(); + $query = ' + SELECT id, name, permalink + FROM '.CATEGORIES_TABLE.' + WHERE id IN ('.$cat['uppercats'].') + ;'; + $names = hash_from_query($query, 'id'); + + // category names must be in the same order than uppercats list + $cat['upper_names'] = array(); + foreach ($upper_ids as $cat_id) + { + array_push( $cat['upper_names'], $names[$cat_id]); + } + } + return $cat; +} + +// get_complete_dir returns the concatenation of get_site_url and +// get_local_dir +// Example : "pets > rex > 1_year_old" is on the the same site as the +// Piwigo files and this category has 22 for identifier +// get_complete_dir(22) returns "./galleries/pets/rex/1_year_old/" +function get_complete_dir( $category_id ) +{ + return get_site_url($category_id).get_local_dir($category_id); +} + +// get_local_dir returns an array with complete path without the site url +// Example : "pets > rex > 1_year_old" is on the the same site as the +// Piwigo files and this category has 22 for identifier +// get_local_dir(22) returns "pets/rex/1_year_old/" +function get_local_dir( $category_id ) +{ + global $page; + + $uppercats = ''; + $local_dir = ''; + + if ( isset( $page['plain_structure'][$category_id]['uppercats'] ) ) + { + $uppercats = $page['plain_structure'][$category_id]['uppercats']; + } + else + { + $query = 'SELECT uppercats'; + $query.= ' FROM '.CATEGORIES_TABLE.' WHERE id = '.$category_id; + $query.= ';'; + $row = mysql_fetch_array( pwg_query( $query ) ); + $uppercats = $row['uppercats']; + } + + $upper_array = explode( ',', $uppercats ); + + $database_dirs = array(); + $query = 'SELECT id,dir'; + $query.= ' FROM '.CATEGORIES_TABLE.' WHERE id IN ('.$uppercats.')'; + $query.= ';'; + $result = pwg_query( $query ); + while( $row = mysql_fetch_array( $result ) ) + { + $database_dirs[$row['id']] = $row['dir']; + } + foreach ($upper_array as $id) + { + $local_dir.= $database_dirs[$id].'/'; + } + + return $local_dir; +} + +// retrieving the site url : "http://domain.com/gallery/" or +// simply "./galleries/" +function get_site_url($category_id) +{ + global $page; + + $query = ' +SELECT galleries_url + FROM '.SITES_TABLE.' AS s,'.CATEGORIES_TABLE.' AS c + WHERE s.id = c.site_id + AND c.id = '.$category_id.' +;'; + $row = mysql_fetch_array(pwg_query($query)); + return $row['galleries_url']; +} + +// returns an array of image orders available for users/visitors +function get_category_preferred_image_orders() +{ + global $conf; + return array( + array(l10n('default_sort'), '', true), + array(l10n('Average rate'), 'average_rate DESC', $conf['rate']), + array(l10n('most_visited_cat'), 'hit DESC', true), + array(l10n('Creation date'), 'date_creation DESC', true), + array(l10n('Post date'), 'date_available DESC', true), + array(l10n('File name'), 'file ASC', true) + ); +} + +function display_select_categories($categories, + $selecteds, + $blockname, + $fullname = true) +{ + global $template; + + $tpl_cats = array(); + foreach ($categories as $category) + { + if ($fullname) + { + $option = get_cat_display_name_cache($category['uppercats'], + null, + false); + } + else + { + $option = str_repeat(' ', + (3 * substr_count($category['global_rank'], '.'))); + $option.= '- '.$category['name']; + } + $tpl_cats[ $category['id'] ] = $option; + } + + $template->assign( $blockname, $tpl_cats); + $template->assign( $blockname.'_selected', $selecteds); +} + +function display_select_cat_wrapper($query, $selecteds, $blockname, + $fullname = true) +{ + $result = pwg_query($query); + $categories = array(); + if (!empty($result)) + { + while ($row = mysql_fetch_assoc($result)) + { + array_push($categories, $row); + } + } + usort($categories, 'global_rank_compare'); + display_select_categories($categories, $selecteds, $blockname, $fullname); +} + +/** + * returns all subcategory identifiers of given category ids + * + * @param array ids + * @return array + */ +function get_subcat_ids($ids) +{ + $query = ' +SELECT DISTINCT(id) + FROM '.CATEGORIES_TABLE.' + WHERE '; + foreach ($ids as $num => $category_id) + { + is_numeric($category_id) + or trigger_error( + 'get_subcat_ids expecting numeric, not '.gettype($category_id), + E_USER_WARNING + ); + if ($num > 0) + { + $query.= ' + OR '; + } + $query.= 'uppercats REGEXP \'(^|,)'.$category_id.'(,|$)\''; + } + $query.= ' +;'; + $result = pwg_query($query); + + $subcats = array(); + while ($row = mysql_fetch_array($result)) + { + array_push($subcats, $row['id']); + } + return $subcats; +} + +/** finds a matching category id from a potential list of permalinks + * @param array permalinks example: holiday holiday/france holiday/france/paris + * @param int idx - output of the index in $permalinks that matches + * return category id or null if no match + */ +function get_cat_id_from_permalinks( $permalinks, &$idx ) +{ + $in = ''; + foreach($permalinks as $permalink) + { + if ( !empty($in) ) $in.=', '; + $in .= '"'.$permalink.'"'; + } + $query =' +SELECT cat_id AS id, permalink, 1 AS is_old + FROM '.OLD_PERMALINKS_TABLE.' + WHERE permalink IN ('.$in.') +UNION +SELECT id, permalink, 0 AS is_old + FROM '.CATEGORIES_TABLE.' + WHERE permalink IN ('.$in.') +;'; + $perma_hash = hash_from_query($query, 'permalink'); + + if ( empty($perma_hash) ) + return null; + for ($i=count($permalinks)-1; $i>=0; $i--) + { + if ( isset( $perma_hash[ $permalinks[$i] ] ) ) + { + $idx = $i; + $cat_id = $perma_hash[ $permalinks[$i] ]['id']; + if ($perma_hash[ $permalinks[$i] ]['is_old']) + { + $query=' +UPDATE '.OLD_PERMALINKS_TABLE.' SET last_hit=NOW(), hit=hit+1 + WHERE permalink="'.$permalinks[$i].'" AND cat_id='.$cat_id.' + LIMIT 1'; + pwg_query($query); + } + return $cat_id; + } + } + return null; +} + +function global_rank_compare($a, $b) +{ + return strnatcasecmp($a['global_rank'], $b['global_rank']); +} + +function rank_compare($a, $b) +{ + if ($a['rank'] == $b['rank']) + { + return 0; + } + + return ($a['rank'] < $b['rank']) ? -1 : 1; +} + +/** + * returns display text for information images of category + * + * @param array categories + * @return string + */ +function get_display_images_count($cat_nb_images, $cat_count_images, $cat_count_categories, $short_message = true, $Separator = '\n') +{ + $display_text = ''; + + if ($cat_count_images > 0) + { + if ($cat_nb_images > 0 and $cat_nb_images < $cat_count_images) + { + $display_text.= get_display_images_count($cat_nb_images, $cat_nb_images, 0, $short_message, $Separator).$Separator; + $cat_count_images-= $cat_nb_images; + $cat_nb_images = 0; + } + + //at least one image direct or indirect + $display_text.= l10n_dec('%d element', '%d elements', $cat_count_images); + + if ($cat_count_categories == 0 or $cat_nb_images == $cat_count_images) + { + //no descendant categories or descendants do not contain images + if (! $short_message) + { + $display_text.= ' '.l10n('images_available_cpl'); + } + } + else + { + $display_text.= ' '.l10n_dec('images_available_cat', 'images_available_cats', $cat_count_categories); + } + } + + return $display_text; +} + +/** + * returns the link of upload menu + * + * @param null + * @return string or null + */ +function get_upload_menu_link() +{ + global $conf, $page, $user; + + $show_link = false; + $arg_link = null; + + if (is_autorize_status($conf['upload_user_access'])) + { + if (isset($page['category']) and $page['category']['uploadable'] ) + { + // upload a picture in the category + $show_link = true; + $arg_link = 'cat='.$page['category']['id']; + } + else + if ($conf['upload_link_everytime']) + { + // upload a picture in the category + $query = ' +SELECT + 1 +FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' + ON id = cat_id and user_id = '.$user['id'].' +WHERE + uploadable = \'true\' + '.get_sql_condition_FandF + ( + array + ( + 'visible_categories' => 'id', + ), + 'AND' + ).' +LIMIT 1'; + + $show_link = mysql_num_rows(pwg_query($query)) <> 0; + } + } + if ($show_link) + { + return get_root_url().'upload.php'.(empty($arg_link) ? '' : '?'.$arg_link); + } + else + { + return; + } +} + +?> diff --git a/BSF/include/functions_comment.inc.php b/BSF/include/functions_comment.inc.php new file mode 100644 index 000000000..6e6498c38 --- /dev/null +++ b/BSF/include/functions_comment.inc.php @@ -0,0 +1,228 @@ +$conf['comment_spam_max_links'] ) + return $my_action; + + return $action; +} + + +add_event_handler('user_comment_check', 'user_comment_check', + EVENT_HANDLER_PRIORITY_NEUTRAL, 2); + +/** + * Tries to insert a user comment in the database and returns one of : + * validate, moderate, reject + * @param array comm contains author, content, image_id + * @param string key secret key sent back to the browser + * @param array infos out array of messages + */ +function insert_user_comment( &$comm, $key, &$infos ) +{ + global $conf, $user; + + $comm = array_merge( $comm, + array( + 'ip' => $_SERVER['REMOTE_ADDR'], + 'agent' => $_SERVER['HTTP_USER_AGENT'] + ) + ); + + $infos = array(); + if (!$conf['comments_validation'] or is_admin()) + { + $comment_action='validate'; //one of validate, moderate, reject + } + else + { + $comment_action='moderate'; //one of validate, moderate, reject + } + + // display author field if the user status is guest or generic + if (!is_classic_user()) + { + if ( empty($comm['author']) ) + { + $comm['author'] = 'guest'; + } + // if a guest try to use the name of an already existing user, he must be + // rejected + if ( $comm['author'] != 'guest' ) + { + $query = ' +SELECT COUNT(*) AS user_exists + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['username']." = '".addslashes($comm['author'])."'"; + $row = mysql_fetch_assoc( pwg_query( $query ) ); + if ( $row['user_exists'] == 1 ) + { + array_push($infos, l10n('comment_user_exists') ); + $comment_action='reject'; + } + } + } + else + { + $comm['author'] = $user['username']; + } + if ( empty($comm['content']) ) + { // empty comment content + $comment_action='reject'; + } + + $key = explode( ':', @$key ); + if ( count($key)!=2 + or $key[0]>time()-2 // page must have been retrieved more than 2 sec ago + or $key[0]0 ) + { // anti-flood system + $reference_date = time() - $conf['anti-flood_time']; + $query = ' +SELECT id FROM '.COMMENTS_TABLE.' + WHERE date > FROM_UNIXTIME('.$reference_date.') + AND author = "'.addslashes($comm['author']).'"'; + if ( mysql_num_rows( pwg_query( $query ) ) > 0 ) + { + array_push( $infos, l10n('comment_anti-flood') ); + $comment_action='reject'; + } + } + + // perform more spam check + $comment_action = trigger_event('user_comment_check', + $comment_action, $comm + ); + + if ( $comment_action!='reject' ) + { + $query = ' +INSERT INTO '.COMMENTS_TABLE.' + (author, content, date, validated, validation_date, image_id) + VALUES ( + "'.addslashes($comm['author']).'", + "'.addslashes($comm['content']).'", + NOW(), + "'.($comment_action=='validate' ? 'true':'false').'", + '.($comment_action=='validate' ? 'NOW()':'NULL').', + '.$comm['image_id'].' + ) +'; + + pwg_query($query); + + $comm['id'] = mysql_insert_id(); + + if + ( + ($comment_action=='validate' and $conf['email_admin_on_comment']) + or + ($comment_action!='validate' and $conf['email_admin_on_comment_validation']) + ) + { + include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php'); + + $del_url = + get_absolute_root_url().'comments.php?delete='.$comm['id']; + + $keyargs_content = array + ( + get_l10n_args('Author: %s', $comm['author']), + get_l10n_args('Comment: %s', $comm['content']), + get_l10n_args('', ''), + get_l10n_args('Delete: %s', $del_url) + ); + + if ($comment_action!='validate') + { + $keyargs_content[] = + get_l10n_args('', ''); + $keyargs_content[] = + get_l10n_args('Validate: %s', + get_absolute_root_url().'comments.php?validate='.$comm['id']); + } + + pwg_mail_notification_admins + ( + get_l10n_args('Comment by %s', $comm['author']), + $keyargs_content + ); + } + } + return $comment_action; +} + +?> \ No newline at end of file diff --git a/BSF/include/functions_cookie.inc.php b/BSF/include/functions_cookie.inc.php new file mode 100644 index 000000000..159a5b538 --- /dev/null +++ b/BSF/include/functions_cookie.inc.php @@ -0,0 +1,115 @@ + diff --git a/BSF/include/functions_filter.inc.php b/BSF/include/functions_filter.inc.php new file mode 100644 index 000000000..24efb0994 --- /dev/null +++ b/BSF/include/functions_filter.inc.php @@ -0,0 +1,63 @@ + $category) + { + foreach ($upd_fields as $upd_field) + { + $cats[$cat_id][$upd_field] = $filter['categories'][$category['id']][$upd_field]; + } + } + } +} + +?> diff --git a/BSF/include/functions_group.inc.php b/BSF/include/functions_group.inc.php new file mode 100644 index 000000000..a5c07b5b5 --- /dev/null +++ b/BSF/include/functions_group.inc.php @@ -0,0 +1,26 @@ + diff --git a/BSF/include/functions_html.inc.php b/BSF/include/functions_html.inc.php new file mode 100644 index 000000000..b51f6f9df --- /dev/null +++ b/BSF/include/functions_html.inc.php @@ -0,0 +1,751 @@ + $page['get_icon_cache']['sql_recent_date'] ) + { + if ( !isset($page['get_icon_cache']['_icons_'] ) ) + { + $icons = array(false => 'recent', true => 'recent_by_child' ); + $title = sprintf( + l10n('elements posted during the last %d days'), + $user['recent_period'] + ); + foreach ($icons as $key => $icon) + { + $icon_url = get_themeconf('icon_dir').'/'.$icon.'.png'; + $size = getimagesize( PHPWG_ROOT_PATH.$icon_url ); + $icon_url = get_root_url().$icon_url; + $output = '(!)'; + $page['get_icon_cache']['_icons_'][$key] = $output; + } + } + $page['get_icon_cache'][$date] = true; + } + + if (! $page['get_icon_cache'][$date] ) + return ''; + return $page['get_icon_cache']['_icons_'][$is_child_date]; +} + +function create_navigation_bar( + $url, $nb_element, $start, $nb_element_page, $clean_url = false + ) +{ + global $conf; + + $pages_around = $conf['paginate_pages_around']; + $start_str = $clean_url ? '/start-' : + ( ( strstr($url, '?')===false ? '?':'&') . 'start=' ); + + $navbar = ''; + + // current page detection + if (!isset($start) + or !is_numeric($start) + or (is_numeric($start) and $start < 0)) + { + $start = 0; + } + + // navigation bar useful only if more than one page to display ! + if ($nb_element > $nb_element_page) + { + // current page and last page + $cur_page = ceil($start / $nb_element_page) + 1; + $maximum = ceil($nb_element / $nb_element_page); + + // link to first page ? + if ($cur_page != 1) + { + $navbar.= + '' + .l10n('first_page') + .''; + } + else + { + $navbar.= l10n('first_page'); + } + $navbar.= ' | '; + // link on previous page ? + if ($start != 0) + { + $previous = $start - $nb_element_page; + + $navbar.= + ''; + } + else + { + $navbar.= l10n('previous_page'); + } + $navbar.= ' |'; + + if ($cur_page > $pages_around + 1) + { + $navbar.= ' 1'; + + if ($cur_page > $pages_around + 2) + { + $navbar.= ' ...'; + } + } + + // inspired from punbb source code + for ($i = $cur_page - $pages_around, $stop = $cur_page + $pages_around + 1; + $i < $stop; + $i++) + { + if ($i < 1 or $i > $maximum) + { + continue; + } + else if ($i != $cur_page) + { + $temp_start = ($i - 1) * $nb_element_page; + + $navbar.= + ' ' + .'' + .$i + .''; + } + else + { + $navbar.= + ' ' + .'' + .$i + .''; + } + } + + if ($cur_page < ($maximum - $pages_around)) + { + $temp_start = ($maximum - 1) * $nb_element_page; + + if ($cur_page < ($maximum - $pages_around - 1)) + { + $navbar.= ' ...'; + } + + $navbar.= ' '.$maximum.''; + } + + $navbar.= ' | '; + // link on next page ? + if ($nb_element > $nb_element_page + and $start + $nb_element_page < $nb_element) + { + $next = $start + $nb_element_page; + + $navbar.= + ''; + } + else + { + $navbar.= l10n('next_page'); + } + + $navbar.= ' | '; + // link to last page ? + if ($cur_page != $maximum) + { + $temp_start = ($maximum - 1) * $nb_element_page; + + $navbar.= + '' + .l10n('last_page') + .''; + } + else + { + $navbar.= l10n('last_page'); + } + } + return $navbar; +} + +/** + * returns the list of categories as a HTML string + * + * categories string returned contains categories as given in the input + * array $cat_informations. $cat_informations array must be an array + * of array( id=>?, name=>?, permalink=>?). If url input parameter is null, + * returns only the categories name without links. + * + * @param array cat_informations + * @param string url + * @param boolean replace_space + * @return string + */ +function get_cat_display_name($cat_informations, + $url = '', + $replace_space = true) +{ + global $conf; + + $output = ''; + $is_first = true; + foreach ($cat_informations as $cat) + { + is_array($cat) or trigger_error( + 'get_cat_display_name wrong type for category ', E_USER_WARNING + ); + if ($is_first) + { + $is_first = false; + } + else + { + $output.= $conf['level_separator']; + } + + if ( !isset($url) ) + { + $output.= $cat['name']; + } + elseif ($url == '') + { + $output.= ''; + $output.= $cat['name'].''; + } + else + { + $output.= ''; + $output.= $cat['name'].''; + } + } + if ($replace_space) + { + return replace_space($output); + } + else + { + return $output; + } +} + +/** + * returns the list of categories as a HTML string, with cache of names + * + * categories string returned contains categories as given in the input + * array $cat_informations. $uppercats is the list of category ids to + * display in the right order. If url input parameter is empty, returns only + * the categories name without links. + * + * @param string uppercats + * @param string url + * @param boolean replace_space + * @return string + */ +function get_cat_display_name_cache($uppercats, + $url = '', + $replace_space = true) +{ + global $cache, $conf; + + if (!isset($cache['cat_names'])) + { + $query = ' +SELECT id, name, permalink + FROM '.CATEGORIES_TABLE.' +;'; + $cache['cat_names'] = hash_from_query($query, 'id'); + } + + $output = ''; + $is_first = true; + foreach (explode(',', $uppercats) as $category_id) + { + $cat = $cache['cat_names'][$category_id]; + + if ($is_first) + { + $is_first = false; + } + else + { + $output.= $conf['level_separator']; + } + + if ( !isset($url) ) + { + $output.= $cat['name']; + } + elseif ($url == '') + { + $output.= ' +'.$cat['name'].''; + } + else + { + $output.= ' +'.$cat['name'].''; + } + } + if ($replace_space) + { + return replace_space($output); + } + else + { + return $output; + } +} + +/** + * returns the HTML code for a category item in the menu (for the main page) + * + * HTML code generated uses logical list tags ul and each category is an + * item li. The paramter given is the category informations as an array, + * used keys are : id, name, nb_images, max_date_last, date_last + * count_images, count_categories + * + * @param array categories + * @return string + */ +function get_html_menu_category($categories, $selected_category) +{ + $ref_level = 0; + $level = 0; + + $menu = trigger_event('get_html_menu_category', '', + $categories, $selected_category); + if (strlen($menu)) + { + return $menu; + } + + foreach ($categories as $category) + { + $level = substr_count($category['global_rank'], '.') + 1; + if ($level > $ref_level) + { + $menu.= "\n
    "; + } + else if ($level == $ref_level) + { + $menu.= "\n"; + } + else if ($level < $ref_level) + { + // we may have to close more than one level at the same time... + $menu.= "\n"; + $menu.= str_repeat("\n
",($ref_level-$level)); + } + $ref_level = $level; + + $menu.= "\n\n".' $category + ) + ); + + $title = get_display_images_count + ( + $category['nb_images'], + $category['count_images'], + $category['count_categories'], + false, + ' / ' + ); + + $menu.= ''.$category['name'].''; + + if ( $category['count_images']>0 ) + {// at least one direct or indirect image + $menu.= "\n".''; + // show total number of images + $menu.= '['.$category['count_images'].']'; + $menu.= ''; + } + $child_date_last = @$category['max_date_last']> @$category['date_last']; + $menu.= get_icon($category['max_date_last'], $child_date_last); + } + + $menu.= str_repeat("\n",($level)); + + return $menu; +} + +/** + * returns HTMLized comment contents retrieved from database + * + * newlines becomes br tags, _word_ becomes underline, /word/ becomes + * italic, *word* becomes bolded + * + * @param string content + * @return string + */ +function parse_comment_content($content) +{ + $pattern = '/(https?:\/\/\S*)/'; + $replacement = '$1'; + $content = preg_replace($pattern, $replacement, $content); + + $content = nl2br($content); + + // replace _word_ by an underlined word + $pattern = '/\b_(\S*)_\b/'; + $replacement = '$1'; + $content = preg_replace($pattern, $replacement, $content); + + // replace *word* by a bolded word + $pattern = '/\b\*(\S*)\*\b/'; + $replacement = '$1'; + $content = preg_replace($pattern, $replacement, $content); + + // replace /word/ by an italic word + $pattern = "/\/(\S*)\/(\s)/"; + $replacement = '$1$2'; + $content = preg_replace($pattern, $replacement, $content); + + $content = '
'.$content.'
'; + return $content; +} + +function get_cat_display_name_from_id($cat_id, + $url = '', + $replace_space = true) +{ + $cat_info = get_cat_info($cat_id); + return get_cat_display_name($cat_info['upper_names'], $url, $replace_space); +} + +/** + * Returns an HTML list of tags. It can be a multi select field or a list of + * checkboxes. + * + * @param string HTML field name + * @param array selected tag ids + * @return array + */ +function get_html_tag_selection( + $tags, + $fieldname, + $selecteds = array(), + $forbidden_categories = null + ) +{ + global $conf; + + if (count ($tags) == 0 ) + { + return ''; + } + $output = '
    '; + foreach ($tags as $tag) + { + $output.= + '
  • ' + .'' + .'
  • ' + ."\n" + ; + } + $output.= '
'; + + return $output; +} + +function name_compare($a, $b) +{ + return strcmp(strtolower($a['name']), strtolower($b['name'])); +} + +/** + * exits the current script (either exit or redirect) + */ +function access_denied() +{ + global $user; + + $login_url = + get_root_url().'identification.php?redirect=' + .urlencode(urlencode($_SERVER['REQUEST_URI'])); + + if ( isset($user) and !is_a_guest() ) + { + echo '
'.l10n('access_forbiden').'
'; + echo ''.l10n('identification').' '; + echo ''.l10n('home').'
'; + exit(); + } + else + { + set_status_header(401); + redirect_html($login_url); + } +} + +/** + * exits the current script with 403 code + * @param string msg a message to display + * @param string alternate_url redirect to this url + */ +function page_forbidden($msg, $alternate_url=null) +{ + set_status_header(403); + if ($alternate_url==null) + $alternate_url = make_index_url(); + redirect_html( $alternate_url, + '
+

Forbidden


' +.$msg.'
', + 5 ); +} + +/** + * exits the current script with 400 code + * @param string msg a message to display + * @param string alternate_url redirect to this url + */ +function bad_request($msg, $alternate_url=null) +{ + set_status_header(400); + if ($alternate_url==null) + $alternate_url = make_index_url(); + redirect_html( $alternate_url, + '
+

Bad request


' +.$msg.'
', + 5 ); +} + +/** + * exits the current script with 404 code when a page cannot be found + * @param string msg a message to display + * @param string alternate_url redirect to this url + */ +function page_not_found($msg, $alternate_url=null) +{ + set_status_header(404); + if ($alternate_url==null) + $alternate_url = make_index_url(); + redirect_html( $alternate_url, + '
+

Page not found


' +.$msg.'
', + 5 ); +} + +/* returns the title to be displayed above thumbnails on tag page + */ +function get_tags_content_title() +{ + global $page; + $title = count($page['tags']) > 1 ? l10n('Tags') : l10n('Tag'); + $title.= ' '; + + for ($i=0; $i0 ? ' + ' : ''; + + $title.= + '' + .$page['tags'][$i]['name'] + .''; + + if ( count($page['tags'])>2 ) + { + $other_tags = $page['tags']; + unset ( $other_tags[$i] ); + $title.= + 'x' + .''; + } + + } + return $title; +} + +/** + Sets the http status header (200,401,...) + */ +function set_status_header($code, $text='') +{ + if (empty($text)) + { + switch ($code) + { + case 200: $text='OK';break; + case 301: $text='Moved permanently';break; + case 302: $text='Moved temporarily';break; + case 304: $text='Not modified';break; + case 400: $text='Bad request';break; + case 401: $text='Authorization required';break; + case 403: $text='Forbidden';break; + case 404: $text='Not found';break; + case 500: $text='Server error';break; + case 503: $text='Service unavailable';break; + } + } + $protocol = $_SERVER["SERVER_PROTOCOL"]; + if ( ('HTTP/1.1' != $protocol) && ('HTTP/1.0' != $protocol) ) + $protocol = 'HTTP/1.0'; + + if ( version_compare( phpversion(), '4.3.0', '>=' ) ) + { + header( "$protocol $code $text", true, $code ); + } + else + { + header( "$protocol $code $text" ); + } + trigger_action('set_status_header', $code, $text); +} + +/** returns the category comment for rendering in html. + * this is an event handler. don't call directly + */ +function render_category_description($desc) +{ + global $conf; + if ( !( $conf['allow_html_descriptions'] and + preg_match('/<(div|br|img|script).*>/i', $desc) ) ) + { + $desc = nl2br($desc); + } + return $desc; +} + +/** returns the category comment for rendering in html textual mode (subcatify) + * this is an event handler. don't call directly + */ +function render_category_literal_description($desc) +{ + return strip_tags($desc, '


'); +} + +/** returns the argument_ids array with new sequenced keys based on related + * names. Sequence is not case sensitive. + * Warning: By definition, this function breaks original keys + */ +function order_by_name($element_ids,$name) +{ + $ordered_element_ids = array(); + foreach ($element_ids as $k_id => $element_id) + { + $key = strtolower($name[$element_id]) .'-'. $name[$element_id] .'-'. $k_id; + $ordered_element_ids[$key] = $element_id; + } + ksort($ordered_element_ids); + return $ordered_element_ids; +} + +?> diff --git a/BSF/include/functions_mail.inc.php b/BSF/include/functions_mail.inc.php new file mode 100644 index 000000000..9e7f9024d --- /dev/null +++ b/BSF/include/functions_mail.inc.php @@ -0,0 +1,822 @@ + $conf['mail_options'], + 'send_bcc_mail_webmaster' => $conf['send_bcc_mail_webmaster'], + 'default_email_format' => $conf['default_email_format'], + 'use_smtp' => !empty($conf['smtp_host']), + 'smtp_host' => $conf['smtp_host'], + 'smtp_user' => $conf['smtp_user'], + 'smtp_password' => $conf['smtp_password'] + ); + + // we have webmaster id among user list, what's his email address ? + $conf_mail['email_webmaster'] = get_webmaster_mail_address(); + + // name of the webmaster is the title of the gallery + $conf_mail['formated_email_webmaster'] = + format_email(get_mail_sender_name(), $conf_mail['email_webmaster']); + + $conf_mail['boundary_key'] = generate_key(32); + + return $conf_mail; +} + +/** + * Returns an email address with an associated real name + * + * @param string name + * @param string email + */ +function format_email($name, $email) +{ + // Spring cleaning + $cvt_email = trim(preg_replace('#[\n\r]+#s', '', $email)); + $cvt_name = trim(preg_replace('#[\n\r]+#s', '', $name)); + + if ($cvt_name!="") + { + $cvt_name = encode_mime_header( + '"' + .addcslashes($cvt_name,'"') + .'"'); + $cvt_name .= ' '; + } + + if (strpos($cvt_email, '<') === false) + { + return $cvt_name.'<'.$cvt_email.'>'; + } + else + { + return $cvt_name.$cvt_email; + } +} + +/** + * Returns an email address list with minimal email string + * + * @param string with email list (email separated by comma) + */ +function get_strict_email_list($email_list) +{ + $result = array(); + $list = explode(',', $email_list); + foreach ($list as $email) + { + if (strpos($email, '<') !== false) + { + $email = preg_replace('/.*<(.*)>.*/i', '$1', $email); + } + $result[] = trim($email); + } + + return implode(',', $result); +} + +/** + * Returns an completed array template/theme + * completed with get_default_template() + * + * @params: + * - args: incompleted array of template/theme + * o template: template to use [default get_default_template()] + * o theme: template to use [default get_default_template()] + */ +function get_array_template_theme($args = array()) +{ + global $conf; + + $res = array(); + + if (empty($args['template']) or empty($args['theme'])) + { + list($res['template'], $res['theme']) = explode('/', get_default_template()); + } + + if (!empty($args['template'])) + { + $res['template'] = $args['template']; + } + + if (!empty($args['theme'])) + { + $res['theme'] = $args['theme']; + } + + return $res; +} + +/** + * Return an new mail template + * + * @params: + * - email_format: mail format + * - args: function params of mail function: + * o template: template to use [default get_default_template()] + * o theme: template to use [default get_default_template()] + */ +function & get_mail_template($email_format, $args = array()) +{ + $args = get_array_template_theme($args); + + $mail_template = new Template(PHPWG_ROOT_PATH.'template/'.$args['template'], $args['theme']); + $mail_template->set_template_dir(PHPWG_ROOT_PATH.'template/'.$args['template'].'/mail/'.$email_format); + return $mail_template; +} + +/** + * Return string email format (html or not) + * + * @param string format + */ +function get_str_email_format($is_html) +{ + return ($is_html ? 'text/html' : 'text/plain'); +} + +/* + * Switch language to param language + * All entries are push on language stack + * + * @param string language + */ +function switch_lang_to($language) +{ + global $switch_lang, $user, $lang, $lang_info; + + if (count($switch_lang['stack']) == 0) + { + $prev_language = $user['language']; + } + else + { + $prev_language = end($switch_lang['stack']); + } + + $switch_lang['stack'][] = $language; + + if ($prev_language != $language) + { + if (!isset($switch_lang['language'][$prev_language])) + { + $switch_lang[$prev_language]['lang_info'] = $lang_info; + $switch_lang[$prev_language]['lang'] = $lang; + } + + if (!isset($switch_lang['language'][$language])) + { + // Re-Init language arrays + $lang_info = array(); + $lang = array(); + + // language files + load_language('common.lang', '', $language); + // No test admin because script is checked admin (user selected no) + // Translations are in admin file too + load_language('admin.lang', '', $language); + trigger_action('loading_lang'); + load_language('local.lang', '', $language); + + $switch_lang[$language]['lang_info'] = $lang_info; + $switch_lang[$language]['lang'] = $lang; + } + else + { + $lang_info = $switch_lang[$language]['lang_info']; + $lang = $switch_lang[$language]['lang']; + } + + $user['language'] = $language; + } +} + +/* + * Switch back language pushed with switch_lang_to function + * + * @param: none + */ +function switch_lang_back() +{ + global $switch_lang, $user, $lang, $lang_info; + + $last_language = array_pop($switch_lang['stack']); + + if (count($switch_lang['stack']) > 0) + { + $language = end($switch_lang['stack']); + } + else + { + $language = $user['language']; + } + + if ($last_language != $language) + { + if (!isset($switch_lang['language'][$language])) + { + $lang_info = $switch_lang[$language]['lang_info']; + $lang = $switch_lang[$language]['lang']; + } + $user['language'] = $language; + } +} + +/** + * Returns email of all administrator + * + * @return string + */ +/* + * send en notification email to all administrators + * if a administrator is doing action, + * he's be removed to email list + * + * @param: + * - keyargs_subject: mail subject on l10n_args format + * - keyargs_content: mail content on l10n_args format + * + * @return boolean (Ok or not) + */ +function pwg_mail_notification_admins($keyargs_subject, $keyargs_content) +{ + // Check arguments + if + ( + empty($keyargs_subject) or + empty($keyargs_content) + ) + { + return false; + } + + global $conf, $user; + $return = true; + + $admins = array(); + + $query = ' +select + U.'.$conf['user_fields']['username'].' as username, + U.'.$conf['user_fields']['email'].' as mail_address +from + '.USERS_TABLE.' as U, + '.USER_INFOS_TABLE.' as I +where + I.user_id = U.'.$conf['user_fields']['id'].' and + I.status in (\'webmaster\', \'admin\') and + I.adviser = \'false\' and + '.$conf['user_fields']['email'].' is not null and + I.user_id <> '.$user['id'].' +order by + username +'; + + $datas = pwg_query($query); + if (!empty($datas)) + { + while ($admin = mysql_fetch_array($datas)) + { + if (!empty($admin['mail_address'])) + { + array_push($admins, format_email($admin['username'], $admin['mail_address'])); + } + } + } + + if (count($admins) > 0) + { + $keyargs_content_admin_info = array + ( + get_l10n_args('Connected user: %s', $user['username']), + get_l10n_args('IP: %s', $_SERVER['REMOTE_ADDR']), + get_l10n_args('Browser: %s', $_SERVER['HTTP_USER_AGENT']) + ); + + switch_lang_to(get_default_language()); + + $return = pwg_mail + ( + '', + array + ( + 'Bcc' => $admins, + 'subject' => '['.$conf['gallery_title'].'] '.l10n_args($keyargs_subject), + 'content' => + l10n_args($keyargs_content)."\n\n" + .l10n_args($keyargs_content_admin_info)."\n", + 'content_format' => 'text/plain' + ) + ) and $return; + + switch_lang_back(); + } + + return $return; +} + +/* + * send en email to user's group + * + * @param: + * - group_id: mail are sent to group with this Id + * - email_format: mail format + * - keyargs_subject: mail subject on l10n_args format + * - dirname: short name of directory including template + * - tpl_shortname: short template name without extension + * - assign_vars: array used to assign_vars to mail template + * - language_selected: send mail only to user with this selected language + * + * @return boolean (Ok or not) + */ +function pwg_mail_group( + $group_id, $email_format, $keyargs_subject, + $dirname, $tpl_shortname, + $assign_vars = array(), $language_selected = '') +{ + // Check arguments + if + ( + empty($group_id) or + empty($email_format) or + empty($keyargs_subject) or + empty($tpl_shortname) + ) + { + return false; + } + + global $conf; + $return = true; + + $query = ' +SELECT + distinct language, template +FROM + '.USER_GROUP_TABLE.' as ug + INNER JOIN '.USERS_TABLE.' as u ON '.$conf['user_fields']['id'].' = ug.user_id + INNER JOIN '.USER_INFOS_TABLE.' as ui ON ui.user_id = ug.user_id +WHERE + '.$conf['user_fields']['email'].' IS NOT NULL + AND group_id = '.$group_id; + + if (!empty($language_selected)) + { + $query .= ' + AND language = \''.$language_selected.'\''; + } + + $query .= ' +;'; + + $result = pwg_query($query); + + if (mysql_num_rows($result) > 0) + { + $list = array(); + while ($row = mysql_fetch_array($result)) + { + $row['template_theme'] = $row['template']; + list($row['template'], $row['theme']) = explode('/', $row['template_theme']); + $list[] = $row; + } + + foreach ($list as $elem) + { + $query = ' +SELECT + u.'.$conf['user_fields']['username'].' as username, + u.'.$conf['user_fields']['email'].' as mail_address +FROM + '.USER_GROUP_TABLE.' as ug + INNER JOIN '.USERS_TABLE.' as u ON '.$conf['user_fields']['id'].' = ug.user_id + INNER JOIN '.USER_INFOS_TABLE.' as ui ON ui.user_id = ug.user_id +WHERE + '.$conf['user_fields']['email'].' IS NOT NULL + AND group_id = '.$group_id.' + AND language = \''.$elem['language'].'\' + AND template = \''.$elem['template_theme'].'\' +;'; + + $result = pwg_query($query); + + if (mysql_num_rows($result) > 0) + { + $Bcc = array(); + while ($row = mysql_fetch_array($result)) + { + if (!empty($row['mail_address'])) + { + array_push($Bcc, format_email($row['username'], $row['mail_address'])); + } + } + + if (count($Bcc) > 0) + { + switch_lang_to($elem['language']); + + $mail_template = get_mail_template($email_format, $elem); + $mail_template->set_filename($tpl_shortname, + (empty($dirname) ? '' : $dirname.'/').$tpl_shortname.'.tpl'); + + $mail_template->assign( + trigger_event('mail_group_assign_vars', $assign_vars)); + + $return = pwg_mail + ( + '', + array + ( + 'Bcc' => $Bcc, + 'subject' => l10n_args($keyargs_subject), + 'email_format' => $email_format, + 'content' => $mail_template->parse($tpl_shortname, true), + 'content_format' => $email_format, + 'template' => $elem['template'], + 'theme' => $elem['theme'] + ) + ) and $return; + + switch_lang_back(); + } + } + } + } + + return $return; +} + +/* + * sends an email, using Piwigo specific informations + * + * @param: + * - to: receiver(s) of the mail (list separated by comma). + * - args: function params of mail function: + * o from: sender [default value webmaster email] + * o Cc: array of carbon copy receivers of the mail. [default value empty] + * o Bcc: array of blind carbon copy receivers of the mail. [default value empty] + * o subject [default value 'Piwigo'] + * o content: content of mail [default value ''] + * o content_format: format of mail content [default value 'text/plain'] + * o email_format: global mail format [default value $conf_mail['default_email_format']] + * o template: template to use [default get_default_template()] + * o theme: template to use [default get_default_template()] + * + * @return boolean (Ok or not) + */ +function pwg_mail($to, $args = array()) +{ + global $conf, $conf_mail, $lang_info, $page; + + if (empty($to) and empty($args['Cc']) and empty($args['Bcc'])) + { + return true; + } + + if (!isset($conf_mail)) + { + $conf_mail = get_mail_configuration(); + } + + if (empty($args['email_format'])) + { + $args['email_format'] = $conf_mail['default_email_format']; + } + + // Compute root_path in order have complete path + if ($args['email_format'] == 'text/html') + { + set_make_full_url(); + } + + if (empty($args['from'])) + { + $args['from'] = $conf_mail['formated_email_webmaster']; + } + else + { + $args['from'] = format_email('', $args['from']); + } + + if (empty($args['subject'])) + { + $args['subject'] = 'Piwigo'; + } + // Spring cleaning + $cvt_subject = trim(preg_replace('#[\n\r]+#s', '', $args['subject'])); + // Ascii convertion + $cvt_subject = encode_mime_header($cvt_subject); + + if (!isset($args['content'])) + { + $args['content'] = ''; + } + + if (empty($args['content_format'])) + { + $args['content_format'] = 'text/plain'; + } + + if ($conf_mail['send_bcc_mail_webmaster']) + { + $args['Bcc'][] = $conf_mail['formated_email_webmaster']; + } + + if (($args['content_format'] == 'text/html') and ($args['email_format'] == 'text/plain')) + { + // Todo find function to convert html text to plain text + return false; + } + + $args = array_merge($args, get_array_template_theme($args)); + + $headers = 'From: '.$args['from']."\n"; + $headers.= 'Reply-To: '.$args['from']."\n"; + if (empty($to)) + { + $headers.= 'To: undisclosed-recipients: ;'."\n"; + } + else + { + $headers.= 'To: '.$to."\n"; + } + + if (!empty($args['Cc'])) + { + $headers.= 'Cc: '.implode(',', $args['Cc'])."\n"; + } + + if (!empty($args['Bcc'])) + { + $headers.= 'Bcc: '.implode(',', $args['Bcc'])."\n"; + } + + $headers.= 'Content-Type: multipart/alternative;'."\n"; + $headers.= ' boundary="---='.$conf_mail['boundary_key'].'";'."\n"; + $headers.= ' reply-type=original'."\n"; + $headers.= 'MIME-Version: 1.0'."\n"; + $headers.= 'X-Mailer: Piwigo Mailer'."\n"; + + $content = ''; + + // key compose of indexes witch allow ti cache mail data + $cache_key = $args['email_format'].'-'.$lang_info['code'].'-'.$args['template'].'-'.$args['theme']; + + if (!isset($conf_mail[$cache_key])) + { + if (!isset($mail_template)) + { + $mail_template = get_mail_template($args['email_format']); + } + + $mail_template->set_filename('mail_header', 'header.tpl'); + $mail_template->set_filename('mail_footer', 'footer.tpl'); + + $mail_template->assign( + array( + //Header + 'BOUNDARY_KEY' => $conf_mail['boundary_key'], + 'CONTENT_TYPE' => $args['email_format'], + 'CONTENT_ENCODING' => get_pwg_charset(), + 'LANG' => $lang_info['code'], + 'DIR' => $lang_info['direction'], + + // Footer + 'GALLERY_URL' => + isset($page['gallery_url']) ? + $page['gallery_url'] : $conf['gallery_url'], + 'GALLERY_TITLE' => + isset($page['gallery_title']) ? + $page['gallery_title'] : $conf['gallery_title'], + 'VERSION' => $conf['show_version'] ? PHPWG_VERSION : '', + 'PHPWG_URL' => PHPWG_URL, + + 'TITLE_MAIL' => urlencode(l10n('title_send_mail')), + 'MAIL' => get_webmaster_mail_address() + )); + + if ($args['email_format'] == 'text/html') + { + if (is_file($mail_template->get_template_dir().'/global-mail-css.tpl')) + { + $mail_template->set_filename('css', 'global-mail-css.tpl'); + $mail_template->assign_var_from_handle('GLOBAL_MAIL_CSS', 'css'); + } + + $root_abs_path = dirname(dirname(__FILE__)); + + $file = $root_abs_path.'/template/'.$args['template'].'/theme/'.$args['theme'].'/mail-css.tpl'; + if (is_file($file)) + { + $mail_template->set_filename('css', $file); + $mail_template->assign_var_from_handle('MAIL_CSS', 'css'); + } + + $file = $root_abs_path.'/template-common/local-mail-css.tpl'; + if (is_file($file)) + { + $mail_template->set_filename('css', $file); + $mail_template->assign_var_from_handle('LOCAL_MAIL_CSS', 'css'); + } + } + + // what are displayed on the header of each mail ? + $conf_mail[$cache_key]['header'] = + $mail_template->parse('mail_header', true); + + // what are displayed on the footer of each mail ? + $conf_mail[$cache_key]['footer'] = + $mail_template->parse('mail_footer', true); + } + + // Header + $content.= $conf_mail[$cache_key]['header']; + + // Content + if (($args['content_format'] == 'text/plain') and ($args['email_format'] == 'text/html')) + { + $content.= '

'. + nl2br( + preg_replace("/(http:\/\/)([^\s,]*)/i", + "$1$2", + htmlspecialchars($args['content']))). + '

'; + } + else + { + $content.= $args['content']; + } + + // Footer + $content.= $conf_mail[$cache_key]['footer']; + + // Close boundary + $content.= "\n".'-----='.$conf_mail['boundary_key'].'--'."\n"; + + // Undo Compute root_path in order have complete path + if ($args['email_format'] == 'text/html') + { + unset_make_full_url(); + } + + return + trigger_event('send_mail', + false, /* Result */ + trigger_event('send_mail_to', get_strict_email_list($to)), + trigger_event('send_mail_subject', $cvt_subject), + trigger_event('send_mail_content', $content), + trigger_event('send_mail_headers', $headers), + $args + ); +} + +/* + * pwg sendmail + * + * @param: + * - result of other sendmail + * - to: Receiver or receiver(s) of the mail. + * - subject [default value 'Piwigo'] + * - content: content of mail + * - headers: headers of mail + * + * @return boolean (Ok or not) + */ +function pwg_send_mail($result, $to, $subject, $content, $headers) +{ + if (!$result) + { + global $conf_mail; + + if ($conf_mail['use_smtp']) + { + include_once( PHPWG_ROOT_PATH.'include/class_smtp_mail.inc.php' ); + $smtp_mail = new smtp_mail( + $conf_mail['smtp_host'], $conf_mail['smtp_user'], $conf_mail['smtp_password'], + $conf_mail['email_webmaster']); + return $smtp_mail->mail($to, $subject, $content, $headers); + } + else + { + if ($conf_mail['mail_options']) + { + $options = '-f '.$conf_mail['email_webmaster']; + return mail($to, $subject, $content, $headers, $options); + } + else + { + return mail($to, $subject, $content, $headers); + } + } + } + else + { + return $result; + } +} + +/*Testing block*/ +/*function pwg_send_mail_test($result, $to, $subject, $content, $headers, $args) +{ + global $conf, $user, $lang_info; + $dir = $conf['local_data_dir'].'/tmp'; + @mkdir( $dir ); + $filename = $dir.'/mail.'.$user['username'].'.'.$lang_info['code'].'.'.$args['template'].'.'.$args['theme']; + if ($args['content_format'] == 'text/plain') + { + $filename .= '.txt'; + } + else + { + $filename .= '.html'; + } + $file = fopen($filename, 'w+'); + fwrite($file, $to ."\n"); + fwrite($file, $subject ."\n"); + fwrite($file, $headers); + fwrite($file, $content); + fclose($file); + return $result; +} +add_event_handler('send_mail', 'pwg_send_mail_test', EVENT_HANDLER_PRIORITY_NEUTRAL+10, 6);*/ + + +add_event_handler('send_mail', 'pwg_send_mail', EVENT_HANDLER_PRIORITY_NEUTRAL, 5); +trigger_action('functions_mail_included'); + +?> diff --git a/BSF/include/functions_metadata.inc.php b/BSF/include/functions_metadata.inc.php new file mode 100644 index 000000000..df89eea9c --- /dev/null +++ b/BSF/include/functions_metadata.inc.php @@ -0,0 +1,142 @@ + $field) + { + if (strpos($field, ';') === false) + { + if (isset($exif[$field])) + { + $result[$key] = $exif[$field]; + } + } + else + { + $tokens = explode(';', $field); + if (isset($exif[$tokens[0]][$tokens[1]])) + { + $result[$key] = $exif[$tokens[0]][$tokens[1]]; + } + } + } + } + + return $result; +} +?> \ No newline at end of file diff --git a/BSF/include/functions_notification.inc.php b/BSF/include/functions_notification.inc.php new file mode 100644 index 000000000..259a34613 --- /dev/null +++ b/BSF/include/functions_notification.inc.php @@ -0,0 +1,608 @@ + 'ic.category_id', + 'visible_categories' => 'ic.category_id', + 'visible_images' => 'ic.image_id' + ), + $prefix_condition, + $force_one_condition + ); +} + +/* + * Execute custom notification query + * + * @param string action ('count' or 'info') + * @param string type of query ('new_comments', 'unvalidated_comments', 'new_elements', 'updated_categories', 'new_users', 'waiting_elements') + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * + * @return integer for action count + * array for info + */ +function custom_notification_query($action, $type, $start, $end) +{ + global $user; + + switch($type) + { + case 'new_comments': + $query = ' + FROM '.COMMENTS_TABLE.' AS c + , '.IMAGE_CATEGORY_TABLE.' AS ic + WHERE c.image_id = ic.image_id + AND c.validation_date > \''.$start.'\' + AND c.validation_date <= \''.$end.'\' + '.get_std_sql_where_restrict_filter('AND').' +;'; + break; + case 'unvalidated_comments': + $query = ' + FROM '.COMMENTS_TABLE.' + WHERE date> \''.$start.'\' AND date <= \''.$end.'\' + AND validated = \'false\' +;'; + break; + case 'new_elements': + $query = ' + FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON image_id = id + WHERE date_available > \''.$start.'\' + AND date_available <= \''.$end.'\' + '.get_std_sql_where_restrict_filter('AND').' +;'; + break; + case 'updated_categories': + $query = ' + FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON image_id = id + WHERE date_available > \''.$start.'\' + AND date_available <= \''.$end.'\' + '.get_std_sql_where_restrict_filter('AND').' +;'; + break; + case 'new_users': + $query = ' + FROM '.USER_INFOS_TABLE.' + WHERE registration_date > \''.$start.'\' + AND registration_date <= \''.$end.'\' +;'; + break; + case 'waiting_elements': + $query = ' + FROM '.WAITING_TABLE.' + WHERE validated = \'false\' +;'; + break; + default: + // stop this function and return nothing + return; + break; + } + + switch($action) + { + case 'count': + switch($type) + { + case 'new_comments': + $field_id = 'c.id'; + break; + case 'unvalidated_comments': + $field_id = 'id'; + break; + case 'new_elements': + $field_id = 'image_id'; + break; + case 'updated_categories': + $field_id = 'category_id'; + break; + case 'new_users': + $field_id = 'user_id'; + break; + case 'waiting_elements': + $field_id = 'id'; + break; + } + $query = 'SELECT count(distinct '.$field_id.') as CountId +'.$query; + list($count) = mysql_fetch_array(pwg_query($query)); + return $count; + + break; + case 'info': + switch($type) + { + case 'new_comments': + $fields = array('c.id'); + break; + case 'unvalidated_comments': + $fields = array('id'); + break; + case 'new_elements': + $fields = array('image_id'); + break; + case 'updated_categories': + $fields = array('category_id'); + break; + case 'new_users': + $fields = array('user_id'); + break; + case 'waiting_elements': + $fields = array('id'); + break; + } + + $query = 'SELECT distinct '.implode(', ', $fields).' +'.$query; + $result = pwg_query($query); + + $infos = array(); + + while ($row = mysql_fetch_array($result)) + { + array_push($infos, $row); + } + + return $infos; + + break; + } + + //return is done on previous switch($action) +} + +/** + * new comments between two dates, according to authorized categories + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @param string forbidden categories (comma separated) + * @return count comment ids + */ +function nb_new_comments($start, $end) +{ + return custom_notification_query('count', 'new_comments', $start, $end); +} + +/** + * new comments between two dates, according to authorized categories + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @param string forbidden categories (comma separated) + * @return array comment ids + */ +function new_comments($start, $end) +{ + return custom_notification_query('info', 'new_comments', $start, $end); +} + +/** + * unvalidated at a precise date + * + * Comments that are registered and not validated yet on a precise date + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @return count comment ids + */ +function nb_unvalidated_comments($start, $end) +{ + return custom_notification_query('count', 'unvalidated_comments', $start, $end); +} + + +/** + * new elements between two dates, according to authorized categories + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @param string forbidden categories (comma separated) + * @return count element ids + */ +function nb_new_elements($start, $end) +{ + return custom_notification_query('count', 'new_elements', $start, $end); +} + +/** + * new elements between two dates, according to authorized categories + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @param string forbidden categories (comma separated) + * @return array element ids + */ +function new_elements($start, $end) +{ + return custom_notification_query('info', 'new_elements', $start, $end); +} + +/** + * updated categories between two dates, according to authorized categories + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @param string forbidden categories (comma separated) + * @return count element ids + */ +function nb_updated_categories($start, $end) +{ + return custom_notification_query('count', 'updated_categories', $start, $end); +} + +/** + * updated categories between two dates, according to authorized categories + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @param string forbidden categories (comma separated) + * @return array element ids + */ +function updated_categories($start, $end) +{ + return custom_notification_query('info', 'updated_categories', $start, $end); +} + +/** + * new registered users between two dates + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @return count user ids + */ +function nb_new_users($start, $end) +{ + return custom_notification_query('count', 'new_users', $start, $end); +} + +/** + * new registered users between two dates + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @return array user ids + */ +function new_users($start, $end) +{ + return custom_notification_query('info', 'new_users', $start, $end); +} + +/** + * currently waiting pictures + * + * @return count waiting ids + */ +function nb_waiting_elements() +{ + return custom_notification_query('count', 'waiting_elements', '', ''); +} + +/** + * currently waiting pictures + * + * @return array waiting ids + */ +function waiting_elements() +{ + return custom_notification_query('info', 'waiting_elements', $start, $end); +} + +/** + * There are new between two dates ? + * + * Informations : number of new comments, number of new elements, number of + * updated categories. Administrators are also informed about : number of + * unvalidated comments, number of new users (TODO : number of unvalidated + * elements) + * + * @param string start date (mysql datetime format) + * @param string end date (mysql datetime format) + * + * @return boolean : true if exist news else false + */ +function news_exists($start, $end) +{ + return ( + (nb_new_comments($start, $end) > 0) or + (nb_new_elements($start, $end) > 0) or + (nb_updated_categories($start, $end) > 0) or + ((is_admin()) and (nb_unvalidated_comments($start, $end) > 0)) or + ((is_admin()) and (nb_new_users($start, $end) > 0)) or + ((is_admin()) and (nb_waiting_elements() > 0)) + ); +} + +/** + * Formats a news line and adds it to the array (e.g. '5 new elements') + */ +function add_news_line(&$news, $count, $singular_fmt_key, $plural_fmt_key, $url='', $add_url=false) +{ + if ($count > 0) + { + $line = l10n_dec($singular_fmt_key, $plural_fmt_key, $count); + if ($add_url and !empty($url) ) + { + $line = ''.$line.''; + } + array_push($news, $line); + } +} + +/** + * What's new between two dates ? + * + * Informations : number of new comments, number of new elements, number of + * updated categories. Administrators are also informed about : number of + * unvalidated comments, number of new users (TODO : number of unvalidated + * elements) + * + * @param string start date (mysql datetime format) + * @param string end date (mysql datetime format) + * @param bool exclude_img_cats if true, no info about new images/categories + * @param bool add_url add html A link around news + * + * @return array of news + */ +function news($start, $end, $exclude_img_cats=false, $add_url=false) +{ + $news = array(); + + if (!$exclude_img_cats) + { + add_news_line( $news, + nb_new_elements($start, $end), '%d new element', '%d new elements', + make_index_url(array('section'=>'recent_pics')), $add_url ); + } + + if (!$exclude_img_cats) + { + add_news_line( $news, + nb_updated_categories($start, $end), '%d category updated', '%d categories updated', + make_index_url(array('section'=>'recent_cats')), $add_url ); + } + + add_news_line( $news, + nb_new_comments($start, $end), '%d new comment', '%d new comments', + get_root_url().'comments.php', $add_url ); + + if (is_admin()) + { + add_news_line( $news, + nb_unvalidated_comments($start, $end), '%d comment to validate', '%d comments to validate', + get_root_url().'admin.php?page=comments', $add_url ); + + add_news_line( $news, + nb_new_users($start, $end), '%d new user', '%d new users', + get_root_url().'admin.php?page=user_list', $add_url ); + + add_news_line( $news, + nb_waiting_elements(), '%d waiting element', '%d waiting elements', + get_root_url().'admin.php?page=upload', $add_url ); + } + + return $news; +} + +/** + * returns information about recently published elements grouped by post date + * @param int max_dates maximum returned number of recent dates + * @param int max_elements maximum returned number of elements per date + * @param int max_cats maximum returned number of categories per date + */ +function get_recent_post_dates($max_dates, $max_elements, $max_cats) +{ + global $conf, $user; + + $where_sql = get_std_sql_where_restrict_filter('WHERE', true); + + $query = ' +SELECT date_available, + COUNT(DISTINCT id) nb_elements, + COUNT(DISTINCT category_id) nb_cats + FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id=image_id + '.$where_sql.' + GROUP BY date_available + ORDER BY date_available DESC + LIMIT 0,'.$max_dates.' +;'; + $result = pwg_query($query); + $dates = array(); + while ($row = mysql_fetch_assoc($result)) + { + array_push($dates, $row); + } + + for ($i=0; $i0) + { // get some thumbnails ... + $query = ' +SELECT DISTINCT id, path, name, tn_ext, file + FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id=image_id + '.$where_sql.' + AND date_available="'.$dates[$i]['date_available'].'" + AND tn_ext IS NOT NULL + ORDER BY RAND(NOW()) + LIMIT 0,'.$max_elements.' +;'; + $dates[$i]['elements'] = array(); + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + array_push($dates[$i]['elements'], $row); + } + } + + if ($max_cats>0) + {// get some categories ... + $query = ' +SELECT DISTINCT c.uppercats, COUNT(DISTINCT i.id) img_count + FROM '.IMAGES_TABLE.' i INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON i.id=image_id + INNER JOIN '.CATEGORIES_TABLE.' c ON c.id=category_id + '.$where_sql.' + AND date_available="'.$dates[$i]['date_available'].'" + GROUP BY category_id + ORDER BY img_count DESC + LIMIT 0,'.$max_cats.' +;'; + $dates[$i]['categories'] = array(); + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + array_push($dates[$i]['categories'], $row); + } + } + } + return $dates; +} + +/* + Call function get_recent_post_dates but + the parameters to be passed to the function, as an indexed array. + +*/ +function get_recent_post_dates_array($args) +{ + return + get_recent_post_dates + ( + (empty($args['max_dates']) ? 3 : $args['max_dates']), + (empty($args['max_elements']) ? 3 : $args['max_elements']), + (empty($args['max_cats']) ? 3 : $args['max_cats']) + ); +} + + +/** + * returns html description about recently published elements grouped by post date + * @param $date_detail: selected date computed by get_recent_post_dates function + */ +function get_html_description_recent_post_date($date_detail) +{ + global $conf; + + $description = ''; + + $description .= + '
  • ' + .l10n_dec('%d new element', '%d new elements', $date_detail['nb_elements']) + .' (' + .'' + .l10n('recent_pics_cat').'' + .')' + .'

  • '; + + foreach($date_detail['elements'] as $element) + { + $tn_src = get_thumbnail_url($element); + $description .= ''; + } + $description .= '...
    '; + + $description .= + '
  • ' + .l10n_dec('%d category updated', '%d categories updated', + $date_detail['nb_cats']) + .'
  • '; + + $description .= '
      '; + foreach($date_detail['categories'] as $cat) + { + $description .= + '
    • ' + .get_cat_display_name_cache($cat['uppercats']) + .' ('. + l10n_dec('%d new element', + '%d new elements', $cat['img_count']).')' + .'
    • '; + } + $description .= '
    '; + + return $description; +} + +/** + * explodes a MySQL datetime format (2005-07-14 23:01:37) in fields "year", + * "month", "day", "hour", "minute", "second". + * + * @param string mysql datetime format + * @return array + */ +function explode_mysqldt($mysqldt) +{ + $date = array(); + list($date['year'], + $date['month'], + $date['day'], + $date['hour'], + $date['minute'], + $date['second']) + = preg_split('/[-: ]/', $mysqldt); + + return $date; +} + +/** + * returns title about recently published elements grouped by post date + * @param $date_detail: selected date computed by get_recent_post_dates function + */ +function get_title_recent_post_date($date_detail) +{ + global $lang; + + $date = $date_detail['date_available']; + $exploded_date = explode_mysqldt($date); + + $title = l10n_dec('%d new element', '%d new elements', $date_detail['nb_elements']); + $title .= ' ('.$lang['month'][(int)$exploded_date['month']].' '.$exploded_date['day'].')'; + + return $title; +} + +?> \ No newline at end of file diff --git a/BSF/include/functions_picture.inc.php b/BSF/include/functions_picture.inc.php new file mode 100644 index 000000000..1b6403ff3 --- /dev/null +++ b/BSF/include/functions_picture.inc.php @@ -0,0 +1,330 @@ + $element_info['id'], + 'part' => $what_part, + ) + ); + return trigger_event( 'get_download_url', $url, $element_info); +} + +/* + * get slideshow default params into array + * + * @param void + * + * @return slideshow default values into array + */ +function get_default_slideshow_params() +{ + global $conf; + + return array( + 'period' => $conf['slideshow_period'], + 'repeat' => $conf['slideshow_repeat'], + 'play' => true, + ); +} + +/* + * check and correct slideshow params from array + * + * @param array of params + * + * @return slideshow corrected values into array + */ +function correct_slideshow_params($params = array()) +{ + global $conf; + + if ($params['period'] < $conf['slideshow_period_min']) + { + $params['period'] = $conf['slideshow_period_min']; + } + else if ($params['period'] > $conf['slideshow_period_max']) + { + $params['period'] = $conf['slideshow_period_max']; + } + + return $params; +} + +/* + * Decode slideshow string params into array + * + * @param string params like "" + * + * @return slideshow values into array + */ +function decode_slideshow_params($encode_params = null) +{ + global $conf; + + $result = get_default_slideshow_params(); + + if (is_numeric($encode_params)) + { + $result['period'] = $encode_params; + } + else + { + $matches = array(); + if (preg_match_all('/([a-z]+)-(\d+)/', $encode_params, $matches)) + { + $matchcount = count($matches[1]); + for ($i = 0; $i < $matchcount; $i++) + { + $result[$matches[1][$i]] = $matches[2][$i]; + } + } + + if (preg_match_all('/([a-z]+)-(true|false)/', $encode_params, $matches)) + { + $matchcount = count($matches[1]); + for ($i = 0; $i < $matchcount; $i++) + { + $result[$matches[1][$i]] = get_boolean($matches[2][$i]); + } + } + } + + return correct_slideshow_params($result); +} + +/* + * Encode slideshow array params into array + * + * @param array params + * + * @return slideshow values into string + */ +function encode_slideshow_params($decode_params = array()) +{ + global $conf; + + $params = array_diff_assoc(correct_slideshow_params($decode_params), get_default_slideshow_params()); + $result = ''; + + foreach ($params as $name => $value) + { + // boolean_to_string return $value, if it's not a bool + $result .= '+'.$name.'-'.boolean_to_string($value); + } + + return $result; +} + +?> diff --git a/BSF/include/functions_plugins.inc.php b/BSF/include/functions_plugins.inc.php new file mode 100644 index 000000000..e2beb18ac --- /dev/null +++ b/BSF/include/functions_plugins.inc.php @@ -0,0 +1,284 @@ +$func, + 'accepted_args'=>$accepted_args); + ksort( $pwg_event_handlers[$event] ); + return true; +} + +/* Register a event handler. + * @param string $event the name of the event to listen to + * @param mixed $func the function that needs removal + * @param int $priority optional priority (greater priority will + * be executed at last) +*/ +function remove_event_handler($event, $func, + $priority=EVENT_HANDLER_PRIORITY_NEUTRAL) +{ + global $pwg_event_handlers; + + if (!isset( $pwg_event_handlers[$event][$priority] ) ) + { + return false; + } + for ($i=0; $i$event, 'data'=>$data) ); + + if ( !isset($pwg_event_handlers[$event]) ) + { + trigger_action('post_trigger_event', + array('event'=>$event, 'data'=>$data) ); + return $data; + } + $args = array_slice(func_get_args(), 2); + + foreach ($pwg_event_handlers[$event] as $priority => $handlers) + { + if ( !is_null($handlers) ) + { + foreach($handlers as $handler) + { + $all_args = array_merge( array($data), $args); + $function_name = $handler['function']; + $accepted_args = $handler['accepted_args']; + + if ( $accepted_args == 1 ) + $the_args = array($data); + elseif ( $accepted_args > 1 ) + $the_args = array_slice($all_args, 0, $accepted_args); + elseif ( $accepted_args == 0 ) + $the_args = NULL; + else + $the_args = $all_args; + + $data = call_user_func_array($function_name, $the_args); + } + } + } + trigger_action('post_trigger_event', + array('event'=>$event, 'data'=>$data) ); + return $data; +} + +function trigger_action($event, $data=null) +{ + global $pwg_event_handlers; + if ($event!='pre_trigger_event' + and $event!='post_trigger_event' + and $event!='trigger_action') + {// special case for debugging - avoid recursive calls + trigger_action('trigger_action', + array('event'=>$event, 'data'=>$data) ); + } + + if ( !isset($pwg_event_handlers[$event]) ) + { + return; + } + $args = array_slice(func_get_args(), 2); + + foreach ($pwg_event_handlers[$event] as $priority => $handlers) + { + if ( !is_null($handlers) ) + { + foreach($handlers as $handler) + { + $all_args = array_merge( array($data), $args); + $function_name = $handler['function']; + $accepted_args = $handler['accepted_args']; + + if ( $accepted_args == 1 ) + $the_args = array($data); + elseif ( $accepted_args > 1 ) + $the_args = array_slice($all_args, 0, $accepted_args); + elseif ( $accepted_args == 0 ) + $the_args = NULL; + else + $the_args = $all_args; + + call_user_func_array($function_name, $the_args); + } + } + } +} + +/** Saves some data with the associated plugim id. It can be retrieved later ( + * during this script lifetime) using get_plugin_data + * @param string plugin_id + * @param mixed data + * returns true on success, false otherwise + */ +function set_plugin_data($plugin_id, &$data) +{ + global $pwg_loaded_plugins; + if ( isset($pwg_loaded_plugins[$plugin_id]) ) + { + $pwg_loaded_plugins[$plugin_id]['plugin_data'] = &$data; + return true; + } + return false; +} + +/** Retrieves plugin data saved previously with set_plugin_data + * @param string plugin_id + */ +function &get_plugin_data($plugin_id) +{ + global $pwg_loaded_plugins; + if ( isset($pwg_loaded_plugins[$plugin_id]) ) + { + return $pwg_loaded_plugins[$plugin_id]['plugin_data']; + } + return null; +} + +/* Returns an array of plugins defined in the database + * @param string $state optional filter on this state + * @param string $id optional returns only data about given plugin +*/ +function get_db_plugins($state='', $id='') +{ + $query = ' +SELECT * FROM '.PLUGINS_TABLE; + if (!empty($state) or !empty($id) ) + { + $query .= ' +WHERE 1=1'; + if (!empty($state)) + { + $query .= ' + AND state="'.$state.'"'; + } + if (!empty($id)) + { + $query .= ' + AND id="'.$id.'"'; + } + } + + $result = pwg_query($query); + $plugins = array(); + while ($row = mysql_fetch_array($result)) + { + array_push($plugins, $row); + } + return $plugins; +} + + +function load_plugin($plugin) +{ + $file_name = PHPWG_PLUGINS_PATH.$plugin['id'].'/main.inc.php'; + if ( file_exists($file_name) ) + { + global $pwg_loaded_plugins; + $pwg_loaded_plugins[ $plugin['id'] ] = $plugin; + include_once( $file_name ); + } +} + +/*loads all the plugins on startup*/ +function load_plugins() +{ + global $conf, $pwg_loaded_plugins; + $pwg_loaded_plugins = array(); + if ($conf['enable_plugins']) + { + $plugins = get_db_plugins('active'); + foreach( $plugins as $plugin) + {// include main from a function to avoid using same function context + load_plugin($plugin); + } + trigger_action('plugins_loaded'); + } +} +?> \ No newline at end of file diff --git a/BSF/include/functions_rate.inc.php b/BSF/include/functions_rate.inc.php new file mode 100644 index 000000000..ad3de1b2f --- /dev/null +++ b/BSF/include/functions_rate.inc.php @@ -0,0 +1,134 @@ + 3) + { + array_pop($ip_components); + } + $anonymous_id = implode ('.', $ip_components); + + if ($user_anonymous) + { + $save_anonymous_id = pwg_get_cookie_var('anonymous_rater', $anonymous_id); + + if ($anonymous_id != $save_anonymous_id) + { // client has changed his IP adress or he's trying to fool us + $query = ' +SELECT element_id + FROM '.RATE_TABLE.' + WHERE user_id = '.$user['id'].' + AND anonymous_id = \''.$anonymous_id.'\' +;'; + $already_there = array_from_query($query, 'element_id'); + + if (count($already_there) > 0) + { + $query = ' +DELETE + FROM '.RATE_TABLE.' + WHERE user_id = '.$user['id'].' + AND anonymous_id = \''.$save_anonymous_id.'\' + AND element_id IN ('.implode(',', $already_there).') +;'; + pwg_query($query); + } + + $query = ' +UPDATE '.RATE_TABLE.' + SET anonymous_id = \'' .$anonymous_id.'\' + WHERE user_id = '.$user['id'].' + AND anonymous_id = \'' . $save_anonymous_id.'\' +;'; + pwg_query($query); + } // end client changed ip + + pwg_set_cookie_var('anonymous_rater', $anonymous_id); + } // end anonymous user + + $query = ' +DELETE + FROM '.RATE_TABLE.' + WHERE element_id = '.$image_id.' + AND user_id = '.$user['id'].' +'; + if (isset($user_anonymous)) + { + $query.= ' AND anonymous_id = \''.$anonymous_id.'\''; + } + pwg_query($query); + $query = ' +INSERT + INTO '.RATE_TABLE.' + (user_id,anonymous_id,element_id,rate,date) + VALUES + (' + .$user['id'].',' + .'\''.$anonymous_id.'\',' + .$image_id.',' + .$rate + .',NOW()) +;'; + pwg_query($query); + + // update of images.average_rate field + $query = ' +SELECT ROUND(AVG(rate),2) AS average_rate + FROM '.RATE_TABLE.' + WHERE element_id = '.$image_id.' +;'; + $row = mysql_fetch_array(pwg_query($query)); + $query = ' +UPDATE '.IMAGES_TABLE.' + SET average_rate = '.$row['average_rate'].' + WHERE id = '.$image_id.' +;'; + pwg_query($query); +} + +?> \ No newline at end of file diff --git a/BSF/include/functions_search.inc.php b/BSF/include/functions_search.inc.php new file mode 100644 index 000000000..7069bd5c9 --- /dev/null +++ b/BSF/include/functions_search.inc.php @@ -0,0 +1,560 @@ +' : ' <'). + ($search['fields'][$key]['inc'] ? '=' : ''). + " '".$search['fields'][$key]['date']."'" + + ); + } + } + } + + if (isset($search['fields']['cat'])) + { + if ($search['fields']['cat']['sub_inc']) + { + // searching all the categories id of sub-categories + $cat_ids = get_subcat_ids($search['fields']['cat']['words']); + } + else + { + $cat_ids = $search['fields']['cat']['words']; + } + + $local_clause = 'category_id IN ('.implode(',', $cat_ids).')'; + array_push($clauses, $local_clause); + } + + // adds brackets around where clauses + $clauses = prepend_append_array_items($clauses, '(', ')'); + + $where_separator = + implode( + "\n ".$search['mode'].' ', + $clauses + ); + + $search_clause = $where_separator; + + return $search_clause; +} + +/** + * returns the list of items corresponding to the advanced search array + * + * @param array search + * @return array + */ +function get_regular_search_results($search) +{ + $items = array(); + + $search_clause = get_sql_search_clause($search); + + if (!empty($search_clause)) + { + $query = ' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE '.$search_clause.' +;'; + $items = array_from_query($query, 'id'); + } + + if (isset($search['fields']['tags'])) + { + $tag_items = get_image_ids_for_tags( + $search['fields']['tags']['words'], + $search['fields']['tags']['mode'] + ); + + switch ($search['mode']) + { + case 'AND': + { + if (empty($search_clause)) + { + $items = $tag_items; + } + else + { + $items = array_intersect($items, $tag_items); + } + break; + } + case 'OR': + { + $items = array_unique( + array_merge( + $items, + $tag_items + ) + ); + break; + } + } + } + + return $items; +} + +/** + * returns the LIKE sql clause corresponding to the quick search query $q + * and the field $field. example q='john bill', field='file' will return + * file LIKE '%john%' OR file LIKE '%bill%'. Special characters for MySql full + * text search (+,<,>,~) are omitted. The query can contain a phrase: + * 'Pierre "New York"' will return LIKE '%Pierre%' OR LIKE '%New York%'. + * @param string q + * @param string field + * @return string + */ +function get_qsearch_like_clause($q, $field) +{ + $q = stripslashes($q); + $tokens = array(); + $token_modifiers = array(); + $crt_token = ""; + $crt_token_modifier = ""; + $state = 0; + + for ($i=0; $i<~')==0 ) + { //special full text modifier + if (strlen($crt_token)) + { + $tokens[] = $crt_token; + $token_modifiers[] = $crt_token_modifier; + $crt_token = ""; + $crt_token_modifier = ""; + } + $crt_token_modifier .= $ch; + } + elseif (preg_match('/[\s,.;!\?]+/', $ch)) + { // white space + if (strlen($crt_token)) + { + $tokens[] = $crt_token; + $token_modifiers[] = $crt_token_modifier; + $crt_token = ""; + $crt_token_modifier = ""; + } + } + else + { + $crt_token .= $ch; + } + break; + case 1: // qualified with quotes + switch ($ch) + { + case '"': + $tokens[] = $crt_token; + $token_modifiers[] = $crt_token_modifier; + $crt_token = ""; + $crt_token_modifier = ""; + $state=0; + break; + default: + $crt_token .= $ch; + } + break; + } + } + if (strlen($crt_token)) + { + $tokens[] = $crt_token; + $token_modifiers[] = $crt_token_modifier; + } + + $clauses = array(); + for ($i=0; $i array(85,68,79...) + * 'as_is' => 1 (indicates the caller that items are ordered and permissions checked + * 'qs' => array( + * 'matching_tags' => array of matching tags + * 'matching_cats' => array of matching categories + * 'matching_cats_no_images' =>array(99) - matching categories without images + * )) + * + * @param string q + * @param string images_where optional aditional restriction on images table + * @return array + */ +function get_quick_search_results($q, $images_where='') +{ + global $page; + $search_results = + array( + 'items' => array(), + 'as_is' => 1, + 'qs' => array('q'=>stripslashes($q)), + ); + $q = trim($q); + if (empty($q)) + { + return $search_results; + } + $q_like_field = '@@__db_field__@@'; //something never in a search + $q_like_clause = get_qsearch_like_clause($q, $q_like_field ); + + + // Step 1 - first we find matches in #images table =========================== + $where_clauses='MATCH(i.name, i.comment) AGAINST( "'.$q.'" IN BOOLEAN MODE)'; + if (!empty($q_like_clause)) + { + $where_clauses .= ' + OR '. str_replace($q_like_field, 'file', $q_like_clause); + $where_clauses = '('.$where_clauses.')'; + } + $where_clauses = array($where_clauses); + if (!empty($images_where)) + { + $where_clauses[]='('.$images_where.')'; + } + $where_clauses[] .= get_sql_condition_FandF + ( + array( 'visible_images' => 'i.id' ), null, true + ); + $query = ' +SELECT i.id, + MATCH(i.name, i.comment) AGAINST( "'.$q.'" IN BOOLEAN MODE) AS weight + FROM '.IMAGES_TABLE.' i + WHERE '.implode("\n AND ", $where_clauses); + + $by_weights=array(); + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { // weight is important when sorting images by relevance + if ($row['weight']) + { + $by_weights[(int)$row['id']] = 2*$row['weight']; + } + else + {//full text does not match but file name match + $by_weights[(int)$row['id']] = 2; + } + } + + + // Step 2 - search tags corresponding to the query $q ======================== + if (!empty($q_like_clause)) + { // search name and url name (without accents) + $query = ' +SELECT id, name, url_name + FROM '.TAGS_TABLE.' + WHERE ('.str_replace($q_like_field, 'CONVERT(name, CHAR)', $q_like_clause).' + OR '.str_replace($q_like_field, 'url_name', $q_like_clause).')'; + $tags = hash_from_query($query, 'id'); + if ( !empty($tags) ) + { // we got some tags; get the images + $search_results['qs']['matching_tags']=$tags; + $query = ' +SELECT image_id, COUNT(tag_id) AS weight + FROM '.IMAGE_TAG_TABLE.' + WHERE tag_id IN ('.implode(',',array_keys($tags)).') + GROUP BY image_id'; + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { // weight is important when sorting images by relevance + $image_id=(int)$row['image_id']; + @$by_weights[$image_id] += $row['weight']; + } + } + } + + + // Step 3 - search categories corresponding to the query $q ================== + global $user; + $query = ' +SELECT id, name, permalink, nb_images + FROM '.CATEGORIES_TABLE.' + INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' ON id=cat_id + WHERE user_id='.$user['id'].' + AND MATCH(name, comment) AGAINST( "'.$q.'" IN BOOLEAN MODE)'. + get_sql_condition_FandF ( + array( 'visible_categories' => 'cat_id' ), "\n AND" + ); + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { // weight is important when sorting images by relevance + if ($row['nb_images']==0) + { + $search_results['qs']['matching_cats_no_images'][] = $row; + } + else + { + $search_results['qs']['matching_cats'][$row['id']] = $row; + } + } + + if ( empty($by_weights) and empty($search_results['qs']['matching_cats']) ) + { + return $search_results; + } + + // Step 4 - now we have $by_weights ( array image id => weight ) that need + // permission checks and/or matching categories to get images from + $where_clauses = array(); + if ( !empty($by_weights) ) + { + $where_clauses[]='i.id IN (' + . implode(',', array_keys($by_weights)) . ')'; + } + if ( !empty($search_results['qs']['matching_cats']) ) + { + $where_clauses[]='category_id IN ('. + implode(',',array_keys($search_results['qs']['matching_cats'])).')'; + } + $where_clauses = array( '('.implode("\n OR ",$where_clauses).')' ); + if (!empty($images_where)) + { + $where_clauses[]='('.$images_where.')'; + } + $where_clauses[] = get_sql_condition_FandF( + array + ( + 'forbidden_categories' => 'category_id', + 'visible_categories' => 'category_id', + 'visible_images' => 'i.id' + ), + null,true + ); + + global $conf; + $query = ' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' i + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE '.implode("\n AND ", $where_clauses)."\n". + $conf['order_by']; + + $allowed_images = array_from_query( $query, 'id'); + + if ( isset($page['super_order_by']) or empty($by_weights) ) + { + $search_results['items'] = $allowed_images; + return $search_results; + } + + $allowed_images = array_flip( $allowed_images ); + $divisor = 5.0 * count($allowed_images); + foreach ($allowed_images as $id=>$rank ) + { + $weight = isset($by_weights[$id]) ? $by_weights[$id] : 1; + $weight -= $rank/$divisor; + $allowed_images[$id] = $weight; + } + arsort($allowed_images, SORT_NUMERIC); + $search_results['items'] = array_keys($allowed_images); + return $search_results; +} + +/** + * returns an array of 'items' corresponding to the search id + * + * @param int search id + * @param string images_where optional aditional restriction on images table + * @return array + */ +function get_search_results($search_id, $images_where='') +{ + $search = get_search_array($search_id); + if ( !isset($search['q']) ) + { + $result['items'] = get_regular_search_results($search); + return $result; + } + else + { + return get_quick_search_results($search['q'], $images_where); + } +} +?> \ No newline at end of file diff --git a/BSF/include/functions_session.inc.php b/BSF/include/functions_session.inc.php new file mode 100644 index 000000000..f17f2377a --- /dev/null +++ b/BSF/include/functions_session.inc.php @@ -0,0 +1,225 @@ +0 ) + { + return true; + } + $query = ' +INSERT INTO '.SESSIONS_TABLE.' + (id,data,expiration) + VALUES(\''.$session_id.'\',\''.$data.'\',now()) +;'; + mysql_query($query); + return true; +} + +/** + * returns true; delete the active session + * + * @param string session id + */ +function pwg_session_destroy($session_id) +{ + $query = ' +DELETE + FROM '.SESSIONS_TABLE.' + WHERE id = \''.$session_id.'\' +;'; + pwg_query($query); + return true; +} + +/** + * returns true; delete expired sessions + * called each time a session is closed. + */ +function pwg_session_gc() +{ + global $conf; + + $query = ' +DELETE + FROM '.SESSIONS_TABLE.' + WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(expiration) > ' + .$conf['session_length'].' +;'; + pwg_query($query); + return true; +} + + +/** + * persistently stores a variable for the current session + * currently we use standard php sessions but it might change + * @return boolean true on success + * @see pwg_get_session_var, pwg_unset_session_var + */ +function pwg_set_session_var($var, $value) +{ + if ( !isset($_SESSION) ) + return false; + $_SESSION['pwg_'.$var] = $value; + return true; +} + +/** + * retrieves the value of a persistent variable for the current session + * currently we use standard php sessions but it might change + * @return mixed + * @see pwg_set_session_var, pwg_unset_session_var + */ +function pwg_get_session_var($var, $default = null) +{ + if (isset( $_SESSION['pwg_'.$var] ) ) + { + return $_SESSION['pwg_'.$var]; + } + return $default; +} + +/** + * deletes a persistent variable for the current session + * currently we use standard php sessions but it might change + * @return boolean true on success + * @see pwg_set_session_var, pwg_get_session_var + */ +function pwg_unset_session_var($var) +{ + if ( !isset($_SESSION) ) + return false; + unset( $_SESSION['pwg_'.$var] ); + return true; +} + +?> diff --git a/BSF/include/functions_tag.inc.php b/BSF/include/functions_tag.inc.php new file mode 100644 index 000000000..7bd5d8408 --- /dev/null +++ b/BSF/include/functions_tag.inc.php @@ -0,0 +1,323 @@ + 'category_id', + 'visible_categories' => 'category_id', + 'visible_images' => 'ic.image_id' + ), + ' + WHERE' + ).' + GROUP BY tag_id + ORDER BY NULL'; + $tag_counters = simple_hash_from_query($query, 'tag_id', 'counter'); + + if ( empty($tag_counters) ) + { + return array(); + } + + $query = ' +SELECT id, name, url_name + FROM '.TAGS_TABLE; + $result = pwg_query($query); + $tags = array(); + while ($row = mysql_fetch_assoc($result)) + { + $counter = @$tag_counters[ $row['id'] ]; + if ( $counter ) + { + $row['counter'] = $counter; + array_push($tags, $row); + } + } + return $tags; +} + +/** + * All tags, even tags associated to no image. + * + * @return array + */ +function get_all_tags() +{ + $query = ' +SELECT id, + name, + url_name + FROM '.TAGS_TABLE.' +;'; + $result = pwg_query($query); + $tags = array(); + while ($row = mysql_fetch_assoc($result)) + { + array_push($tags, $row); + } + + usort($tags, 'name_compare'); + + return $tags; +} + +/** + * Giving a set of tags with a counter for each one, calculate the display + * level of each tag. + * + * The level of each tag depends on the average count of tags. This + * calcylation method avoid having very different levels for tags having + * nearly the same count when set are small. + * + * @param array tags + * @return array + */ +function add_level_to_tags($tags) +{ + global $conf; + + if (count($tags) == 0) + { + return $tags; + } + + $total_count = 0; + + foreach ($tags as $tag) + { + $total_count+= $tag['counter']; + } + + // average count of available tags will determine the level of each tag + $tag_average_count = $total_count / count($tags); + + // tag levels threshold calculation: a tag with an average rate must have + // the middle level. + for ($i = 1; $i < $conf['tags_levels']; $i++) + { + $threshold_of_level[$i] = + 2 * $i * $tag_average_count / $conf['tags_levels']; + } + + // display sorted tags + foreach (array_keys($tags) as $k) + { + $tags[$k]['level'] = 1; + + // based on threshold, determine current tag level + for ($i = $conf['tags_levels'] - 1; $i >= 1; $i--) + { + if ($tags[$k]['counter'] > $threshold_of_level[$i]) + { + $tags[$k]['level'] = $i + 1; + break; + } + } + } + + return $tags; +} + +/** + * return the list of image ids corresponding to given tags. AND & OR mode + * supported. + * + * @param array tag ids + * @param string mode + * @return array + */ +function get_image_ids_for_tags($tag_ids, $mode = 'AND') +{ + switch ($mode) + { + case 'AND': + { + // strategy is to list images associated to each tag + $tag_images = array(); + + foreach ($tag_ids as $tag_id) + { + $query = ' +SELECT image_id + FROM '.IMAGE_TAG_TABLE.' + WHERE tag_id = '.$tag_id.' +;'; + $tag_images[$tag_id] = array_from_query($query, 'image_id'); + } + + // then we calculate the intersection, the images that are associated to + // every tags + $items = array_shift($tag_images); + foreach ($tag_images as $images) + { + $items = array_intersect($items, $images); + } + + return array_unique($items); + break; + } + case 'OR': + { + $query = ' +SELECT DISTINCT image_id + FROM '.IMAGE_TAG_TABLE.' + WHERE tag_id IN ('.implode(',', $tag_ids).') +;'; + return array_from_query($query, 'image_id'); + break; + } + default: + { + die('get_image_ids_for_tags: unknown mode, only AND & OR are supported'); + } + } +} + +/** + * return a list of tags corresponding to given items. + * + * @param array items + * @param array max_tags + * @param array excluded_tag_ids + * @return array + */ +function get_common_tags($items, $max_tags, $excluded_tag_ids=null) +{ + if (empty($items)) + { + return array(); + } + $query = ' +SELECT id, name, url_name, count(*) counter + FROM '.IMAGE_TAG_TABLE.' + INNER JOIN '.TAGS_TABLE.' ON tag_id = id + WHERE image_id IN ('.implode(',', $items).')'; + if (!empty($excluded_tag_ids)) + { + $query.=' + AND tag_id NOT IN ('.implode(',', $excluded_tag_ids).')'; + } + $query .=' + GROUP BY tag_id'; + if ($max_tags>0) + { + $query .= ' + ORDER BY counter DESC + LIMIT 0,'.$max_tags; + } + else + { + $query .= ' + ORDER BY NULL'; + } + + $result = pwg_query($query); + $tags = array(); + while($row = mysql_fetch_assoc($result)) + { + array_push($tags, $row); + } + usort($tags, 'name_compare'); + return $tags; +} + +/** + * return a list of tags corresponding to any of ids, url_names, names + * + * @param array ids + * @param array url_names + * @param array names + * @return array + */ +function find_tags($ids, $url_names=array(), $names=array() ) +{ + $where_clauses = array(); + if ( !empty($ids) ) + { + $where_clauses[] = 'id IN ('.implode(',', $ids).')'; + } + if ( !empty($url_names) ) + { + $where_clauses[] = + 'url_name IN ('. + implode( + ',', + array_map( + create_function('$s', 'return "\'".$s."\'";'), + $url_names + ) + ) + .')'; + } + if ( !empty($names) ) + { + $where_clauses[] = + 'name IN ('. + implode( + ',', + array_map( + create_function('$s', 'return "\'".$s."\'";'), + $names + ) + ) + .')'; + } + if (empty($where_clauses)) + { + return array(); + } + + $query = ' +SELECT id, url_name, name + FROM '.TAGS_TABLE.' + WHERE '. implode( ' + OR ', $where_clauses); + + $result = pwg_query($query); + $tags = array(); + while ($row = mysql_fetch_assoc($result)) + { + array_push($tags, $row); + } + return $tags; +} +?> \ No newline at end of file diff --git a/BSF/include/functions_url.inc.php b/BSF/include/functions_url.inc.php new file mode 100644 index 000000000..fa7114dea --- /dev/null +++ b/BSF/include/functions_url.inc.php @@ -0,0 +1,740 @@ +'b')) returns /x?a=b + * add_url_params('/x?cat_id=10', array('a'=>'b')) returns /x?cat_id=10&a=b + * @param string url + * @param array params + * @return string + */ +function add_url_params($url, $params) +{ + if ( !empty($params) ) + { + assert( is_array($params) ); + $is_first = true; + foreach($params as $param=>$val) + { + if ($is_first) + { + $is_first = false; + $url .= ( strstr($url, '?')===false ) ? '?' :'&'; + } + else + { + $url .= '&'; + } + $url .= $param; + if (isset($val)) + { + $url .= '='.$val; + } + } + } + return $url; +} + +/** + * build an index URL for a specific section + * + * @param array + * @return string + */ +function make_index_url($params = array()) +{ + global $conf; + $url = get_root_url().'index'; + if ($conf['php_extension_in_urls']) + { + $url .= '.php'; + } + if ($conf['question_mark_in_urls']) + { + $url .= '?'; + } + $url.= make_section_in_url($params); + $url = add_well_known_params_in_url($url, $params); + return $url; +} + +/** + * build an index URL with current page parameters, but with redefinitions + * and removes. + * + * duplicate_index_url( array( + * 'category' => array('id'=>12, 'name'=>'toto'), + * array('start') + * ) will create an index URL on the current section (categories), but on + * a redefined category and without the start URL parameter. + * + * @param array redefined keys + * @param array removed keys + * @return string + */ +function duplicate_index_url($redefined = array(), $removed = array()) +{ + return make_index_url( + params_for_duplication($redefined, $removed) + ); +} + +/** + * returns $page global array with key redefined and key removed + * + * @param array redefined keys + * @param array removed keys + * @return array + */ +function params_for_duplication($redefined, $removed) +{ + global $page; + + if (count($removed) > 0) + { + $params = array(); + + foreach ($page as $page_item_key => $page_item_value) + { + if (!in_array($page_item_key, $removed)) + { + $params[$page_item_key] = $page_item_value; + } + } + } + else + { + $params = $page; + } + + foreach ($redefined as $redefined_param => $redefined_value) + { + $params[$redefined_param] = $redefined_value; + } + + return $params; +} + +/** + * create a picture URL with current page parameters, but with redefinitions + * and removes. See duplicate_index_url. + * + * @param array redefined keys + * @param array removed keys + * @return string + */ +function duplicate_picture_url($redefined = array(), $removed = array()) +{ + return make_picture_url( + params_for_duplication($redefined, $removed) + ); +} + +/** + * create a picture URL on a specific section for a specific picture + * + * @param array + * @return string + */ +function make_picture_url($params) +{ + global $conf; + if (!isset($params['image_id'])) + { + die('make_picture_url: image_id is a required parameter'); + } + + $url = get_root_url().'picture'; + if ($conf['php_extension_in_urls']) + { + $url .= '.php'; + } + if ($conf['question_mark_in_urls']) + { + $url .= '?'; + } + $url.= '/'; + switch ( $conf['picture_url_style'] ) + { + case 'id-file': + $url .= $params['image_id']; + if ( isset($params['image_file']) ) + { + $url .= '-'.get_filename_wo_extension($params['image_file']); + } + break; + case 'file': + if ( isset($params['image_file']) ) + { + $fname_wo_ext = get_filename_wo_extension($params['image_file']); + if (! preg_match('/^\d+(-|$)/', $fname_wo_ext) ) + { + $url .= $fname_wo_ext; + break; + } + } + default: + $url .= $params['image_id']; + } + if ( !isset($params['category'] ) ) + {// make urls shorter ... + unset( $params['flat'] ); + } + $url .= make_section_in_url($params); + $url = add_well_known_params_in_url($url, $params); + return $url; +} + +/** + *adds to the url the chronology and start parameters +*/ +function add_well_known_params_in_url($url, $params) +{ + if ( isset($params['chronology_field']) ) + { + $url .= '/'. $params['chronology_field']; + $url .= '-'. $params['chronology_style']; + if ( isset($params['chronology_view']) ) + { + $url .= '-'. $params['chronology_view']; + } + if ( !empty($params['chronology_date']) ) + { + $url .= '-'. implode('-', $params['chronology_date'] ); + } + } + + if (isset($params['flat'])) + { + $url.= '/flat'; + } + + if (isset($params['start']) and $params['start'] > 0) + { + $url.= '/start-'.$params['start']; + } + return $url; +} + +/** + * return the section token of an index or picture URL. + * + * Depending on section, other parameters are required (see function code + * for details) + * + * @param array + * @return string + */ +function make_section_in_url($params) +{ + global $conf; + $section_string = ''; + + $section_of = array( + 'category' => 'categories', + 'tags' => 'tags', + 'list' => 'list', + 'search' => 'search', + ); + + foreach ($section_of as $param => $section) + { + if (isset($params[$param])) + { + $params['section'] = $section; + } + } + + if (!isset($params['section'])) + { + $params['section'] = 'none'; + } + + switch($params['section']) + { + case 'categories' : + { + if (!isset($params['category'])) + { + $section_string.= '/categories'; + } + else + { + is_array($params['category']) or trigger_error( + 'make_section_in_url wrong type for category', E_USER_WARNING + ); + is_numeric($params['category']['id']) or trigger_error( + 'make_section_in_url category id not numeric', E_USER_WARNING + ); + isset($params['category']['name']) or trigger_error( + 'make_section_in_url category name not set', E_USER_WARNING + ); + + array_key_exists('permalink', $params['category']) or trigger_error( + 'make_section_in_url category permalink not set', E_USER_WARNING + ); + + $section_string.= '/category/'; + if ( empty($params['category']['permalink']) ) + { + $section_string.= $params['category']['id']; + if ( $conf['category_url_style']=='id-name' ) + { + $section_string.= '-'.str2url($params['category']['name']); + } + } + else + { + $section_string.= $params['category']['permalink']; + } + } + + break; + } + case 'tags' : + { + if (!isset($params['tags']) or count($params['tags']) == 0) + { + die('make_section_in_url: require at least one tag'); + } + + $section_string.= '/tags'; + + foreach ($params['tags'] as $tag) + { + switch ( $conf['tag_url_style'] ) + { + case 'id': + $section_string.= '/'.$tag['id']; + break; + case 'tag': + if (isset($tag['url_name']) and !is_numeric($tag['url_name']) ) + { + $section_string.= '/'.$tag['url_name']; + break; + } + default: + $section_string.= '/'.$tag['id']; + if (isset($tag['url_name'])) + { + $section_string.= '-'.$tag['url_name']; + } + } + } + + break; + } + case 'search' : + { + if (!isset($params['search'])) + { + die('make_section_in_url: require a search identifier'); + } + + $section_string.= '/search/'.$params['search']; + + break; + } + case 'list' : + { + if (!isset($params['list'])) + { + die('make_section_in_url: require a list of items'); + } + + $section_string.= '/list/'.implode(',', $params['list']); + + break; + } + case 'none' : + { + break; + } + default : + { + $section_string.= '/'.$params['section']; + } + } + + return $section_string; +} + +/** + * the reverse of make_section_in_url + * returns the 'section' (categories/tags/...) and the data associated with it + * + * Depending on section, other parameters are returned (category/tags/list/...) + * + * @param array of url tokens to parse + * @param int the index in the array of url tokens; in/out + * @return array + */ +function parse_section_url( $tokens, &$next_token) +{ + $page=array(); + if (0 === strpos(@$tokens[$next_token], 'categor')) + { + $page['section'] = 'categories'; + $next_token++; + + if (isset($tokens[$next_token]) ) + { + if (preg_match('/^(\d+)(?:-(.+))?$/', $tokens[$next_token], $matches)) + { + if ( isset($matches[2]) ) + $page['hit_by']['cat_url_name'] = $matches[2]; + $page['category'] = $matches[1]; + $next_token++; + } + else + {// try a permalink + $maybe_permalinks = array(); + $current_token = $next_token; + while ( isset($tokens[$current_token]) + and strpos($tokens[$current_token], 'created-')!==0 + and strpos($tokens[$current_token], 'posted-')!==0 + and strpos($tokens[$next_token], 'start-')!==0 + and $tokens[$current_token] != 'flat') + { + if (empty($maybe_permalinks)) + { + array_push($maybe_permalinks, $tokens[$current_token]); + } + else + { + array_push($maybe_permalinks, + $maybe_permalinks[count($maybe_permalinks)-1] + . '/' . $tokens[$current_token] + ); + } + $current_token++; + } + + if ( count($maybe_permalinks) ) + { + $cat_id = get_cat_id_from_permalinks($maybe_permalinks, $perma_index); + if ( isset($cat_id) ) + { + $next_token += $perma_index+1; + $page['category'] = $cat_id; + $page['hit_by']['cat_permalink'] = $maybe_permalinks[$perma_index]; + } + else + { + page_not_found('Permalink for album not found'); + } + } + } + } + + if (isset($page['category'])) + { + $result = get_cat_info($page['category']); + if (empty($result)) + { + page_not_found('Requested category does not exist' ); + } + $page['category']=$result; + } + } + else if (0 === strpos(@$tokens[$next_token], 'tag')) + { + $page['section'] = 'tags'; + $page['tags'] = array(); + + $next_token++; + $i = $next_token; + + $requested_tag_ids = array(); + $requested_tag_url_names = array(); + + while (isset($tokens[$i])) + { + if ( preg_match('/^(created-|posted-|start-(\d)+)/', $tokens[$i]) ) + break; + + if ( preg_match('/^(\d+)(?:-(.*))?/', $tokens[$i], $matches) ) + { + array_push($requested_tag_ids, $matches[1]); + } + else + { + array_push($requested_tag_url_names, $tokens[$i]); + } + $i++; + } + $next_token = $i; + + if ( empty($requested_tag_ids) && empty($requested_tag_url_names) ) + { + bad_request('at least one tag required'); + } + + $page['tags'] = find_tags($requested_tag_ids, $requested_tag_url_names); + if ( empty($page['tags']) ) + { + page_not_found('Requested tag does not exist', get_root_url().'tags.php' ); + } + } + else if (0 === strpos(@$tokens[$next_token], 'fav')) + { + $page['section'] = 'favorites'; + $next_token++; + } + else if ('most_visited' == @$tokens[$next_token]) + { + $page['section'] = 'most_visited'; + $next_token++; + } + else if ('best_rated' == @$tokens[$next_token]) + { + $page['section'] = 'best_rated'; + $next_token++; + } + else if ('recent_pics' == @$tokens[$next_token]) + { + $page['section'] = 'recent_pics'; + $next_token++; + } + else if ('recent_cats' == @$tokens[$next_token]) + { + $page['section'] = 'recent_cats'; + $next_token++; + } + else if ('search' == @$tokens[$next_token]) + { + $page['section'] = 'search'; + $next_token++; + + preg_match('/(\d+)/', @$tokens[$next_token], $matches); + if (!isset($matches[1])) + { + bad_request('search identifier is missing'); + } + $page['search'] = $matches[1]; + $next_token++; + } + else if ('list' == @$tokens[$next_token]) + { + $page['section'] = 'list'; + $next_token++; + + $page['list'] = array(); + + // No pictures + if (empty($tokens[$next_token])) + { + // Add dummy element list + array_push($page['list'], -1); + } + // With pictures list + else + { + if (!preg_match('/^\d+(,\d+)*$/', $tokens[$next_token])) + { + bad_request('wrong format on list GET parameter'); + } + foreach (explode(',', $tokens[$next_token]) as $image_id) + { + array_push($page['list'], $image_id); + } + } + $next_token++; + } + return $page; +} + +/** + * the reverse of add_well_known_params_in_url + * parses start, flat and chronology from url tokens +*/ +function parse_well_known_params_url($tokens, &$i) +{ + $page = array(); + while (isset($tokens[$i])) + { + if (preg_match('/^start-(\d+)/', $tokens[$i], $matches)) + { + $page['start'] = $matches[1]; + } + + if ( 'flat' == $tokens[$i] ) + { + // indicate a special list of images + $page['flat'] = true; + } + + if (preg_match('/^(posted|created)/', $tokens[$i] )) + { + $chronology_tokens = explode('-', $tokens[$i] ); + + $page['chronology_field'] = $chronology_tokens[0]; + + array_shift($chronology_tokens); + $page['chronology_style'] = $chronology_tokens[0]; + + array_shift($chronology_tokens); + if ( count($chronology_tokens)>0 ) + { + if ('list'==$chronology_tokens[0] or + 'calendar'==$chronology_tokens[0]) + { + $page['chronology_view'] = $chronology_tokens[0]; + array_shift($chronology_tokens); + } + $page['chronology_date'] = $chronology_tokens; + } + } + $i++; + } + return $page; +} + +/** + * Indicate to build url with full path + * + * @param null + * @return null + */ +function set_make_full_url() +{ + global $page; + + if (!isset($page['save_root_path'])) + { + if (isset($page['root_path'])) + { + $page['save_root_path']['path'] = $page['root_path']; + } + $page['save_root_path']['count'] = 1; + $page['root_path'] = get_absolute_root_url(); + } + else + { + $page['save_root_path']['count'] += 1; + } +} + +/** + * Restore old parameter to build url with full path + * + * @param null + * @return null + */ +function unset_make_full_url() +{ + global $page; + + if (isset($page['save_root_path'])) + { + if ($page['save_root_path']['count'] == 1) + { + if (isset($page['save_root_path']['path'])) + { + $page['root_path'] = $page['save_root_path']['path']; + } + else + { + unset($page['root_path']); + } + unset($page['save_root_path']); + } + else + { + $page['save_root_path']['count'] -= 1; + } + } +} + +/** + * Embellish the url argument + * + * @param $url + * @return $url embellished + */ +function embellish_url($url) +{ + return str_replace('/./', '/', $url); +} + +?> \ No newline at end of file diff --git a/BSF/include/functions_user.inc.php b/BSF/include/functions_user.inc.php new file mode 100644 index 000000000..d2c9530e2 --- /dev/null +++ b/BSF/include/functions_user.inc.php @@ -0,0 +1,1340 @@ +$login, + 'password'=>$password, + 'email'=>$mail_address, + ) + ); + + // if no error until here, registration of the user + if (count($errors) == 0) + { + // what will be the inserted id ? + $query = ' +SELECT MAX('.$conf['user_fields']['id'].') + 1 + FROM '.USERS_TABLE.' +;'; + list($next_id) = mysql_fetch_array(pwg_query($query)); + + $insert = + array( + $conf['user_fields']['id'] => $next_id, + $conf['user_fields']['username'] => mysql_escape_string($login), + $conf['user_fields']['password'] => $conf['pass_convert']($password), + $conf['user_fields']['email'] => $mail_address + ); + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + mass_inserts(USERS_TABLE, array_keys($insert), array($insert)); + + // Assign by default groups + { + $query = ' +SELECT id + FROM '.GROUPS_TABLE.' + WHERE is_default = \''.boolean_to_string(true).'\' + ORDER BY id ASC +;'; + $result = pwg_query($query); + + $inserts = array(); + while ($row = mysql_fetch_array($result)) + { + array_push + ( + $inserts, + array + ( + 'user_id' => $next_id, + 'group_id' => $row['id'] + ) + ); + } + } + + if (count($inserts) != 0) + { + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + mass_inserts(USER_GROUP_TABLE, array('user_id', 'group_id'), $inserts); + } + + create_user_infos($next_id); + + if ($with_notification and $conf['email_admin_on_new_user']) + { + include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php'); + $admin_url = get_absolute_root_url() + .'admin.php?page=user_list&username='.$login; + + $keyargs_content = array + ( + get_l10n_args('User: %s', $login), + get_l10n_args('Email: %s', $_POST['mail_address']), + get_l10n_args('', ''), + get_l10n_args('Admin: %s', $admin_url) + ); + + pwg_mail_notification_admins + ( + get_l10n_args('Registration of %s', $login), + $keyargs_content + ); + } + + trigger_action('register_user', + array( + 'id'=>$next_id, + 'username'=>$login, + 'email'=>$mail_address, + ) + ); + } + + return $errors; +} + +function build_user( $user_id, $use_cache ) +{ + global $conf; + + $user['id'] = $user_id; + $user = array_merge( $user, getuserdata($user_id, $use_cache) ); + + if ($user['id'] == $conf['guest_id'] and $user['status'] <> 'guest') + { + $user['status'] = 'guest'; + $user['internal_status']['guest_must_be_guest'] = true; + } + + // calculation of the number of picture to display per page + $user['nb_image_page'] = $user['nb_image_line'] * $user['nb_line_page']; + + if (is_admin($user['status'])) + { + list($user['admin_template'], $user['admin_theme']) = + explode ('/', $conf['admin_layout']); + } + + list($user['template'], $user['theme']) = explode('/', $user['template']); + + return $user; +} + +/** + * find informations related to the user identifier + * + * @param int user identifier + * @param boolean use_cache + * @param array + */ +function getuserdata($user_id, $use_cache) +{ + global $conf; + + $userdata = array(); + + $query = ' +SELECT '; + $is_first = true; + foreach ($conf['user_fields'] as $pwgfield => $dbfield) + { + if ($is_first) + { + $is_first = false; + } + else + { + $query.= ' + , '; + } + $query.= $dbfield.' AS '.$pwgfield; + } + $query.= ' + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['id'].' = \''.$user_id.'\' +;'; + + $row = mysql_fetch_array(pwg_query($query)); + + while (true) + { + $query = ' +SELECT ui.*, uc.* + FROM '.USER_INFOS_TABLE.' AS ui LEFT JOIN '.USER_CACHE_TABLE.' AS uc + ON ui.user_id = uc.user_id + WHERE ui.user_id = \''.$user_id.'\' +;'; + $result = pwg_query($query); + if (mysql_num_rows($result) > 0) + { + break; + } + else + { + create_user_infos($user_id); + } + } + + $row = array_merge($row, mysql_fetch_array($result)); + + foreach ($row as $key => $value) + { + if (!is_numeric($key)) + { + // If the field is true or false, the variable is transformed into a + // boolean value. + if ($value == 'true' or $value == 'false') + { + $userdata[$key] = get_boolean($value); + } + else + { + $userdata[$key] = $value; + } + } + } + + if ($use_cache) + { + if (!isset($userdata['need_update']) + or !is_bool($userdata['need_update']) + or $userdata['need_update'] == true) + { + $userdata['forbidden_categories'] = + calculate_permissions($userdata['id'], $userdata['status']); + + /* now we build the list of forbidden images (this list does not contain + images that are not in at least an authorized category)*/ + $query = ' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id=image_id + WHERE category_id NOT IN ('.$userdata['forbidden_categories'].') + AND level>'.$userdata['level']; + $forbidden_ids = array_from_query($query, 'id'); + + if ( empty($forbidden_ids) ) + { + array_push( $forbidden_ids, 0 ); + } + $userdata['image_access_type'] = 'NOT IN'; //TODO maybe later + $userdata['image_access_list'] = implode(',',$forbidden_ids); + + update_user_cache_categories($userdata); + + // Set need update are done + $userdata['need_update'] = false; + + // Indicate update done + $userdata['need_update_done'] = true; + + $query = ' +SELECT COUNT(DISTINCT(image_id)) as total + FROM '.IMAGE_CATEGORY_TABLE.' + WHERE category_id NOT IN ('.$userdata['forbidden_categories'].') + AND image_id '.$userdata['image_access_type'].' ('.$userdata['image_access_list'].') +;'; + list($userdata['nb_total_images']) = mysql_fetch_array(pwg_query($query)); + + // update user cache + $query = ' +DELETE FROM '.USER_CACHE_TABLE.' + WHERE user_id = '.$userdata['id'].' +;'; + pwg_query($query); + + $query = ' +INSERT INTO '.USER_CACHE_TABLE.' + (user_id, need_update, forbidden_categories, nb_total_images, + image_access_type, image_access_list) + VALUES + ('.$userdata['id'].',\''.boolean_to_string($userdata['need_update']).'\',\'' + .$userdata['forbidden_categories'].'\','.$userdata['nb_total_images'].',"' + .$userdata['image_access_type'].'","'.$userdata['image_access_list'].'") +;'; + pwg_query($query); + } + else + { + // Indicate update not done + $userdata['need_update_done'] = false; + } + } + + return $userdata; +} + +/* + * deletes favorites of the current user if he's not allowed to see them + * + * @return void + */ +function check_user_favorites() +{ + global $user; + + if ($user['forbidden_categories'] == '') + { + return; + } + + // $filter['visible_categories'] and $filter['visible_images'] + // must be not used because filter <> restriction + // retrieving images allowed : belonging to at least one authorized + // category + $query = ' +SELECT DISTINCT f.image_id + FROM '.FAVORITES_TABLE.' AS f INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic + ON f.image_id = ic.image_id + WHERE f.user_id = '.$user['id'].' +'.get_sql_condition_FandF + ( + array + ( + 'forbidden_categories' => 'ic.category_id', + ), + 'AND' + ).' +;'; + $result = pwg_query($query); + $authorizeds = array(); + while ($row = mysql_fetch_array($result)) + { + array_push($authorizeds, $row['image_id']); + } + + $query = ' +SELECT image_id + FROM '.FAVORITES_TABLE.' + WHERE user_id = '.$user['id'].' +;'; + $result = pwg_query($query); + $favorites = array(); + while ($row = mysql_fetch_array($result)) + { + array_push($favorites, $row['image_id']); + } + + $to_deletes = array_diff($favorites, $authorizeds); + + if (count($to_deletes) > 0) + { + $query = ' +DELETE FROM '.FAVORITES_TABLE.' + WHERE image_id IN ('.implode(',', $to_deletes).') + AND user_id = '.$user['id'].' +;'; + pwg_query($query); + } +} + +/** + * calculates the list of forbidden categories for a given user + * + * Calculation is based on private categories minus categories authorized to + * the groups the user belongs to minus the categories directly authorized + * to the user. The list contains at least -1 to be compliant with queries + * such as "WHERE category_id NOT IN ($forbidden_categories)" + * + * @param int user_id + * @param string user_status + * @return string forbidden_categories + */ +function calculate_permissions($user_id, $user_status) +{ + $private_array = array(); + $authorized_array = array(); + + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE status = \'private\' +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($private_array, $row['id']); + } + + // retrieve category ids directly authorized to the user + $query = ' +SELECT cat_id + FROM '.USER_ACCESS_TABLE.' + WHERE user_id = '.$user_id.' +;'; + $authorized_array = array_from_query($query, 'cat_id'); + + // retrieve category ids authorized to the groups the user belongs to + $query = ' +SELECT cat_id + FROM '.USER_GROUP_TABLE.' AS ug INNER JOIN '.GROUP_ACCESS_TABLE.' AS ga + ON ug.group_id = ga.group_id + WHERE ug.user_id = '.$user_id.' +;'; + $authorized_array = + array_merge( + $authorized_array, + array_from_query($query, 'cat_id') + ); + + // uniquify ids : some private categories might be authorized for the + // groups and for the user + $authorized_array = array_unique($authorized_array); + + // only unauthorized private categories are forbidden + $forbidden_array = array_diff($private_array, $authorized_array); + + // if user is not an admin, locked categories are forbidden + if (!is_admin($user_status)) + { + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE visible = \'false\' +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($forbidden_array, $row['id']); + } + $forbidden_array = array_unique($forbidden_array); + } + + if ( empty($forbidden_array) ) + {// at least, the list contains 0 value. This category does not exists so + // where clauses such as "WHERE category_id NOT IN(0)" will always be + // true. + array_push($forbidden_array, 0); + } + + return implode(',', $forbidden_array); +} + +/** + * compute data of categories branches (one branch only) + */ +function compute_branch_cat_data(&$cats, &$list_cat_id, &$level, &$ref_level) +{ + $date = ''; + $count_images = 0; + $count_categories = 0; + do + { + $cat_id = array_pop($list_cat_id); + if (!is_null($cat_id)) + { + // Count images and categories + $cats[$cat_id]['count_images'] += $count_images; + $cats[$cat_id]['count_categories'] += $count_categories; + $count_images = $cats[$cat_id]['count_images']; + $count_categories = $cats[$cat_id]['count_categories'] + 1; + + if ((empty($cats[$cat_id]['max_date_last'])) or ($cats[$cat_id]['max_date_last'] < $date)) + { + $cats[$cat_id]['max_date_last'] = $date; + } + else + { + $date = $cats[$cat_id]['max_date_last']; + } + $ref_level = substr_count($cats[$cat_id]['global_rank'], '.') + 1; + } + else + { + $ref_level = 0; + } + } while ($level <= $ref_level); + + // Last cat updating must be added to list for next branch + if ($ref_level <> 0) + { + array_push($list_cat_id, $cat_id); + } +} + +/** + * compute data of categories branches + */ +function compute_categories_data(&$cats) +{ + $ref_level = 0; + $level = 0; + $list_cat_id = array(); + + foreach ($cats as $id => $category) + { + // Compute + $level = substr_count($category['global_rank'], '.') + 1; + if ($level > $ref_level) + { + array_push($list_cat_id, $id); + } + else + { + compute_branch_cat_data($cats, $list_cat_id, $level, $ref_level); + array_push($list_cat_id, $id); + } + $ref_level = $level; + } + + $level = 1; + compute_branch_cat_data($cats, $list_cat_id, $level, $ref_level); +} + +/** + * get computed array of categories + * + * @param array userdata + * @param int filter_days number of recent days to filter on or null + * @return array + */ +function get_computed_categories($userdata, $filter_days=null) +{ + $query = 'SELECT c.id cat_id, global_rank'; + // Count by date_available to avoid count null + $query .= ', + MAX(date_available) date_last, COUNT(date_available) nb_images +FROM '.CATEGORIES_TABLE.' as c + LEFT JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.category_id = c.id + LEFT JOIN '.IMAGES_TABLE.' AS i + ON ic.image_id = i.id + AND i.level<='.$userdata['level']; + + if ( isset($filter_days) ) + { + $query .= ' AND i.date_available > SUBDATE(CURRENT_DATE,INTERVAL '.$filter_days.' DAY)'; + } + + if ( !empty($userdata['forbidden_categories']) ) + { + $query.= ' + WHERE c.id NOT IN ('.$userdata['forbidden_categories'].')'; + } + + $query.= ' + GROUP BY c.id'; + + $result = pwg_query($query); + + $cats = array(); + while ($row = mysql_fetch_assoc($result)) + { + $row['user_id'] = $userdata['id']; + $row['count_categories'] = 0; + $row['count_images'] = (int)$row['nb_images']; + $row['max_date_last'] = $row['date_last']; + + $cats += array($row['cat_id'] => $row); + } + usort($cats, 'global_rank_compare'); + + compute_categories_data($cats); + + if ( isset($filter_days) ) + { + $cat_tmp = $cats; + $cats = array(); + + foreach ($cat_tmp as $category) + { + if (!empty($category['max_date_last'])) + { + // Re-init counters + $category['count_categories'] = 0; + $category['count_images'] = (int)$category['nb_images']; + // Keep category + $cats[$category['cat_id']] = $category; + } + } + // Compute a second time + compute_categories_data($cats); + } + return $cats; +} + +/** + * update data of user_cache_categories + * + * @param array userdata + * @return null + */ +function update_user_cache_categories($userdata) +{ + // delete user cache + $query = ' +DELETE FROM '.USER_CACHE_CATEGORIES_TABLE.' + WHERE user_id = '.$userdata['id'].' +;'; + pwg_query($query); + + $cats = get_computed_categories($userdata, null); + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + mass_inserts + ( + USER_CACHE_CATEGORIES_TABLE, + array + ( + 'user_id', 'cat_id', + 'date_last', 'max_date_last', 'nb_images', 'count_images', 'count_categories' + ), + $cats + ); +} + +/** + * returns the username corresponding to the given user identifier if exists + * + * @param int user_id + * @return mixed + */ +function get_username($user_id) +{ + global $conf; + + $query = ' +SELECT '.$conf['user_fields']['username'].' + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['id'].' = '.intval($user_id).' +;'; + $result = pwg_query($query); + if (mysql_num_rows($result) > 0) + { + list($username) = mysql_fetch_row($result); + } + else + { + return false; + } + + return $username; +} + +/** + * returns user identifier thanks to his name, false if not found + * + * @param string username + * @param int user identifier + */ +function get_userid($username) +{ + global $conf; + + $username = mysql_escape_string($username); + + $query = ' +SELECT '.$conf['user_fields']['id'].' + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['username'].' = \''.$username.'\' +;'; + $result = pwg_query($query); + + if (mysql_num_rows($result) == 0) + { + return false; + } + else + { + list($user_id) = mysql_fetch_row($result); + return $user_id; + } +} + +/** + * search an available feed_id + * + * @return string feed identifier + */ +function find_available_feed_id() +{ + while (true) + { + $key = generate_key(50); + $query = ' +SELECT COUNT(*) + FROM '.USER_FEED_TABLE.' + WHERE id = \''.$key.'\' +;'; + list($count) = mysql_fetch_row(pwg_query($query)); + if (0 == $count) + { + return $key; + } + } +} + +/* + * Returns a array with default user value + * + * @param convert_str allows to convert string value if necessary + */ +function get_default_user_info($convert_str = true) +{ + global $page, $conf; + + if (!isset($page['cache_default_user'])) + { + $query = 'select * from '.USER_INFOS_TABLE. + ' where user_id = '.$conf['default_user_id'].';'; + + $result = pwg_query($query); + $page['cache_default_user'] = mysql_fetch_assoc($result); + + if ($page['cache_default_user'] !== false) + { + unset($page['cache_default_user']['user_id']); + unset($page['cache_default_user']['status']); + unset($page['cache_default_user']['registration_date']); + } + } + + if (is_array($page['cache_default_user']) and $convert_str) + { + $default_user = array(); + foreach ($page['cache_default_user'] as $name => $value) + { + // If the field is true or false, the variable is transformed into a + // boolean value. + if ($value == 'true' or $value == 'false') + { + $default_user[$name] = get_boolean($value); + } + else + { + $default_user[$name] = $value; + } + } + return $default_user; + } + else + { + return $page['cache_default_user']; + } +} + +/* + * Returns a default user value + * + * @param value_name: name of value + * @param sos_value: value used if don't exist value + */ +function get_default_user_value($value_name, $sos_value) +{ + $default_user = get_default_user_info(true); + if ($default_user === false or !isset($default_user[$value_name])) + { + return $sos_value; + } + else + { + return $default_user[$value_name]; + } +} + +/* + * Returns the default template value + * + */ +function get_default_template() +{ + return get_default_user_value('template', PHPWG_DEFAULT_TEMPLATE); +} + +/* + * Returns the default language value + * + */ +function get_default_language() +{ + return get_default_user_value('language', PHPWG_DEFAULT_LANGUAGE); +} + +/** + * add user informations based on default values + * + * @param int user_id / array of user_if + * @param array of values used to override default user values + */ +function create_user_infos($arg_id, $override_values = null) +{ + global $conf; + + if (is_array($arg_id)) + { + $user_ids = $arg_id; + } + else + { + $user_ids = array(); + if (is_numeric($arg_id)) + { + $user_ids[] = $arg_id; + } + } + + if (!empty($user_ids)) + { + $inserts = array(); + list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();')); + + $default_user = get_default_user_info(false); + if ($default_user === false) + { + // Default on structure are used + $default_user = array(); + } + + if (!is_null($override_values)) + { + $default_user = array_merge($default_user, $override_values); + } + + foreach ($user_ids as $user_id) + { + $level= isset($default_user['level']) ? $default_user['level'] : 0; + if ($user_id == $conf['webmaster_id']) + { + $status = 'webmaster'; + $level = max( $conf['available_permission_levels'] ); + } + else if (($user_id == $conf['guest_id']) or + ($user_id == $conf['default_user_id'])) + { + $status = 'guest'; + } + else + { + $status = 'normal'; + } + + $insert = array_merge( + $default_user, + array( + 'user_id' => $user_id, + 'status' => $status, + 'registration_date' => $dbnow, + 'level' => $level + )); + + array_push($inserts, $insert); + } + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + mass_inserts(USER_INFOS_TABLE, array_keys($inserts[0]), $inserts); + + } +} + +/** + * returns the groupname corresponding to the given group identifier if + * exists + * + * @param int group_id + * @return mixed + */ +function get_groupname($group_id) +{ + $query = ' +SELECT name + FROM '.GROUPS_TABLE.' + WHERE id = '.intval($group_id).' +;'; + $result = pwg_query($query); + if (mysql_num_rows($result) > 0) + { + list($groupname) = mysql_fetch_row($result); + } + else + { + return false; + } + + return $groupname; +} + + +/** + * returns the auto login key or false on error + * @param int user_id + * @param string [out] username +*/ +function calculate_auto_login_key($user_id, &$username) +{ + global $conf; + $query = ' +SELECT '.$conf['user_fields']['username'].' AS username + , '.$conf['user_fields']['password'].' AS password +FROM '.USERS_TABLE.' +WHERE '.$conf['user_fields']['id'].' = '.$user_id; + $result = pwg_query($query); + if (mysql_num_rows($result) > 0) + { + $row = mysql_fetch_assoc($result); + $username = $row['username']; + $data = $row['username'].$row['password']; + $key = base64_encode( + pack('H*', sha1($data)) + .hash_hmac('md5', $data, $conf['secret_key'],true) + ); + return $key; + } + return false; +} + +/* + * Performs all required actions for user login + * @param int user_id + * @param bool remember_me + * @return void +*/ +function log_user($user_id, $remember_me) +{ + global $conf, $user; + + if ($remember_me and $conf['authorize_remembering']) + { + $key = calculate_auto_login_key($user_id, $username); + if ($key!==false) + { + $cookie = array('id' => (int)$user_id, 'key' => $key); + setcookie($conf['remember_me_name'], + serialize($cookie), + time()+$conf['remember_me_length'], + cookie_path() + ); + } + } + else + { // make sure we clean any remember me ... + setcookie($conf['remember_me_name'], '', 0, cookie_path()); + } + if ( session_id()!="" ) + { // we regenerate the session for security reasons + // see http://www.acros.si/papers/session_fixation.pdf + session_regenerate_id(); + } + else + { + session_start(); + } + $_SESSION['pwg_uid'] = (int)$user_id; + + $user['id'] = $_SESSION['pwg_uid']; +} + +/* + * Performs auto-connexion when cookie remember_me exists + * @return true/false +*/ +function auto_login() { + global $conf; + + if ( isset( $_COOKIE[$conf['remember_me_name']] ) ) + { + $cookie = unserialize(stripslashes($_COOKIE[$conf['remember_me_name']])); + if ($cookie!==false and is_numeric(@$cookie['id']) ) + { + $key = calculate_auto_login_key( $cookie['id'], $username ); + if ($key!==false and $key===$cookie['key']) + { + log_user($cookie['id'], true); + trigger_action('login_success', $username); + return true; + } + } + setcookie($conf['remember_me_name'], '', 0, cookie_path()); + } + return false; +} + +/** + * Tries to login a user given username and password (must be MySql escaped) + * return true on success + */ +function try_log_user($username, $password, $remember_me) +{ + global $conf; + // retrieving the encrypted password of the login submitted + $query = ' +SELECT '.$conf['user_fields']['id'].' AS id, + '.$conf['user_fields']['password'].' AS password + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['username'].' = \''.$username.'\' +;'; + $row = mysql_fetch_assoc(pwg_query($query)); + if ($row['password'] == $conf['pass_convert']($password)) + { + log_user($row['id'], $remember_me); + trigger_action('login_success', $username); + return true; + } + trigger_action('login_failure', $username); + return false; +} + +/* + * Return user status used in this library + * @return string +*/ +function get_user_status($user_status) +{ + global $user; + + if (empty($user_status)) + { + if (isset($user['status'])) + { + $user_status = $user['status']; + } + else + { + // swicth to default value + $user_status = ''; + } + } + return $user_status; +} + +/* + * Return access_type definition of user + * Test does with user status + * @return bool +*/ +function get_access_type_status($user_status='') +{ + global $conf; + + switch (get_user_status($user_status)) + { + case 'guest': + { + $access_type_status = + ($conf['guest_access'] ? ACCESS_GUEST : ACCESS_FREE); + break; + } + case 'generic': + { + $access_type_status = ACCESS_GUEST; + break; + } + case 'normal': + { + $access_type_status = ACCESS_CLASSIC; + break; + } + case 'admin': + { + $access_type_status = ACCESS_ADMINISTRATOR; + break; + } + case 'webmaster': + { + $access_type_status = ACCESS_WEBMASTER; + break; + } + default: + { + $access_type_status = ACCESS_FREE; + break; + } + } + + return $access_type_status; +} + +/* + * Return if user have access to access_type definition + * Test does with user status + * @return bool +*/ +function is_autorize_status($access_type, $user_status = '') +{ + return (get_access_type_status($user_status) >= $access_type); +} + +/* + * Check if user have access to access_type definition + * Stop action if there are not access + * Test does with user status + * @return none +*/ +function check_status($access_type, $user_status = '') +{ + if (!is_autorize_status($access_type, $user_status)) + { + access_denied(); + } +} + +/* + * Return if user is generic + * @return bool +*/ + function is_generic($user_status = '') +{ + return get_user_status($user_status) == 'generic'; +} + +/* + * Return if user is only a guest + * @return bool +*/ + function is_a_guest($user_status = '') +{ + return get_user_status($user_status) == 'guest'; +} + +/* + * Return if user is, at least, a classic user + * @return bool +*/ + function is_classic_user($user_status = '') +{ + return is_autorize_status(ACCESS_CLASSIC, $user_status); +} + +/* + * Return if user is, at least, an administrator + * @return bool +*/ + function is_admin($user_status = '') +{ + return is_autorize_status(ACCESS_ADMINISTRATOR, $user_status); +} + +/* + * Return if current user is an adviser + * @return bool +*/ +function is_adviser() +{ + global $user; + + return ($user['adviser'] == 'true'); +} + +/* + * Return mail address as display text + * @return string +*/ +function get_email_address_as_display_text($email_address) +{ + global $conf; + + if (!isset($email_address) or (trim($email_address) == '')) + { + return ''; + } + else + { + if (defined('IN_ADMIN') and is_adviser()) + { + return 'adviser.mode@'.$_SERVER['SERVER_NAME']; + } + else + { + return $email_address; + } + } +} + +/* + * Compute sql where condition with restrict and filter data. "FandF" means + * Forbidden and Filters. + * + * @param array condition_fields: read function body + * @param string prefix_condition: prefixes sql if condition is not empty + * @param boolean force_one_condition: use at least "1 = 1" + * + * @return string sql where/conditions + */ +function get_sql_condition_FandF( + $condition_fields, + $prefix_condition = null, + $force_one_condition = false + ) +{ + global $user, $filter; + + $sql_list = array(); + + foreach ($condition_fields as $condition => $field_name) + { + switch($condition) + { + case 'forbidden_categories': + { + if (!empty($user['forbidden_categories'])) + { + $sql_list[] = + $field_name.' NOT IN ('.$user['forbidden_categories'].')'; + } + break; + } + case 'visible_categories': + { + if (!empty($filter['visible_categories'])) + { + $sql_list[] = + $field_name.' IN ('.$filter['visible_categories'].')'; + } + break; + } + case 'visible_images': + if (!empty($filter['visible_images'])) + { + $sql_list[] = + $field_name.' IN ('.$filter['visible_images'].')'; + } + // note there is no break - visible include forbidden + case 'forbidden_images': + if ( + !empty($user['image_access_list']) + or $user['image_access_type']!='NOT IN' + ) + { + $table_prefix=null; + if ($field_name=='id') + { + $table_prefix = ''; + } + elseif ($field_name=='i.id') + { + $table_prefix = 'i.'; + } + if ( isset($table_prefix) ) + { + $sql_list[]=$table_prefix.'level<='.$user['level']; + } + else + { + $sql_list[]=$field_name.' '.$user['image_access_type'] + .' ('.$user['image_access_list'].')'; + } + } + break; + default: + { + die('Unknow condition'); + break; + } + } + } + + if (count($sql_list) > 0) + { + $sql = '('.implode(' AND ', $sql_list).')'; + } + else + { + if ($force_one_condition) + { + $sql = '1 = 1'; + } + else + { + $sql = ''; + } + } + + if (isset($prefix_condition) and !empty($sql)) + { + $sql = $prefix_condition.' '.$sql; + } + + return $sql; +} + +?> \ No newline at end of file diff --git a/BSF/include/functions_xml.inc.php b/BSF/include/functions_xml.inc.php new file mode 100644 index 000000000..1a849d434 --- /dev/null +++ b/BSF/include/functions_xml.inc.php @@ -0,0 +1,141 @@ +Joe
    " ) returns "Joe" +// +// It also works with strings containing themself sub-tags : +// JeanBillie -> +// JeanBillie +function getContent( $element ) +{ + // deleting start of the tag + $content = preg_replace( '/^<[^>]+>/', '', $element ); + // deleting end of the tag + $content = preg_replace( '/<\/[^>]+>$/', '', $content ); + // replacing multiple instance of space character + $content = preg_replace( '/\s+/', ' ', $content ); + + return $content; +} + +// The function get Attribute returns the value corresponding to the +// attribute $attribute for the tag $element. +function getAttribute( $element, $attribute ) +{ +// echo htmlentities($element).'

    '; + $regex = '/^<\w+[^>]*\b'.$attribute.'\s*=\s*"('.VAL_REG.')"/i'; + if ( preg_match( $regex, $element, $out ) ) + { + return html_entity_decode($out[1], ENT_QUOTES); + } + else return ''; +} + +// The function encode Attribute returns the xml attribute $attribute="$value" +function encodeAttribute( $attribute, $value ) +{ + return $attribute.'="'.htmlspecialchars($value, ENT_QUOTES).'" '; +} + +// The function getChild returns the first child +// exemple : getChild( "XXXYYY
    ", "tr" ) +// returns "XXX" +function getChild( $document, $node ) +{ + $regex = '/<'.$node.'(\s+'.ATT_REG.'="'.VAL_REG.'")*'; + $regex.= '(\s*\/>|>.*<\/'.$node.'>)/U'; + + if + ( + preg_match( $regex, $document, $out ) + or + preg_last_error() == PREG_NO_ERROR + ) + { + return $out[0]; + } + else + { + die('getChild: error ['.preg_last_error().'] with preg_match function'); + } +} + +// getChildren returns a list of the children identified by the $node +// example : +// getChild( "XXXYYY
    ", "tr" ) +// returns an array with : +// $array[0] equals "XXX" +// $array[1] equals "YYY" +function getChildren( $document, $node ) +{ + $regex = '/<'.$node.'(\s+'.ATT_REG.'="'.VAL_REG.'")*'; + $regex.= '(\s*\/>|>.*<\/'.$node.'>)/U'; + + if + ( + preg_match_all( $regex, $document, $out ) + or + preg_last_error() == PREG_NO_ERROR + ) + { + return $out[0]; + } + else + { + die('getChild: error ['.preg_last_error().'] with preg_match_all function'); + } +} + +// get_CodeXML places the content of a text file in a PHP variable and +// return it. If the file can't be opened, returns false. +function getXmlCode( $filename ) +{ + if (function_exists('ini_set')) + { + // limit must be growed with php5 and "big" listing file + ini_set("pcre.backtrack_limit", pow(2, 32)); + } + + $file = fopen( $filename, 'r' ); + if ( !$file ) + { + return false; + } + + $xml_content = ''; + while ( !feof( $file ) ) + { + $xml_content .= fgets( $file, 1024 ); + } + fclose( $file ); + $xml_content = str_replace( "\n", '', $xml_content ); + $xml_content = str_replace( "\t", '', $xml_content ); + + return $xml_content; +} +?> diff --git a/BSF/include/index.php b/BSF/include/index.php new file mode 100644 index 000000000..c15b15795 --- /dev/null +++ b/BSF/include/index.php @@ -0,0 +1,30 @@ + diff --git a/BSF/include/menubar.inc.php b/BSF/include/menubar.inc.php new file mode 100644 index 000000000..03e941226 --- /dev/null +++ b/BSF/include/menubar.inc.php @@ -0,0 +1,311 @@ +set_filenames( + array( + 'menubar' => 'menubar.tpl', + ) + ); + +trigger_action('loc_begin_menubar'); + +$template->assign( + array( + 'NB_PICTURE' => $user['nb_total_images'], + 'MENU_CATEGORIES_CONTENT' => get_categories_menu(), + 'U_CATEGORIES' => make_index_url(array('section' => 'categories')), + 'U_LOST_PASSWORD' => get_root_url().'password.php', + 'U_UPLOAD' => get_upload_menu_link() + ) + ); + +//-------------------------------------------------------------- external links +foreach ($conf['links'] as $url => $url_data) +{ + if (!is_array($url_data)) + { + $url_data = array('label' => $url_data); + } + + if + ( + (!isset($url_data['eval_visible'])) + or + (eval($url_data['eval_visible'])) + ) + { + $tpl_var = array( + 'URL' => $url, + 'LABEL' => $url_data['label'] + ); + + if (!isset($url_data['new_window']) or $url_data['new_window']) + { + $tpl_var['new_window'] = + array( + 'NAME' => (isset($url_data['nw_name']) ? $url_data['nw_name'] : ''), + 'FEATURES' => (isset($url_data['nw_features']) ? $url_data['nw_features'] : '') + ); + } + $template->append('links', $tpl_var); + } +} + +//------------------------------------------------------------------------ filter +if (!empty($conf['filter_pages']) and get_filter_page_value('used')) +{ + if ($filter['enabled']) + { + $template->assign( + 'U_STOP_FILTER', + add_url_params(make_index_url(array()), array('filter' => 'stop')) + ); + } + else + { + $template->assign( + 'U_START_FILTER', + add_url_params(make_index_url(array()), array('filter' => 'start-recent-'.$user['recent_period'])) + ); + } +} + +//------------------------------------------------------------------------ tags +if ('tags' == @$page['section']) +{ + // display tags associated to currently tagged items, less current tags + $tags = array(); + if ( !empty($page['items']) ) + { + $tags = get_common_tags($page['items'], + $conf['menubar_tag_cloud_items_number'], $page['tag_ids']); + } + + $tags = add_level_to_tags($tags); + + foreach ($tags as $tag) + { + $template->append( + 'related_tags', + array( + 'U_TAG' => make_index_url( + array( + 'tags' => array($tag) + ) + ), + + 'NAME' => $tag['name'], + + 'CLASS' => 'tagLevel'.$tag['level'], + + 'add' => array( + + 'URL' => make_index_url( + array( + 'tags' => array_merge( + $page['tags'], + array($tag) + ) + ) + ), + 'COUNTER' => $tag['counter'], + ) + ) + ); + } +} +//---------------------------------------------------------- special categories +// favorites categories +if ( !is_a_guest() ) +{ + $template->append( + 'special_categories', + array( + 'URL' => make_index_url(array('section' => 'favorites')), + 'TITLE' => l10n('favorite_cat_hint'), + 'NAME' => l10n('favorite_cat') + )); +} +// most visited +$template->append( + 'special_categories', + array( + 'URL' => make_index_url(array('section' => 'most_visited')), + 'TITLE' => l10n('most_visited_cat_hint'), + 'NAME' => l10n('most_visited_cat') + )); +// best rated +if ($conf['rate']) +{ + $template->append( + 'special_categories', + array( + 'URL' => make_index_url(array('section' => 'best_rated')), + 'TITLE' => l10n('best_rated_cat_hint'), + 'NAME' => l10n('best_rated_cat') + ) + ); +} +// random +$template->append( + 'special_categories', + array( + 'URL' => get_root_url().'random.php', + 'TITLE' => l10n('random_cat_hint'), + 'NAME' => l10n('random_cat'), + 'REL'=> 'rel="nofollow"' + )); + +// recent pics +$template->append( + 'special_categories', + array( + 'URL' => make_index_url(array('section' => 'recent_pics')), + 'TITLE' => l10n('recent_pics_cat_hint'), + 'NAME' => l10n('recent_pics_cat'), + )); +// recent cats +$template->append( + 'special_categories', + array( + 'URL' => make_index_url(array('section' => 'recent_cats')), + 'TITLE' => l10n('recent_cats_cat_hint'), + 'NAME' => l10n('recent_cats_cat'), + )); + +// calendar +$template->append( + 'special_categories', + array( + 'URL' => + make_index_url( + array( + 'chronology_field' => ($conf['calendar_datefield']=='date_available' + ? 'posted' : 'created'), + 'chronology_style'=> 'monthly', + 'chronology_view' => 'calendar' + ) + ), + 'TITLE' => l10n('calendar_hint'), + 'NAME' => l10n('calendar'), + 'REL'=> 'rel="nofollow"' + ) + ); +//--------------------------------------------------------------------- summary + +if (is_a_guest()) +{ + $template->assign( + array( + 'U_IDENTIFY' => get_root_url().'identification.php', + 'AUTHORIZE_REMEMBERING' => $conf['authorize_remembering'] + ) + ); + + if ($conf['allow_user_registration']) + { + $template->assign( 'U_REGISTER', get_root_url().'register.php'); + } +} +else +{ + $template->assign('USERNAME', $user['username']); + + if (is_autorize_status(ACCESS_CLASSIC)) + { + $template->assign('U_PROFILE', get_root_url().'profile.php'); + } + + // the logout link has no meaning with Apache authentication : it is not + // possible to logout with this kind of authentication. + if (!$conf['apache_authentication']) + { + $template->assign('U_LOGOUT', get_root_url().'?act=logout'); + } + + if (is_admin()) + { + $template->assign('U_ADMIN', get_root_url().'admin.php'); + } +} + +// tags link +$template->append( + 'summaries', + array( + 'TITLE' => l10n('See available tags'), + 'NAME' => l10n('Tags'), + 'U_SUMMARY'=> get_root_url().'tags.php', + ) + ); + +// search link +$template->append( + 'summaries', + array( + 'TITLE'=>l10n('hint_search'), + 'NAME'=>l10n('Search'), + 'U_SUMMARY'=> get_root_url().'search.php', + 'REL'=> 'rel="search"' + ) + ); + +// comments link +$template->append( + 'summaries', + array( + 'TITLE'=>l10n('hint_comments'), + 'NAME'=>l10n('comments'), + 'U_SUMMARY'=> get_root_url().'comments.php', + ) + ); + +// about link +$template->append( + 'summaries', + array( + 'TITLE' => l10n('about_page_title'), + 'NAME' => l10n('About'), + 'U_SUMMARY' => get_root_url().'about.php', + ) + ); + +// notification +$template->append( + 'summaries', + array( + 'TITLE'=>l10n('RSS feed'), + 'NAME'=>l10n('Notification'), + 'U_SUMMARY'=> get_root_url().'notification.php', + 'REL'=> 'rel="nofollow"' + ) + ); + +trigger_action('loc_end_menubar'); +$template->assign_var_from_handle('MENUBAR', 'menubar'); + +?> diff --git a/BSF/include/page_header.php b/BSF/include/page_header.php new file mode 100644 index 000000000..102e2bdd8 --- /dev/null +++ b/BSF/include/page_header.php @@ -0,0 +1,90 @@ +set_filenames(array('header'=>'header.tpl')); + +trigger_action('loc_begin_page_header'); + +$template->assign( + array( + 'GALLERY_TITLE' => + isset($page['gallery_title']) ? + $page['gallery_title'] : $conf['gallery_title'], + + 'PAGE_BANNER' => + trigger_event('render_page_banner', + isset($page['page_banner']) ? + $page['page_banner'] : $conf['page_banner']), + + 'BODY_ID' => + isset($page['body_id']) ? + $page['body_id'] : '', + + 'CONTENT_ENCODING' => get_pwg_charset(), + 'PAGE_TITLE' => strip_tags($title), + 'LANG'=>$lang_info['code'], + 'DIR'=>$lang_info['direction'], + + 'U_HOME' => make_index_url(), + )); + + +// Header notes +if ( !empty($header_notes) ) +{ + $template->assign('header_notes',$header_notes); +} + +if ( !empty($page['meta_robots']) ) +{ + $template->append('head_elements', + '' + ); +} + +// refresh +if ( isset( $refresh ) and intval($refresh) >= 0 + and isset( $url_link ) and isset( $redirect_msg ) ) +{ + $template->assign( + array( + 'REDIRECT_MSG' => $redirect_msg, + 'page_refresh' => array( + 'TIME' => $refresh, + 'U_REFRESH' => $url_link + ) + )); +} + +trigger_action('loc_end_page_header'); + +header('Content-Type: text/html; charset='.get_pwg_charset()); +$template->parse('header'); + +trigger_action('loc_after_page_header'); +?> \ No newline at end of file diff --git a/BSF/include/page_tail.php b/BSF/include/page_tail.php new file mode 100644 index 000000000..670d23a2e --- /dev/null +++ b/BSF/include/page_tail.php @@ -0,0 +1,74 @@ +set_filenames(array('tail'=>'footer.tpl')); + +trigger_action('loc_begin_page_tail'); + +$template->assign( + array( + 'VERSION' => $conf['show_version'] ? PHPWG_VERSION : '', + 'PHPWG_URL' => PHPWG_URL, + )); + +//--------------------------------------------------------------------- contact + +if (!is_a_guest()) +{ + $template->assign( + 'CONTACT_MAIL', get_webmaster_mail_address() + ); +} + +//------------------------------------------------------------- generation time +$debug_vars = array(); + +if ($conf['show_queries']) +{ + $debug_vars = array_merge($debug_vars, array('QUERIES_LIST' => $debug) ); +} + +if ($conf['show_gt']) +{ + if (!isset($page['count_queries'])) + { + $page['count_queries'] = 0; + $page['queries_time'] = 0; + } + $time = get_elapsed_time($t2, get_moment()); + + $debug_vars = array_merge($debug_vars, + array('TIME' => $time, + 'NB_QUERIES' => $page['count_queries'], + 'SQL_TIME' => number_format($page['queries_time'],3,'.',' ').' s') + ); +} + +$template->assign('debug', $debug_vars ); + +trigger_action('loc_end_page_tail'); +// +// Generate the page +// +$template->parse('tail'); +$template->p(); +?> \ No newline at end of file diff --git a/BSF/include/php_compat/array_intersect_key.php b/BSF/include/php_compat/array_intersect_key.php new file mode 100644 index 000000000..748b8f6f1 --- /dev/null +++ b/BSF/include/php_compat/array_intersect_key.php @@ -0,0 +1,35 @@ += 5.1.0RC1 +function array_intersect_key() +{ + $args = func_get_args(); + if (count($args) < 2) { + trigger_error('Wrong parameter count for array_intersect_key()', E_USER_WARNING); + return; + } + + // Check arrays + $array_count = count($args); + for ($i = 0; $i !== $array_count; $i++) { + if (!is_array($args[$i])) { + trigger_error('array_intersect_key() Argument #' . ($i + 1) . ' is not an array', E_USER_WARNING); + return; + } + } + + // Compare entries + $result = array(); + foreach ($args[0] as $key1 => $value1) { + for ($i = 1; $i !== $array_count; $i++) { + foreach ($args[$i] as $key2 => $value2) { + if ((string) $key1 === (string) $key2) { + $result[$key1] = $value1; + } + } + } + } + + return $result; +} +?> \ No newline at end of file diff --git a/BSF/include/php_compat/file_put_contents.php b/BSF/include/php_compat/file_put_contents.php new file mode 100644 index 000000000..679d9c984 --- /dev/null +++ b/BSF/include/php_compat/file_put_contents.php @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/BSF/include/php_compat/hash_hmac.php b/BSF/include/php_compat/hash_hmac.php new file mode 100644 index 000000000..5f05e370c --- /dev/null +++ b/BSF/include/php_compat/hash_hmac.php @@ -0,0 +1,25 @@ +'H32','sha1'=>'H40'); + if ( !isset($p[$algo]) or !function_exists($algo) ) + { + $algo = 'md5'; + } + if(strlen($key)>64) $key=pack($p[$algo],$algo($key)); + if(strlen($key)<64) $key=str_pad($key,64,chr(0)); + + $ipad=substr($key,0,64) ^ str_repeat(chr(0x36),64); + $opad=substr($key,0,64) ^ str_repeat(chr(0x5C),64); + + $ret = $algo($opad.pack($p[$algo],$algo($ipad.$data))); + if ($raw_output) + { + $ret = pack('H*', $ret); + } + return $ret; +} +?> \ No newline at end of file diff --git a/BSF/include/php_compat/index.php b/BSF/include/php_compat/index.php new file mode 100644 index 000000000..c15b15795 --- /dev/null +++ b/BSF/include/php_compat/index.php @@ -0,0 +1,30 @@ + diff --git a/BSF/include/php_compat/preg_last_error.php b/BSF/include/php_compat/preg_last_error.php new file mode 100644 index 000000000..c564aeba9 --- /dev/null +++ b/BSF/include/php_compat/preg_last_error.php @@ -0,0 +1,41 @@ += 5.2.0 +if (!defined('PREG_NO_ERROR')) + define('PREG_NO_ERROR', 0); +if (!defined('PREG_INTERNAL_ERROR')) + define('PREG_INTERNAL_ERROR', 1); +if (!defined('PREG_BACKTRACK_LIMIT_ERROR')) + define('PREG_BACKTRACK_LIMIT_ERROR', 2); +if (!defined('PREG_RECURSION_LIMIT_ERROR')) + define('PREG_RECURSION_LIMIT_ERROR', 3); +if (!defined('PREG_BAD_UTF8_ERROR')) + define('PREG_BAD_UTF8_ERROR', 4); + +function preg_last_error() +{ + return PREG_NO_ERROR; +} +?> \ No newline at end of file diff --git a/BSF/include/picture_comment.inc.php b/BSF/include/picture_comment.inc.php new file mode 100644 index 000000000..ad0438d96 --- /dev/null +++ b/BSF/include/picture_comment.inc.php @@ -0,0 +1,183 @@ + trim( stripslashes(@$_POST['author']) ), + 'content' => trim( stripslashes($_POST['content']) ), + 'image_id' => $page['image_id'], + ); + + include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php'); + + $comment_action = insert_user_comment($comm, @$_POST['key'], $infos ); + + switch ($comment_action) + { + case 'moderate': + array_push( $infos, l10n('comment_to_validate') ); + case 'validate': + array_push( $infos, l10n('comment_added')); + break; + case 'reject': + set_status_header(403); + array_push($infos, l10n('comment_not_added') ); + break; + default: + trigger_error('Invalid comment action '.$comment_action, E_USER_WARNING); + } + + $template->assign( + ($comment_action=='reject') ? 'errors' : 'infos', + $infos + ); + + // allow plugins to notify what's going on + trigger_action( 'user_comment_insertion', + array_merge($comm, array('action'=>$comment_action) ) + ); +} +elseif ( isset($_POST['content']) ) +{ + set_status_header(403); + die('ugly spammer'); +} + +if ($page['show_comments']) +{ + // number of comment for this picture + $query = 'SELECT COUNT(*) AS nb_comments'; + $query.= ' FROM '.COMMENTS_TABLE.' WHERE image_id = '.$page['image_id']; + $query.= " AND validated = 'true'"; + $query.= ';'; + $row = mysql_fetch_array( pwg_query( $query ) ); + + // navigation bar creation + if (!isset($page['start'])) + { + $page['start'] = 0; + } + + $navigation_bar = create_navigation_bar( + duplicate_picture_url(array(), array('start')), + $row['nb_comments'], + $page['start'], + $conf['nb_comment_page'], + true // We want a clean URL + ); + + $template->assign( + array( + 'COMMENT_COUNT' => $row['nb_comments'], + 'COMMENT_NAV_BAR' => $navigation_bar, + ) + ); + + if ($row['nb_comments'] > 0) + { + $query = ' +SELECT id,author,date,image_id,content + FROM '.COMMENTS_TABLE.' + WHERE image_id = '.$page['image_id'].' + AND validated = \'true\' + ORDER BY date ASC + LIMIT '.$page['start'].', '.$conf['nb_comment_page'].' +;'; + $result = pwg_query( $query ); + + while ($row = mysql_fetch_array($result)) + { + $tpl_comment = + array( + 'AUTHOR' => trigger_event('render_comment_author', + empty($row['author']) + ? l10n('guest') + : $row['author']), + + 'DATE' => format_date( + $row['date'], + 'mysql_datetime', + true), + + 'CONTENT' => trigger_event('render_comment_content',$row['content']), + ); + + if (is_admin()) + { + $tpl_comment['U_DELETE'] = + add_url_params( + $url_self, + array( + 'action'=>'delete_comment', + 'comment_to_delete'=>$row['id'] + ) + ); + } + $template->append('comments', $tpl_comment); + } + } + + if (!is_a_guest() + or (is_a_guest() and $conf['comments_forall'])) + { + include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php'); + $key = get_comment_post_key($page['image_id']); + $content = ''; + if ('reject'===@$comment_action) + { + $content = htmlspecialchars($comm['content']); + } + $template->assign('comment_add', + array( + 'F_ACTION' => $url_self, + 'KEY' => $key, + 'CONTENT' => $content, + 'SHOW_AUTHOR' => !is_classic_user() + )); + } +} + +?> \ No newline at end of file diff --git a/BSF/include/picture_metadata.inc.php b/BSF/include/picture_metadata.inc.php new file mode 100644 index 000000000..bc6410897 --- /dev/null +++ b/BSF/include/picture_metadata.inc.php @@ -0,0 +1,99 @@ + 'EXIF Metadata', + 'lines' => array(), + ); + + foreach ($conf['show_exif_fields'] as $field) + { + if (strpos($field, ';') === false) + { + if (isset($exif[$field])) + { + $key = $field; + if (isset($lang['exif_field_'.$field])) + { + $key = $lang['exif_field_'.$field]; + } + $tpl_meta['lines'][$key] = $exif[$field]; + } + } + else + { + $tokens = explode(';', $field); + if (isset($exif[$tokens[0]][$tokens[1]])) + { + $key = $tokens[1]; + if (isset($lang['exif_field_'.$tokens[1]])) + { + $key = $lang['exif_field_'.$tokens[1]]; + } + $tpl_meta['lines'][$key] = $exif[$tokens[0]][$tokens[1]]; + } + } + } + $template->append('metadata', $tpl_meta); + } +} + +if ($conf['show_iptc']) +{ + $iptc = get_iptc_data($picture['current']['image_path'], + $conf['show_iptc_mapping']); + + if (count($iptc) > 0) + { + $tpl_meta = array( + 'TITLE' => 'IPTC Metadata', + 'lines' => array(), + ); + + foreach ($iptc as $field => $value) + { + $key = $field; + if (isset($lang[$field])) + { + $key = $lang[$field]; + } + $tpl_meta['lines'][$key] = $value; + } + $template->append('metadata', $tpl_meta); + } +} + + +?> diff --git a/BSF/include/picture_rate.inc.php b/BSF/include/picture_rate.inc.php new file mode 100644 index 000000000..aa1071452 --- /dev/null +++ b/BSF/include/picture_rate.inc.php @@ -0,0 +1,91 @@ + no rate -> no need to query db + $row = array( 'count'=>0, 'average'=>NULL, 'std'=>NULL ); + } + $template->assign('rate_summary', $row); + + $user_rate = null; + if ($conf['rate_anonymous'] or is_autorize_status(ACCESS_CLASSIC) ) + { + if ($row['count']>0) + { + $query = 'SELECT rate + FROM '.RATE_TABLE.' + WHERE element_id = '.$page['image_id'] . ' + AND user_id = '.$user['id'] ; + + if ( !is_autorize_status(ACCESS_CLASSIC) ) + { + $ip_components = explode('.', $_SERVER['REMOTE_ADDR']); + if ( count($ip_components)>3 ) + { + array_pop($ip_components); + } + $anonymous_id = implode ('.', $ip_components); + $query .= ' AND anonymous_id = \''.$anonymous_id . '\''; + } + + $result = pwg_query($query); + if (mysql_num_rows($result) > 0) + { + $row = mysql_fetch_array($result); + $user_rate = $row['rate']; + } + } + + $template->assign( + 'rating', + array( + 'F_ACTION' => add_url_params( + $url_self, + array('action'=>'rate') + ), + 'USER_RATE'=> $user_rate, + 'marks' => $conf['rate_items'] + ) + ); + } +} + +?> \ No newline at end of file diff --git a/BSF/include/section_init.inc.php b/BSF/include/section_init.inc.php new file mode 100644 index 000000000..ffd6cac1a --- /dev/null +++ b/BSF/include/section_init.inc.php @@ -0,0 +1,620 @@ + 'categories', +// 'category' => array('id'=>12, ...), +// 'start' => 24 +// ); + +$page['items'] = array(); + +// some ISPs set PATH_INFO to empty string or to SCRIPT_FILENAME while in the +// default apache implementation it is not set +if ( $conf['question_mark_in_urls']==false and + isset($_SERVER["PATH_INFO"]) and !empty($_SERVER["PATH_INFO"]) ) +{ + $rewritten = $_SERVER["PATH_INFO"]; + $rewritten = str_replace('//', '/', $rewritten); + $path_count = count( explode('/', $rewritten) ); + $page['root_path'] = PHPWG_ROOT_PATH.str_repeat('../', $path_count-1); +} +else +{ + $rewritten = ''; + foreach (array_keys($_GET) as $keynum => $key) + { + $rewritten = $key; + break; + } + $page['root_path'] = PHPWG_ROOT_PATH; +} + +// deleting first "/" if displayed +$tokens = explode( + '/', + preg_replace('#^/#', '', $rewritten) + ); +// $tokens = array( +// 0 => category, +// 1 => 12-foo, +// 2 => start-24 +// ); + +$next_token = 0; +if (script_basename() == 'picture') // basename without file extention +{ // the first token must be the identifier for the picture + if ( isset($_GET['image_id']) + and isset($_GET['cat']) and is_numeric($_GET['cat']) ) + {// url compatibility with versions below 1.6 + $url = make_picture_url( array( + 'section' => 'categories', + 'category' => get_cat_info($_GET['cat']), + 'image_id' => $_GET['image_id'] + ) ); + redirect($url); + } + $token = $tokens[$next_token]; + $next_token++; + if ( is_numeric($token) ) + { + $page['image_id'] = $token; + } + else + { + preg_match('/^(\d+-)?(.*)?$/', $token, $matches); + if (isset($matches[1]) and is_numeric($matches[1]=rtrim($matches[1],'-')) ) + { + $page['image_id'] = $matches[1]; + if ( !empty($matches[2]) ) + { + $page['image_file'] = $matches[2]; + } + } + else + { + if ( !empty($matches[2]) ) + { + $page['image_file'] = $matches[2]; + } + else + { + bad_request('picture identifier is missing'); + } + } + } +} + +$page = array_merge( $page, parse_section_url( $tokens, $next_token) ); +if ( !isset($page['section']) ) +{ + $page['section'] = 'categories'; + + switch (script_basename()) + { + case 'picture': + break; + case 'index': + { + // No section defined, go to selected url + if (!empty($conf['random_index_redirect']) and empty($tokens[$next_token]) ) + { + $random_index_redirect = array(); + foreach ($conf['random_index_redirect'] as $random_url => $random_url_condition) + { + if (empty($random_url_condition) or eval($random_url_condition)) + { + $random_index_redirect[] = $random_url; + } + } + if (!empty($random_index_redirect)) + { + redirect($random_index_redirect[mt_rand(0, count($random_index_redirect)-1)]); + } + } + break; + } + default: + trigger_error('script_basename "'.script_basename().'" unknown', + E_USER_WARNING); + } +} + + +$page = array_merge( $page, parse_well_known_params_url( $tokens, $next_token) ); + + +if ( script_basename()=='picture' and 'categories'==$page['section'] and + !isset($page['category']) and !isset($page['chronology_field']) ) +{ //access a picture only by id, file or id-file without given section + $page['flat']=true; +} + +// $page['nb_image_page'] is the number of picture to display on this page +// By default, it is the same as the $user['nb_image_page'] +$page['nb_image_page'] = $user['nb_image_page']; + +if (pwg_get_session_var('image_order',0) > 0) +{ + $orders = get_category_preferred_image_orders(); + + $conf['order_by'] = str_replace( + 'ORDER BY ', + 'ORDER BY '.$orders[ pwg_get_session_var('image_order',0) ][1].',', + $conf['order_by'] + ); + $page['super_order_by'] = true; +} + +$forbidden = get_sql_condition_FandF( + array + ( + 'forbidden_categories' => 'category_id', + 'visible_categories' => 'category_id', + 'visible_images' => 'id' + ), + 'AND' + ); + +// +-----------------------------------------------------------------------+ +// | category | +// +-----------------------------------------------------------------------+ +if ('categories' == $page['section']) +{ + if (isset($page['category'])) + { + $page = array_merge( + $page, + array( + 'comment' => + trigger_event( + 'render_category_description', + $page['category']['comment'], + 'main_page_category_description' + ), + 'title' => + get_cat_display_name($page['category']['upper_names'], '', false), + ) + ); + } + else + { + $page['title'] = l10n('no_category'); + } + + if + ( + (!isset($page['chronology_field'])) and + ( + (isset($page['category'])) or + (isset($page['flat'])) + ) + ) + { + if ( !empty($page['category']['image_order']) and !isset($page['super_order_by']) ) + { + $conf[ 'order_by' ] = ' ORDER BY '.$page['category']['image_order']; + } + + if (isset($page['flat'])) + {// flat categories mode + if ( isset($page['category']) ) + { // get all allowed sub-categories + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE + uppercats LIKE "'.$page['category']['uppercats'].',%" ' + .get_sql_condition_FandF( + array + ( + 'forbidden_categories' => 'id', + 'visible_categories' => 'id', + ), + "\n AND" + ); + $subcat_ids = array_from_query($query, 'id'); + $subcat_ids[] = $page['category']['id']; + $where_sql = 'category_id IN ('.implode(',',$subcat_ids).')'; + // remove categories from forbidden because just checked above + $forbidden = get_sql_condition_FandF( + array( 'visible_images' => 'id' ), + 'AND' + ); + } + else + { + $where_sql = '1=1'; + } + } + else + {// Normal mode + $where_sql = 'category_id = '.$page['category']['id']; + } + + // Main query + $query = ' +SELECT DISTINCT(image_id) + FROM '.IMAGE_CATEGORY_TABLE.' + INNER JOIN '.IMAGES_TABLE.' ON id = image_id + WHERE + '.$where_sql.' +'.$forbidden.' + '.$conf['order_by'].' +;'; + + $page['items'] = array_from_query($query, 'image_id'); + } //otherwise the calendar will requery all subitems +} +// special sections +else +{ +// +-----------------------------------------------------------------------+ +// | tags section | +// +-----------------------------------------------------------------------+ + if ($page['section'] == 'tags') + { + $page['tag_ids'] = array(); + foreach ($page['tags'] as $tag) + { + array_push($page['tag_ids'], $tag['id']); + } + + $items = get_image_ids_for_tags($page['tag_ids']); + + // permissions depends on category, so to only keep images that are + // reachable to the connected user, we need to check category + // associations + if (!empty($items) ) + { + $query = ' +SELECT DISTINCT image_id + FROM '.IMAGE_CATEGORY_TABLE.' INNER JOIN '.IMAGES_TABLE.' ON image_id=id + WHERE image_id IN ('.implode(',', $items).') + '.$forbidden. + $conf['order_by'].' +;'; + $items = array_from_query($query, 'image_id'); + } + + $title = get_tags_content_title(); + + $page = array_merge( + $page, + array( + 'title' => $title, + 'items' => $items, + ) + ); + } +// +-----------------------------------------------------------------------+ +// | search section | +// +-----------------------------------------------------------------------+ + if ($page['section'] == 'search') + { + include_once( PHPWG_ROOT_PATH .'include/functions_search.inc.php' ); + + $search_result = get_search_results($page['search']); + if ( !empty($search_result['items']) and !isset($search_result['as_is']) ) + { + $query = ' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE id IN ('.implode(',', $search_result['items']).') + '.$forbidden.' + '.$conf['order_by'].' +;'; + $page['items'] = array_from_query($query, 'id'); + } + else + { + $page['items'] = $search_result['items']; + if ( isset($search_result['qs']) ) + {//save the details of the query search + $page['qsearch_details'] = $search_result['qs']; + } + } + + $page = array_merge( + $page, + array( + 'title' => '' + .l10n('search_result').'', + ) + ); + } +// +-----------------------------------------------------------------------+ +// | favorite section | +// +-----------------------------------------------------------------------+ + else if ($page['section'] == 'favorites') + { + check_user_favorites(); + + $query = ' +SELECT image_id + FROM '.FAVORITES_TABLE.' + INNER JOIN '.IMAGES_TABLE.' ON image_id = id + WHERE user_id = '.$user['id'].' +'.get_sql_condition_FandF + ( + array + ( + 'visible_images' => 'image_id' + ), + 'AND' + ).' + '.$conf['order_by'].' +;'; + + $page = array_merge( + $page, + array( + 'title' => l10n('favorites'), + 'items' => array_from_query($query, 'image_id'), + ) + ); + } +// +-----------------------------------------------------------------------+ +// | recent pictures section | +// +-----------------------------------------------------------------------+ + else if ($page['section'] == 'recent_pics') + { + $query = ' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE + date_available >= SUBDATE( + CURRENT_DATE,INTERVAL '.$user['recent_period'].' DAY) + '.$forbidden.' + '.$conf['order_by'].' +;'; + + $page = array_merge( + $page, + array( + 'title' => '' + .l10n('recent_pics_cat').'', + 'items' => array_from_query($query, 'id'), + ) + ); + } +// +-----------------------------------------------------------------------+ +// | recently updated categories section | +// +-----------------------------------------------------------------------+ + else if ($page['section'] == 'recent_cats') + { + $page = array_merge( + $page, + array( + 'title' => l10n('recent_cats_cat'), + ) + ); + } +// +-----------------------------------------------------------------------+ +// | most visited section | +// +-----------------------------------------------------------------------+ + else if ($page['section'] == 'most_visited') + { + $page['super_order_by'] = true; + $conf['order_by'] = ' ORDER BY hit DESC, file ASC'; + $query = ' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE hit > 0 + '.$forbidden.' + '.$conf['order_by'].' + LIMIT 0, '.$conf['top_number'].' +;'; + + $page = array_merge( + $page, + array( + 'title' => '' + .$conf['top_number'].' '.l10n('most_visited_cat').'', + 'items' => array_from_query($query, 'id'), + ) + ); + } +// +-----------------------------------------------------------------------+ +// | best rated section | +// +-----------------------------------------------------------------------+ + else if ($page['section'] == 'best_rated') + { + $page['super_order_by'] = true; + $conf['order_by'] = ' ORDER BY average_rate DESC, id ASC'; + + $query =' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE average_rate IS NOT NULL + '.$forbidden.' + '.$conf['order_by'].' + LIMIT 0, '.$conf['top_number'].' +;'; + $page = array_merge( + $page, + array( + 'title' => '' + .$conf['top_number'].' '.l10n('best_rated_cat').'', + 'items' => array_from_query($query, 'id'), + ) + ); + } +// +-----------------------------------------------------------------------+ +// | list section | +// +-----------------------------------------------------------------------+ + else if ($page['section'] == 'list') + { + $query =' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE image_id IN ('.implode(',', $page['list']).') + '.$forbidden.' + '.$conf['order_by'].' +;'; + + $page = array_merge( + $page, + array( + 'title' => '' + .l10n('random_cat').'', + 'items' => array_from_query($query, 'id'), + ) + ); + } +} + +// +-----------------------------------------------------------------------+ +// | chronology | +// +-----------------------------------------------------------------------+ + +if (isset($page['chronology_field'])) +{ + include_once( PHPWG_ROOT_PATH.'include/functions_calendar.inc.php' ); + initialize_calendar(); +} + +if (script_basename() == 'picture' + and !isset($page['image_id']) ) +{ + if ( !empty($page['items']) ) + { + $query = ' +SELECT id,file + FROM '.IMAGES_TABLE .' + WHERE file LIKE "' . $page['image_file'] . '.%" ESCAPE "|"'; + if ( count($page['items']) < 500) + {// for very large item sets do not add IN - because slow + $query .= ' + AND id IN ('.implode(',',$page['items']).') + LIMIT 0,1'; + } + $result = pwg_query($query); + switch (mysql_num_rows($result)) + { + case 0: break; + case 1: + list($page['image_id'], $page['image_file']) = mysql_fetch_row($result); + break; + default: // more than 1 file name match + while ($row = mysql_fetch_row($result) ) + { + if ( in_array($row[0], $page['items']) ) + { + list($page['image_id'], $page['image_file']) = $row; + break; + } + } + } + } + if ( !isset($page['image_id']) ) + { + $page['image_id'] = -1; // will fail in picture.php + } +} + +// add meta robots noindex, nofollow to avoid unnecesary robot crawls +$page['meta_robots']=array(); +if ( isset($page['chronology_field']) + or ( isset($page['flat']) and isset($page['category']) ) + or 'list'==$page['section'] or 'recent_pics'==$page['section'] ) +{ + $page['meta_robots']=array('noindex'=>1, 'nofollow'=>1); +} +elseif ('tags' == $page['section']) +{ + if ( count($page['tag_ids'])>1 ) + { + $page['meta_robots']=array('noindex'=>1, 'nofollow'=>1); + } +} +elseif ('recent_cats'==$page['section']) +{ + $page['meta_robots']['noindex']=1; +} +elseif ('search'==$page['section']) +{ + $page['meta_robots']['nofollow']=1; +} +if ( $filter['enabled'] ) +{ + $page['meta_robots']['noindex']=1; +} + +// see if we need a redirect because of a permalink +if ( 'categories'==$page['section'] and isset($page['category']) ) +{ + $need_redirect=false; + if ( empty($page['category']['permalink']) ) + { + if ( $conf['category_url_style'] == 'id-name' and + @$page['hit_by']['cat_url_name'] !== str2url($page['category']['name']) ) + { + $need_redirect=true; + } + } + else + { + if ( $page['category']['permalink'] !== @$page['hit_by']['cat_permalink'] ) + { + $need_redirect=true; + } + } + + if ($need_redirect) + { + $redirect_url = ( script_basename()=='picture' + ? duplicate_picture_url() + : duplicate_index_url() + ); + if (!headers_sent()) + { // this is a permanent redirection + set_status_header(301); + redirect_http( $redirect_url ); + } + redirect( $redirect_url ); + } + unset( $need_redirect, $page['hit_by'] ); +} + +trigger_action('loc_end_section_init'); +?> \ No newline at end of file diff --git a/BSF/include/smarty/COPYING.lib b/BSF/include/smarty/COPYING.lib new file mode 100644 index 000000000..3b204400c --- /dev/null +++ b/BSF/include/smarty/COPYING.lib @@ -0,0 +1,458 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/BSF/include/smarty/NEWS b/BSF/include/smarty/NEWS new file mode 100644 index 000000000..fa550ff18 --- /dev/null +++ b/BSF/include/smarty/NEWS @@ -0,0 +1,1024 @@ +Version 2.6.19 (Feb 11th, 2008) +------------------------------- + +- fix regex_replace allowing \0 in the search string (c960657, + monte) +- add append feature to {capture} (jablko, monte) +- fix when (un)registering filters with the same method name but different class + name (danilo) +- fix calling registered objects' methods with an empty argument list + (marcello, messju) + +Version 2.6.18 (Mar 7th, 2007) +------------------------------ + +- fix html_select_date separator when parts are missing (hayk, + monte) +- fix broken detection of non-cached blocks introduced in 2.6.17 + (messju) + +Version 2.6.17 (Mar 5th, 2007) +------------------------------ + +- fix php handling (monte, boots, danilo) +- fix handling of plugin tags directly followed by an else tag (Fahr, danilo) +- fix handling of $etc in the truncate modifier when $etc is longer + than $length (Sylvinus, messju) +- fix handling of %I with mysql timestamps in the date_format modifier + (danilo, boots) +- update smarty_core_write_file() and smarty_modifier_date_format() to better + recognize Windows (boots, danilo) +- emulate %h, %n, %r, %R, %t in the date_format modifier on Windows + (danilo, boots) + +Version 2.6.16 (Dec 1st, 2006) +------------------------------ + +- fixed replacement bug in trimwhitespace output filter that was introduced + in the last release (Spuerhund, boots) + +Version 2.6.15 (Nov 30th, 2006) +------------------------------- + +- change file writing semantics in smarty_core_write_file() to unlink() only + when rename() fails or a Windows system is detected (c960657, boots) +- update debug.tpl to xhtml 1.1 compliance, fix javascript escaping in debug + output and apply a Smarty based color scheme (cybot, boots) +- enhance reporting precision of debug_print_var modifier (cybot, boots) +- make html_select_date work consistently with 0000-00-00 00:00:00 and + 0000-00-00 inputs (cybot, boots) +- fix wrong handling of insert's name attribute. (messju) +- fix false replacement of "$t" inside double quotes (checat, messju) +- added support for column headings and caption element to html_table and + updated the output to use thead/tbody elements (boots) +- fixed ordering of replacements in trimwhitespace output filter (Getty, boots) +- update mailto function plugin to work around a firefox/thunderbird + escaping bug (elijahlofgren, boots) +- emulate %l in the date_format modifier on windows (boots) +- fix handling of apostrophes in capitalize modifier (Alec Smecher, boots) + +Version 2.6.14 (May 28th, 2006) +------------------------------- + +- fix compiler bug allowing php tags in secure templates + (boots,monte) +- un-hide hidden xml open tags (boots) +- fix handling of block-methods of registered objects (El Hombre Gris, + messju) + +Version 2.6.13 (March 9th, 2006) +-------------------------------- + + - update regex_replace, removing possible use of "e" modifier + +Version 2.6.12 (Jan 18th, 2006) +------------------------------- + + - fix improper use of references in the compiler handling cached + attributes and in compiled code handling block plugins (messju) + - make Smarty::_read_file() work on latest php (messju) + - fixed improper tokenization of certain inline math expressions (boots) + +Version 2.6.11 (Dec 14, 2005) +----------------------------- + + - fixed code generation of non-cacheable blocks to play well with php's + "Alternative syntax for control structures" (kihara, messju) + - fix handling of multiple identical inserts in one display()-call (messju) + - replace {} string access with equivalent substr() to avoid E_STRICT + warnings in PHP 5.1 (boots) + - return valid reference in get_config_vars() when given var is + non-existant (Thomas Schulz, boots) + - plugin html_image: fix incorrect secure_dir error when + file doesn't exist (monte) + - plugin html_image: add path_prefix param (monte) + - add char_set parameter to escape modifier (Loading, monte) + - fix notice in debug security check (Drakla, monte) + - return valid reference in get_template_vars() when given var is + non-existant (monte) + - add escape type "urlpathinfo" to escape modifier (monte) + +Version 2.6.10 (Aug 5, 2005) +---------------------------- + + - allow secure_dir to be a filename, not just + a directory name (monte) + - set debug.tpl as a secure_dir, not the entire + SMARTY_DIR (monte) + - fix proper escaping for literal strings in + Smarty_Compiler::_parse_var_props() (boots, messju) + - remove ambiguity for numeric values passed to smarty_make_timestamp() + (and thus the date_format modifier). numeric values are treated as + timestamps now. (andreas, messju) + - add passthru attribute feature to html_select_date (Sedgar, + monte) + - add "middle" parameter to truncate (monte) + - make form input label ids optional (monte) + - add error message for empty if/elseif statements (eykanal, + monte) + - cast selected value to string for comparison in html_radios + (Exeption, monte) + - updated html_select_date's year_as_text-feature to be xhtml compliant + (Mark West, messju) + - fix handling of selected month html_select_date (Yuri Weseman, messju) + +Version 2.6.9 (Mar 31, 2005) +---------------------------- + + - disallow variable function calls in {if} statements (messju, monte) + - disallow variable function calls in {math} equations (messju, monte) + +Version 2.6.8 (Mar 21, 2005) +---------------------------- + + - remove e-modifier from regex_replace modifier (messju) + - remove cast of object to array in foreach's from-attribute (messju) + - add "null" as a valid token for {if} when security is enabled (messju) + - add javascript_charcode encoding option to mailto function + (monte) + - add ids to html_radios labels (monte, menulis) + - fix handling of strip-tags with non-default delimiters (Mark West, messju) + +Version 2.6.7 (Feb 3, 2005) +--------------------------- + + - fix handling of hashed opening php-tags inside strip-blocks (messju) + - removed border tag from html_image function (monte) + - change escape:url use rawurlencode() instead of urlencode() (messju) + - make $smarty.const.FOO compile to "FOO", and not to "constant('foo')". + this is less code and a little faster execution. note that undefined + constants are now displayed as the constant's name. (messju) + - make block functions and registered objects' block methods use a + local variable for block_content instead of a property of $smarty (messju) + - fix escaping in the generated code that calls smarty_core_load_plugins + (jes5199, messju) + - fix invalid HTML issue with popup (Stefanos Harhalakis, + Monte) + - fixed {popup} to properly handle inarray and function parameters and added + support for mouseoff and followmouse options (boots) + +Version 2.6.6 (Oct 13, 2004) +---------------------------- + + - fixed nocache-handling with nested includes (Lars Jankowfsky, messju) + - moved /libs/core to /libs/internals (boots) + - fixed more parsing problems (messju) + +Version 2.6.5 (Sept 13, 2004) +----------------------------- + + - fixed some parsing problems with object calls introduced + in 2.6.4 (Monte) + - add $smarty->security_settings['ALLOW_CONSTANTS']. note: this + defaults to false which means you have to allow them explicitly + in your secured templates from now on! (messju) + +Version 2.6.4 (Sept 7, 2004) +---------------------------- + + - add $smarty.ldelim and $smarty.rdelim to smarty special var (Monte) + - fall back to old uniqid()-behaviour when tempnam() fails in + core.write_file.php (messju) + - fix capitalize modifier, don't rely on buggy ucwords (Monte) + - make html_select_date work with negative timestamps, also + force year range to include given date unless explicitly + set (Garo, Monte) + - fix bug with {fetch}, passing user/pass in url did not work + (Monte) + - fix occasional wrong error messages on mismatched tags when + {else}, {elseif}, {foreachelse} or {sectionelse} is involved (messju) + - fix handling of methods arguments (messju, Manfred Wischin) + - remove touch() call that made the compiled-template's timestamp the + same as the source-template's one. (messju) + - add assign attribute to html_checkboxes and html_radios + (pcg, Monte) + - remove non-xhtml conformant tag from mailto function + (tacker, Monte) + - handle date_format codes %e, %T and %D for windows (tip, + Monte) + - fix unnecessary call to smarty_core_get_include_path() inside + Smarty::_get_auto_filename() (c960657, messju) + - add error-messages when anything else than an identifier is passed + to foreach's key- or item-attribute (messju) + - fix handling of digits inside tagnames (messju) + - fix escaping of backslashes in Smarty_Compiler::_quote_replace() (messju) + +Version 2.6.3 (June 16, 2004) +----------------------------- + + - added escapement of 'tpl_error_reporting to $smarty->error_reporting + (messju) + - fix interpretation of $smarty->security in {html_image} (messju) + - add caching of requested paths to _assemble_plugin_filepath() (messju) + - fix handling of comments inside {php}- and {literal}-blocks (messju) + - fix bug handling triple-quotes in config-files (BRDude, messju) + - change default of request_use_auto_globals to true - $_SERVER is + now preferred over $HTTP_SERVER_VARS (messju) + - re-add support for $SCRIPT_NAME (messju) + - reactivate $smarty->default_modifiers (messju) + - add cookie persistance to debug console (Monte) + - allow single-digit days and months without smarty_make_timestamp() + in html_select_date (messju) + - fix headers sent erroneously with cache_modified_check and fetch() + (wphilips, messju) + - fix config_file path bug (Marc Cabadas, Monte) + - fix 'is even by' and 'is odd by' logic (Monte) + - add day_empty, month_empty, year_empty and all_empty attributes to + html_select_date (messju) + - add table of explanation for {if} qualifiers in docs (boots) + - fix bug when comparing array-keys to "selected" in html_options + and html_checkboxes (messju) + - add better checks for correctly nested tags when compiling (messju) + - remove {$SCRIPT_NAME}. use {$smarty.server.SCRIPT_NAME} instead (messju) + - remove $global_assign. assign global variables explicitly instead (messju) + - fix example for count_characters in docs (boots) + - add section new basic syntax section "Escaping Smarty Parsing" in docs (boots) + - fix error handler call in config_load (boots) + - remove warning in debug_print_var on php-resources (messju) + - move function.assign.php to compiler.assign.php (messju) + - add property $tpl_error_reporting (messju) + - remove property $undefined. "null" is used literally instead (messju) + +Version 2.6.0 (Nov 19, 2003) +---------------------------- + + - move Smarty::quote_replace() to Smarty_Compiler::_quote_replace() (messju) + - remove import of of attributes of {include_php} to php's namespace. + use $params[name] instead (messju) + +Version 2.6.0-RC3 (Nov 13, 2003) +-------------------------------- + + - fix handling of $var.key inside [] (messju) + - fix handling of assign inside {insert}-tags (messju) + - fix handling if [...] inside triple-quotes in config-files (messju) + - fix handling of simple-math-operators inside modifiers (Dominik, messju) + - fix handling of trailing-slashes in open_basedir in + smarty_core_create_dir_structure() (packman, messju) + +Version 2.6.0-RC2 (Oct 8, 2003) +------------------------------- + + - apply modifiers only once to section-loop and foreach-from attrs (messju) + - remove use of _smarty_cached_paths-files (messju) + - remove Smarty::_plugin_implementation_exists() - use is_callable() (messju) + - ignore {strip}/{/strip) inside {strip}-blocks (messju) + - fixed removal of leading/trailing newlines in {strip}-blocks (messju) + - fixed proper escaping of " and ' with escape:javascript (messju) + - fixed bug in traversal of $smarty->plugins_dir-array. now the + first matching plugin is taken (messju) + - moved {strip} back into the compiler (messju) + - fixed config_load: handling of section-attribute and use of + multiple config-files in one template (atu, messju) + +Version 2.6.0-RC1 (August 11, 2003) +----------------------------------- + + - fixed status-header for cache_modified_check under cgi-sapi (messju) + - added optional parameter $cache_attrs to register_function() and + register_block(). $cache_attrs is an array containing attribute- + names that should be cached on calls to functions that have + $cacheable set to false. (messju) + - enabled registration of class-methods as callbacks for the register_*- + functions (use: array('classname', 'method_name')) as callback) (messju) + - added filepath caching (Monte) + - added optional assign-attribute to {capture}-tag (messju) + - added $cacheable-parameter to register_compiler_function() (messju) + - added $cacheable-parameter with default=true to register_function() + and register_block() (messju) + - add math speedup to core (Dominik, Monte) + - fix newlines for tags without template output (Monte) + - added config-option "request_use_auto_globals" to make auto-globals be + used as request vars instead of HTTP_*_VARS (messju) + - speed up config_load, simplify compiling (Monte) + - added block-methods for registered objects (Bharat Mediratta, messju) + - ignore one char resource names like c:foo.tpl (Monte) + - added default_resource_type feature (Monte) + - fix bug where config file starts with hidden section (boots, Monte) + - add discrete error checking pertaining to $cache_dir + and $compile_dir, their existance and writability (Monte) + - fixed behaviour of start=... for {counter} (messju) + - fixed assign for {counter} (messju) + - added params vdir, hdir and inner to html_table to allow looping + over the data in various directions (messju) + - allow spaces in literal tags (Paul Lockaby, Monte) + - speed up compiled templates, hardcode plugin filepaths + instead of dynamically calculate at runtime. (Monte) + - abstract many core components from Smarty.class.php, + speeding up core class instantiation (Monte) + - fixed bug in _create_dir_structure() when used with open_basedir- + restriction and relative paths (messju) + - use DIRECTORY_SEPARATOR exclusively, keep DIR_SEP for BC (Monte) + - changed "link" to "href" in html_image. "link" is still working + but deprecated (messju) + - html_image always renders an alt-tag now (default alt="") (messju) + - fixed assign attribute for multiple counters (messju) + - added simple math operators to variables (Monte) + - enabled array(&$obj. 'source', 'timestamp', 'secure', 'trusted') + as callback for register_resource() (messju); + - enabled array(&$obj, 'method') as callback for + $default_template_handler_func (messju) + - remove unnecessary close/open tags from compiled templates + (Monte) + - fixed errornous creation of '//' in image_path in html_image (messju) + - fix escapement of special chars for key vals in debug + console (Monte) + - fixed debug timing logic for config_load (Tom Sommer, Monte) + - all in-code doc comments converted to phpDocumentor format (Greg) + - moved strip from smarty core to plugin (Monte) + - moved config_load from smarty core to plugin (Monte) + - added &$repeat-parameter to block-functions (messju) + - enabled hex-constants in function.math.php (messju) + - enabled hex-constants (0x...) as function-attributes, inside if-statements + and as modifier-parameters (messju) + - fixed bug with passing $smarty as reference in Smarty.compiler.class + (messju) + - corrected output with {strip} and PHP tag newlines (Monte) + - added possibility to register function-callbacks as "array(&$obj, 'method)" + this affects register_function(), -block, -compiler_function, -modifier, + -prefilter, -postfilter, -outputfilter-functions() and $cache_handler_func + (messju) + - added to html_checkboxes and html_radios (Philippe, messju) + - added "labels"-options to turn off labels in html_checkboxes and _radios + (messju) + +Version 2.5.0 (April 11, 2003) +------------------------------ + + - fixed bug with default modifier when passing integer 0 + (Monte) + - change backtic syntax from $`foo` to `$foo` (Monte) + - recognize $foo[][] syntax inside embedded quotes without + backtics (Monte) + - name=123 is passed as an integer (not a string) to plugins now (messju) + - $length is now propagated to sub-values in debug_print_var (messju) + +Version 2.5.0-RC2 (March 26, 2003) +---------------------------------- + + - made clear_cache() ignore compile_id, when clearing cache-groups (this + is when no $tpl_file is supplied) (messju) + - made onmouseout XHTML-compliant in function.popup.php (messju) + - applied local-var-naming-scheme to fetch() (messju) + - renamed $localvars to $_localvars in cache-file-handling-functions, + added _get_auto_id()-function (messju) + - swapped compile_id and cache_id in read_cache_file and write_cache_file + (messju) + - reverted patch for cache-file-handling (messju) + - made html_radios and html_checkboxes accept "selected" instead + of "checked" optionally. (messju) + - made compile_id ignored in clear_cache, made order of + auto_file_name $cache_id.$compile_id again, applied the the new + variable-naming-scheme for cache_file_handing functions (messju) + - removed notice of undefined var in _rm_auto() (messju) + - added warning message when an array is passed as + the "checked" value of html_radios (Monte) + - fixed errormessage in _compile_smarty_ref() (messju) + - updated docs for html_image "name" -> "file" (messju) + - fixed bug with html_options-optgroups (Nichlas Löfdahl, messju) + - cleaned up calls to readdir() (messju) + - fixed bug with passing multiple modifiers to a parameter + (Monte) + - updated docs for html_checkboxes, html_options and html_radios (messju) + - fixed wrong default "name" attribute for html_options (messju) + - html_checkboxes now expect the options as attribute "options" instead + of "checkboxes. html_radios expect "options" instead of "radios". + cleaned up indentiation (messju) + - fixed too greedy str_replace in trimwhitespace outputfilter (messju) + - html_checkboxes and html_radios passthru all unknown paramters now + additionally their output is now XHTML compliant (messju) + - html_options passthru all unknown paramters now (messju) + - fix link functionality of html_image, also make + output XHTML compatible (Hinrich Donner, Monte) + - append "@" to default modifier vars/args + supress possible warnings (Monte) + - fix problem with escaped double quotes (Monte) + - fix html_radios to not return an array (Monte) + - fixed length in modifier.truncate.php (messju) + - fixed handling of '$'-signs in trimwhitespace outputfilter (messju) + - fix bug that makes config files recompile every time + (Nagger, Monte) + - add dpi functionality to html_image, change "name" + parameter to "file" (Thomas Shulz, Monte) + - fix height/width parameter index in html_image (Gerard, + Monte) + - get rid of unsetting name and script attributes + to insert tag (Thomas Schulz, Monte) + - changed argument order of string_format modifier back, + was right in the first place (Monte) + +Version 2.5.0-RC1 (March 5, 2003) +--------------------------------- + + - fixed notice in popup function (Nagger, Monte) + - fix "once" var compiling for include_php (Monte) + - added nl2br modifier to distribution (Monte) + - added html_image to distribution (Monte) + - added cat modifier to distribution (Monte) + - added html_table to distribution (Monte) + - added << >> <> support to if statments (SMK, Monte) + - fix _assign_smarty_interface to not overwrite keys + other than 'request' (Jerome Poudevigne, Monte) + - added html_checkboxes to distribution (Christopher Kvarme, Monte) + - added html_radios to distribution (Christopher Kvarme, Monte) + - fixed string_format modifier args (wrong order) (Paul + Lockaby, Monte) + - use tmp file for file writes, avoid file lock race (Monte) + - support syntax "$`smarty.config.foo`.tpl" for embedded + vars in quotes, and allow full dollar var syntax (Monte) + - add $smarty.config.varname variable for accessing config vars (Paul + Lockaby, Monte) + - silence PHP warnings in function.fetch.php (Eduardo, + Monte) + - added get_config_vars(), same basic functionality as + get_template_vars() (Monte) + - update get_template_vars() to be able to get + individual vars (Monte) + - fix minor logic in _fetch_template_info (Dennis Gearon, + Monte) + - fix cache groups with compile_id set (Monte) + - add support for merging appended vars (messju, Monte) + - allow null as function attribute value + (André Rabold, Monte) + - support $foo->bar[index] syntax (Monte) + - add get_registered_object function (messju, Monte) + - treat unrecognized param attribute syntax as string (Monte) + - support $smarty.const.$foo syntax (messju, Monte) + - remove E_NOTICE warnings from debug.tpl, + escape modifier (Kanstantin, Monte) + - don't count non-ascii chars in count_words modifier + (Kanstantin, Monte) + - clean up param calls to _parse_var and _parse_attrs (Monte) + - define $template_source var, elude possible warning + (Monte) + - fix syntax problem with evaluating PHP constants (Monte) + - add @ and === as valid if statement tokens (Monte) + - enable error messages for config_load errors, + use $this->config_class for loading class name (Monte) + - fix html_options to not escape already escaped entities (Monte) + - send Last-Modified header on cache creation (Monte) + - check strict syntax of function attributes (Monte) + - dropped support for modifers on object parameters, + added support for objects as modifier parameters (Monte) + - fixed bug with decimal numbers in if statements (Monte) + +Version 2.4.2 (Feb 11, 2003) +---------------------------- + - support embedded variables in objects (Monte) + - fix bug with objects with no properties (M Mohr, Monte) + - support full dollar var syntax in quoted text (Monte) + - fixed bug in $smarty.const.FOO introduced in 2.4.1 (M + Mohr, Monte) + +Version 2.4.1 (Feb 6, 2003) +--------------------------- + + - ignore case in IF statements (Rainer Collet, Monte) + - treat undefined constants as null (Ferdinand Beyer, Monte) + - fix problem with inserts and nested fetches + (Rainer Collet, Monte) + - added support for passing params to include_php + (Tim Riley, Monte) + - added support for math operators in if statements (Monte) + - added support for $foo->bar[$x].blah syntax (Monte) + +Version 2.4.0 (Feb 2, 2003) +--------------------------- + + - fix known problems with php tag handling in templates + (recursion, echoing xml tags) (Monte) + - add support for object registration (Monte) + - add debug template to secure_dir, add template_dir + to secure_dir by default (Ferdinand Beyer, Monte) + - added support for assigned object access (Monte) + - fixed bug with directories named '0' (Frank Bauer, Monte) + - add javascript parameter to escape modifier (Monte) + - added calling function line numbers to syntax error + messages in compiler (Monte) + - added support for modifiers to function calls (Monte) + - support return value for custom functions + instead of echoing (but echo still works) (Monte) + - added direct access to constants + via $smarty.const.FOO (Monte) + - added support for passing modifiers + to static values (Monte) + - fix up regex code in compiler, more accurate and + maintainable (Monte) + - added day_value_format to html_select_date (Marcus + Bointon, Monte) + - assigned variables are no longer in global + namespace, saving extract() calls and speeding + up fetch() and display() linearly with no. of + assigned variables (Monte) + - added trimwhitespace output filter to dist. (Monte) + - fix popup function to allow newlines in text (Monte) + - escape html entities in html_options (Monte) + - fixed bug with label for html_options (Monte) + - added config_load API function (Monte) + - added caching to config file loading (Monte) + - added "extra" parameter to mailto function (Monte, + Massimiliano Perantoni) + - added mailto plugin to dist. (Monte) + +Version 2.3.1 (Nov 19, 2002) +---------------------------- + + - added optgroup support to html_options (Monte, Robert + Amos) + - set mtime on compile files so they match source + files (Monte, Peter Bowen) + - added proper support for open_basedir setting + (Monte, Alessandro Astarita) + - added strip variable modifier, updated docs (Monte) + - fixed access to $smarty.x variables as arrays. (Andrei) + - fixed errors with example setup docs (Monte, Matthew + Hagerty) + - added textformat block function (Monte) + +Version 2.3.0 (Aug 7, 2002) +--------------------------- + + - added assign_by_ref() and append_by_ref() functions + (Bob Silva, Monte) + - changed default warning type for plugin errors from + E_USER_WARNING to E_USER_ERROR (Monte) + - added $all_extra, $hour_extra, $minute_extra, + $second_extra and $meridian_extra parameters to + html_select_time function (Rainer Collet, Monte) + - update debug console to print objects (Simon Willison, + Monte) + - fix Config_File class to not error when there are no + sections (Peter Kmet, Monte) + - add default modifier logic (Monte) + - updated popup_init to be xhtml compliant (Tom Oram, Monte) + - fix filename bug with windows (Gary Loescher, Monte) + - add ability to supply expire time in seconds when clearing + cache or compile files (Monte) + - add {debug} plugin to distribution (Monte) + - fixed bug with insert tags, loading from "script" attribute + when caching is enabled (Monte) + - fix bug with debug_tpl file path with Windows (.SMK., Monte) + - fix append() function with string/array problem (Monte) + +Version 2.2.0 (July 11, 2002) +----------------------------- + + - make debug.tpl work with any delimiter (Monte) + - change logic in assign() and append() to test var names + against != '' instead of empty() (Monte) + - fix PHP notice in append() function (Monte) + - allow $plugins_dir to be an array of directories + (Andreas Kossmeier, Monte) + - move debug.tpl to SMARTY_DIR, add to constructor (Monte) + - fixed warning message in function.assign_debug_info (Monte) + - fixed $template_dir, $compile_dir, $cache_dir, $config_dir, + $plugin_dir to respect include_path (Monte) + - fixed warning message with output filter array (Monte) + - add optional 2nd parameter to date_format, used as + the default date if the passed date is empty (Monte) + - gave $reset a default value in cycle plugin (Monte) + - fixed warnings with html_select_date and timestamp + functions (Monte) + - added support for sub directory exlusion format (Monte) + - added support for grouping by cache_id, compile_id + and segments thereof (Monte) + - changed cache and compile files to human readable + format (Monte) + - remove overlib.js file from distribution (Monte) + - fixed bug with 304 Not Modified response sending + content (Monte) + - fixed cycle function to respect delimiter after + initial setting (Monte) + - update $GLOBALS references to work properly with + track_globals settings (Michal Prinke, Monte) + - fixed bug in math function with call to assign + (Grigory V. Kareev, Monte) + - optimized for loops with count() function calls (Monte) + - add month_value_format attribute to html_select_date + plugin (Gary Loescher, Monte) + - made it possible to use simple variables inside [] for + indexing. (Andrei) + - added "once" attribute to {include_php}. (Monte) + +Version 2.1.1 +------------- + - added cycle function. (Monte) + - fixed bug with resource testing, and include_path. (Monte) + - fixed a bug with register_outputfilter function. (Monte) + +Version 2.1.0 +------------- + + - introduced output filters. (Andrei) + - changed the way filters are loaded, added load_filter() + API function and $autoload_filters variable. (Andrei) + - added caching logic for expire times per cache file + (Norbert Rocher, Monte) + - fixed html_select_date when field separator is "/" + (Roberto Berto, Monte) + - added YYYY-MM-DD format support to html_select_date + (Jan Rosier, Monte) + - fixed cache_lifetime logic bug, also made -1 = never + expire (Monte) + - fixed directory separator issue for Windows. (Andrei) + - added ability to use simple variables as array indices or + object properties. (Andrei) + - added ability to unregister pre/postfilters plugins at + runtime. (Andrei) + - added 'htmlall' attribute to escape modifier. (Monte) + - added template_exists() API function. (Andrei) + - fixed a problem with using dynamic values for 'file' + attribute of {include_php} tag. (Andrei) + - added $smarty.template variable. (Andrei) + - fixed several plugins that would not work if the plugin + directory was not the default one. (Andrei) + - implemented support for block functions. (Andrei) + - made it possible to assign variables in pre/postfilter + plugins. (Andrei) + +Version 2.0.1 +------------- + - rename plugin .make_timestamp.php to shared.make_timestamp.php. + (Monte) + - changed crc32() generated values, replace '-' with 'N'. (Monte) + - added support for +/- N syntax in html_select_date year values. + (Monte) + - fixed behavior of inserts with script attribute. (Andrei) + - fixed bug with $smarty.cookies and $smarty.server. (Andrei) + - wordwrap and indent are missing from 2.0 release, now fixed. + (Monte) + - removed show_info_header and show_info_include variables. (Monte) + +Version 2.0.0 +------------- + - added "eval" function plugin for evaluating variables as + templates. (Monte) + - removed $tpl_file_ext class variable, no longer used. (Monte) + - added "hex" and "hexentity" escape types to escape modifier. + (Monte) + - removed dependency on PEAR. (Andrei) + - update popup_init to accept src attribute. (Monte, Duncan Forrest) + - implemented several optimizations, speeding up Smarty + significantly in most cases. (Andrei,Monte) + - implemented plugin architecture. (Andrei) + - added wordwrap and indent modifiers. (Monte) + - added support for 'If-Modified-Since' headers for cached content. + (Monte) + - removed insert_tag_check class variable, no longer needed. (Monte) + - optimized cache fetches by scanning for insert tags only if they + exist. (Monte) + - fixed bugs in overlib. (Monte, Duncan Forrest) + - fixed a problem with compile_id usage. (Andrei) + - fixed problem with using assigned vars with {include_php ...} + filepath. (Monte) + +Version 1.5.2 +------------- + - added Smarty object as fifth argument for template resource functions. + (Monte) + - fixed a bug with incorrectly combined cache and compile id in + clear_cache(). (Andrei) + - fixed bug in smarty_make_timestamp introduced in PHP 4.1.0. (Monte) + - fixed bug with cached insert debug timing. (Monte) + - added 'script' attribute to {insert..} which specifies the script that + the insert function can be found in. (Andrei) + - added default template function handler. (Monte) + +Version 1.5.1 +------------- + - removed error message from the generic _read_file() method, the caller + should take care of that. (Andrei) + - fixed a bug with incorrectly combined cache and compile id. (Andrei) + +Version 1.5.0 +------------- + - added include_php built-in function, documented. (Monte) + - added trusted_dir functionality, documented. (Monte) + - consolidated secure_dir tests to one function. (Monte) + - prepended _smarty_ to variable names in fetch() class function to avoid + namespace conflicts. (Monte) + - introduced $compile_id class variable that can be used to set persistent + compile identifier across multiple display calls, documented. (Andrei) + - fixed bug with concatenated null cache and compile identifiers. (Andrei) + - added $smarty.section.* syntax for accessing section properties, + documented. (Andrei) + - added custom cache handling function ability, documented. (Monte) + - added assign attribute to include, include_php, insert, fetch, math, and + counter functions, documented. (Monte) + - fixed bug with fetch testing for local file when http address. (Monte) + - fixed bug with counter and skipval setting. (Monte) + - made {config_load ...} merge globals from each config file only once per + scope, thus avoiding several problems. (Andrei) + - added {foreach ...} tag that can be used to iterate through + non-sequential and associative arrays, documented. (Andrei) + - speeded up section property access a bit. (Andrei) + - removed $smarty variable from storage used by normal template variables, + to prevent any problems. (Andrei) + - fixed a bug that could cause parse error with quotes inside literal + blocks. (Andrei, Alexander Belonosov) + - added 'field_array' attribute to html_select_time function, documented. + (Andrei, Michael Caplan) + - documented {section} "max" attribute. (Monte) + - fixed notice message in Smarty_Compiler.class.php. (Monte) + - fixed bug with clear_cache introduced in 1.4.6, third parameter should + default to null. (Monte) + - updated Config_File class to support '\' path separator in OS/2. (Monte, + Francesco Cipriani) + - removed secure_ext setting (not used). (Monte) + - made cache reading process more efficient. (Monte) + - fixed bug, is_cached() now supports new 1.4.6 caching behavior. (Monte) + - update FAQ with mailing list Reply-To header FAQ. (Monte) + - supress error messages for fopen(), fix cache to regenerate if cache + file is not available (i.e. cluster race condition). (Monte) + - added index key example to QUICKSTART guide. (Monte) + +Version 1.4.6 +------------- + - fixed bug with {assign ...} when passing an empty value. (Monte) + - add more warning message fixes. (Monte, Tara Johnson) + - documentation updates. (Monte) + - update fetch function to give proper warning when fetching a non-readable + or non-existant file. (Monte) + - fixed problem with newline at the end of included templates (Monte, Andrei) + - added feature to regenerate cache if compile_check is enabled and an + involved template or config file gets modified. (Monte) + - added DEBUG execution times to included files: REQUIRES updated debug.tpl + file! (Monte) + - added support for hidden config variables that cannot be read by + templates. (Andrei) + - added execution time to DEBUG console, total and inserts. (Monte) + - fixed bug where DEBUG console would not appear with cached content. (Monte) + - added support for postfilter functions that are applied to compiled + template right after compilation. (Andrei) + - fixed the name of clear_compile_tpl() API function to clear_compiled_tpl. + (Andrei) + - added fix for removing comments so that the line numbers are reported + correctly in case of errors. (patch from Anders Janson) + - made html_options output xhtml compatible code. (Monte, Arnaud Limbourg) + +Version 1.4.5 +------------- + - update FAQ with index of questions at the top + - update overlib to 3.50, adjust addon code so that the overlib.js + file isn't modified, and not using the mini one. (Monte) + - added many more options to html_select_date. (Alexander Skwar, Andrei) + - added support for generating different compiled templates from the same + source template. (Hans-Peter Oeri, Andrei) + - modified Smarty to pass itself to insert functions as the second + parameter. (Andrei) + - modified Smarty to pass itself to prefilter functions as the second + parameter. (Andrei) + - fixed syntax error when including a non-existant template with security + enabled. (Monte) + - fixed comments handling to allow commenting out template blocks. (Andrei) + - implemented named capture buffers, with results accessible via + $smarty.capture.. (Andrei) + - added ability to index arrays directly by numbers. (Andrei) + - fixed bug with SMARTY_DIR not prepended to Config_File include. (Monte) + +Version 1.4.4 +------------- + - fixed problem with including insecure templates with security enabled. + (Monte) + - numerous documentation updates. (Monte) + - added ENT_QUOTES to escapement of html. (Monte, Sam Beckwith) + - implemented access to request variables via auto-assigned $smarty + template variable. (Andrei) + - fixed a bug with parsing function arguments inside {if} tags if a comma + was present. (Andrei) + - updated debug console with config file vars. (Monte) + - added SMARTY_DIR constant as an alternative to relying on include_path. + (Monte) + - added popup_init and popup functions (requires overlib.js). (Monte) + - updated debug console with config file vars. (Monte) + - added debugging url control. (Monte) + - added 'quotes' type to escape modifier. (Monte, Mike Krus) + - added 'total' and 'iteration' section properties. (Andrei) + - added 'start', 'max', and 'step' section attributes/properties. (Andrei) + - fixed a bug with security checking of functions inside {if} tags. + (Andrei) + - fixed a bug in Config_File that would incorrectly booleanize values that + weren't really booleans. (Andrei) + +Version 1.4.3 +------------- + - added regex_replace modifier, documented. (Monte) + - added debugging console feature and custom function assign_debug_info, + documented. (Monte) + - added 'scope' attribute for {config_load}, 'global' is now deprecated but + is still supported. (Andrei) + - reduced template symbol table pollution by moving config array into the + class itself. (Andrei) + - fixed a bug with passing quoted arguments to modifiers inside {if} + statements. (Andrei, Sam Beckwith) + - added security features for third party template editing, documented + (Monte) + - added assign custom function, documented. (Monte) + - fixed bug with template header using version instead of _version. (Monte) + - fixed a problem with putting $ followed by numbers inside {strip} and + {/strip} tags. (Andrei) + - fixed Config_File class to allow empty config paths (defaults to current + directory). (Andrei) + +Version 1.4.2 +------------- + - move $version to internal variable, remove from docs. (Monte) + - cleaned up compiled templates global scope by moving some variables into + the class itself. (Andrei) + - fixed a bug that would not allow referring to a section in the including + file from the included file. (Andrei) + - configs directory missing from 1.4.1 release, added back in. (Monte) + - added windows include_path setup instructions to FAQ & QUICKSTART. + (Monte) + +Version 1.4.1 +------------- + - fix LOCK_EX logic for all windows platforms (Monte) + - fixed indexing by section properties with the new syntax. (Andrei) + - updated Smarty to use absolute paths when requiring/including Smarty + components. (Andrei, John Lim) + +Version 1.4.0 +------------- + - added {capture}{/capture} function, documented (Monte) + - added {counter} function, documented (Monte) + +Version 1.4.0b2 +--------------- + - fixed issue in Config_File.class with referencing blank sections (Andrei) + - fixed problem with passing variables to included files (Andrei) + - fixed resource path recognition for windows (Monte) + +Version 1.4.0b1 +--------------- + - added "componentized templates" tip into documentation (Monte) + - added {php}{/php} tags for embedding php code into templates (Monte) + - changed default value of $show_info_header to false (Monte) + - implemented '->' syntax for accessing properties of objects passed to the + template. (Andrei) + - allowed custom functions to receive Smarty object as the second + parameter; this can be used to dynamically change template variables, for + example. (Andrei) + - added custom compiler functions support, register_compiler_function() and + unregister_compiler_function() API functions. (Andrei, Ivo Jansch). + - updated GLOBAL_ASSIGN to take SCRIPT_NAME from HTTP_SERVER_VARS + instead of global variable. You can also assign several variables + in one shot with an array. (Monte, Roman Neuhauser) + - added template prefilters, register_prefilter() and + unregister_prefilter() API functions. (Monte) + - added RELEASE_NOTES file to distribution. (Monte) + - moved CREDITS out of manual into its own file. (Monte) + - added register_resource() and unregister_resource() API functions. (Monte) + - changed the syntax of indexing template variables, thus supporting + structures of arbitrary complexity; supplied fix_vars.php script to fix + old syntax. (Andrei) + - added $insert_tag_check to speed up cached pages if {insert ...} is not + used. (Monte) + - added $compiler_class variable to allow specifying a different compiler + class. (Andrei) + - changed Smarty to compile templates at runtime, allowing for arbitrary + template resources. (Monte) + - added fix for LOCK_EX under Windows and changed a couple of file + permissions for security. (Monte, Fernando Nunes) + - allow arbitrary date strings to date_format, html_select_date and + html_select_time (Monte) + +Version 1.3.2 +------------- + - fixed a bug that caused some nested includes to loop infinitely. (Andrei) + - added optional HTML header to output. (Monte) + - significantly improved config_load performance. (Andrei) + - added format attribute to math function. (Monte) + - added html_select_time custom function. (Andrei) + - fixed minor PHP warning when attempting to unset an unset variable + (Monte) + - added count_characters, count_words, count_sentences, count_paragraphs + modifiers (Monte) + +Version 1.3.1pl1 +-------------- + - bug fix, recovered missing _syntax_error function (Monte) + +Version 1.3.1 +------------- + - document first, last, index_prev, index_next (Monte) + - added 'first' and 'last' section properties. (Andrei) + - split out compiling code to separate class for faster template execution + time (Monte) + - fixed a couple of minor PHP warnings (Monte) + - added and documented unregister_modifier() and unregister_function() API + calls. (Monte) + - added and documented 'fetch' and 'math' functions. (Monte) + - added ability to index looped variables by section properties, e.g. + $foo.index_prev/bar. (Andrei) + - added index_prev and index_next section properties. (Andrei) + - fixed issue with php executing in literal blocks. (Monte) + +Version 1.3.0 +------------- + - moved license from GPL to LGPL (Monte) + - implemented workaround for PHP "feature" that eats carriage returns + if the PHP tag is at the end of the line. (Andrei) + - removed $allow_php, added $php_handling logic (Monte) + - added file locking to prevent reader/writer problem. (Andrei) + - made Smarty catch unimplemented modifiers and custom functions and output + error messages during compilation instead of failing during run time. + (Andrei) + - removed short-tags at the top of the smarty scripts (Monte) + - added register_function() and register_modifier() API calls to make + registering stuff easier. (Andrei) + - added template results caching capability. (Monte, Andrei) + - added optional 'options' attribute to html_options custom function + that allows passing associative arrays for values/output. (Andrei) + - modifier arguments can now contain '|' and ':' characters inside quoted + strings. (Andrei) + +Version 1.2.2 +------------- + - fixed bug that would not respect nested template directories and would + put all compiled files into top-level one. (Andrei) + - fixed bug using $PHP_VERSION instead of environment var PHP_VERSION. + (Monte) + - a couple small warning fixes. (Monte) + +Version 1.2.1 +------------- + - added $compile_dir, removed $compile_dir_ext, simplified usage. (Monte) + - added tips & tricks chapter to documentation. (Monte) + - misc documentation updates. (Monte) + +Version 1.2.0 +------------- + - updated documentation (Monte) + - added file and line number information to syntax error messages. (Andrei) + - added ability to index template vars by a key. (Andrei) + +Version 1.1.0 +------------- + - misc documentation changes, official stable release + +Version 1.0b +------------ + - fixed the bug that prevented using non-array values for 'loop' attribute. + (Andrei) + - many misc documentation changes & additions (Monte) + +Version 1.0a +------------ + - fixed bug that caused templates to recompile every time (Monte) + +Version 1.0 +------------ + - initial release + +/* vim: set et tw=64 ft=changelog: */ diff --git a/BSF/include/smarty/README b/BSF/include/smarty/README new file mode 100644 index 000000000..6e7c93c56 --- /dev/null +++ b/BSF/include/smarty/README @@ -0,0 +1,85 @@ +NAME: + + Smarty - the PHP compiling template engine + +VERSION: 2.6.19 + +AUTHORS: + + Monte Ohrt + Andrei Zmievski + +MAILING LISTS: + + We have a few mailing lists. "discussion" for you to share your ideas or ask + questions, "developers" for those interested in the development efforts of Smarty, + and "svn" for those that would like to track the updates made in the svn + repository. + + send a blank e-mail message to: + smarty-discussion-subscribe@googlecode.com(subscribe to the general discussion list) + smarty-discussion-unsubscribe@googlecode.com (unsubscribe from the general discussion list) + smarty-discussion-digest-subscribe@googlecode.com (subscribe to digest) + smarty-discussion-digest-unsubscribe@googlecode.com (unsubscribe from digest) + smarty-developers-subscribe@googlecode.com (subscribe to the dev list) + smarty-developers-unsubscribe@googlecode.com (unsubscribe from the dev list) + smarty-svn-subscribe@googlecode.com (subscribe to the svn list) + smarty-svn-unsubscribe@googlecode.com (unsubscribe from the svn list) + + You can also browse the mailing list archives at + http://groups.google.com/group/smarty-discussion + http://groups.google.com/group/smarty-developers + + and the OLD list archives at + http://marc.theaimsgroup.com/?l=smarty&r=1&w=2 + +SYNOPSIS: + + require("Smarty.class.php"); + + $smarty = new Smarty; + + $smarty->assign("Title","My Homepage"); + $smarty->assign("Names",array("John","Gary","Gregg","James")); + + $smarty->display("index.tpl"); + + +DESCRIPTION: + + What is Smarty? + + Smarty is a template engine for PHP. Many other template engines for PHP + provide basic variable substitution and dynamic block functionality. + Smarty takes a step further to be a "smart" template engine, adding + features such as configuration files, template functions, and variable + modifiers, and making all of this functionality as easy as possible to + use for both programmers and template designers. Smarty also converts + the templates into PHP scripts, eliminating the need to parse the + templates on every invocation. This makes Smarty extremely scalable and + manageable for large application needs. + + Some of Smarty's features: + + * it is extremely fast + * no template parsing overhead, only compiles once. + * it is smart about recompiling only the template files that have + changed. + * the template language is remarkably extensible via the plugin + architecture. + * configurable template delimiter tag syntax, so you can use + {}, {{}}, , or whatever you like. + * built-in caching of template output. + * arbitrary template sources (filesystem, databases, etc.) + * template if/elseif/else/endif constructs are passed to the PHP parser, + so the if syntax can be as simple or as complex as you like. + * unlimited nesting of sections, conditionals, etc. allowed + * it is possible to embed PHP code right in your template files, + although not recommended and doubtfully needed since the engine + is so customizable. + * and many more. + +COPYRIGHT: + Copyright (c) 2001-2005 New Digital Group, Inc. All rights reserved. + This software is released under the GNU Lesser General Public License. + Please read the disclaimer at the top of the Smarty.class.php file. diff --git a/BSF/include/smarty/libs/Config_File.class.php b/BSF/include/smarty/libs/Config_File.class.php new file mode 100644 index 000000000..89ba41c45 --- /dev/null +++ b/BSF/include/smarty/libs/Config_File.class.php @@ -0,0 +1,389 @@ + + * @access public + * @package Smarty + */ + +/* $Id$ */ + +/** + * Config file reading class + * @package Smarty + */ +class Config_File { + /**#@+ + * Options + * @var boolean + */ + /** + * Controls whether variables with the same name overwrite each other. + */ + var $overwrite = true; + + /** + * Controls whether config values of on/true/yes and off/false/no get + * converted to boolean values automatically. + */ + var $booleanize = true; + + /** + * Controls whether hidden config sections/vars are read from the file. + */ + var $read_hidden = true; + + /** + * Controls whether or not to fix mac or dos formatted newlines. + * If set to true, \r or \r\n will be changed to \n. + */ + var $fix_newlines = true; + /**#@-*/ + + /** @access private */ + var $_config_path = ""; + var $_config_data = array(); + /**#@-*/ + + /** + * Constructs a new config file class. + * + * @param string $config_path (optional) path to the config files + */ + function Config_File($config_path = NULL) + { + if (isset($config_path)) + $this->set_path($config_path); + } + + + /** + * Set the path where configuration files can be found. + * + * @param string $config_path path to the config files + */ + function set_path($config_path) + { + if (!empty($config_path)) { + if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) { + $this->_trigger_error_msg("Bad config file path '$config_path'"); + return; + } + if(substr($config_path, -1) != DIRECTORY_SEPARATOR) { + $config_path .= DIRECTORY_SEPARATOR; + } + + $this->_config_path = $config_path; + } + } + + + /** + * Retrieves config info based on the file, section, and variable name. + * + * @param string $file_name config file to get info for + * @param string $section_name (optional) section to get info for + * @param string $var_name (optional) variable to get info for + * @return string|array a value or array of values + */ + function get($file_name, $section_name = NULL, $var_name = NULL) + { + if (empty($file_name)) { + $this->_trigger_error_msg('Empty config file name'); + return; + } else { + $file_name = $this->_config_path . $file_name; + if (!isset($this->_config_data[$file_name])) + $this->load_file($file_name, false); + } + + if (!empty($var_name)) { + if (empty($section_name)) { + return $this->_config_data[$file_name]["vars"][$var_name]; + } else { + if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name])) + return $this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name]; + else + return array(); + } + } else { + if (empty($section_name)) { + return (array)$this->_config_data[$file_name]["vars"]; + } else { + if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"])) + return (array)$this->_config_data[$file_name]["sections"][$section_name]["vars"]; + else + return array(); + } + } + } + + + /** + * Retrieves config info based on the key. + * + * @param $file_name string config key (filename/section/var) + * @return string|array same as get() + * @uses get() retrieves information from config file and returns it + */ + function &get_key($config_key) + { + list($file_name, $section_name, $var_name) = explode('/', $config_key, 3); + $result = &$this->get($file_name, $section_name, $var_name); + return $result; + } + + /** + * Get all loaded config file names. + * + * @return array an array of loaded config file names + */ + function get_file_names() + { + return array_keys($this->_config_data); + } + + + /** + * Get all section names from a loaded file. + * + * @param string $file_name config file to get section names from + * @return array an array of section names from the specified file + */ + function get_section_names($file_name) + { + $file_name = $this->_config_path . $file_name; + if (!isset($this->_config_data[$file_name])) { + $this->_trigger_error_msg("Unknown config file '$file_name'"); + return; + } + + return array_keys($this->_config_data[$file_name]["sections"]); + } + + + /** + * Get all global or section variable names. + * + * @param string $file_name config file to get info for + * @param string $section_name (optional) section to get info for + * @return array an array of variables names from the specified file/section + */ + function get_var_names($file_name, $section = NULL) + { + if (empty($file_name)) { + $this->_trigger_error_msg('Empty config file name'); + return; + } else if (!isset($this->_config_data[$file_name])) { + $this->_trigger_error_msg("Unknown config file '$file_name'"); + return; + } + + if (empty($section)) + return array_keys($this->_config_data[$file_name]["vars"]); + else + return array_keys($this->_config_data[$file_name]["sections"][$section]["vars"]); + } + + + /** + * Clear loaded config data for a certain file or all files. + * + * @param string $file_name file to clear config data for + */ + function clear($file_name = NULL) + { + if ($file_name === NULL) + $this->_config_data = array(); + else if (isset($this->_config_data[$file_name])) + $this->_config_data[$file_name] = array(); + } + + + /** + * Load a configuration file manually. + * + * @param string $file_name file name to load + * @param boolean $prepend_path whether current config path should be + * prepended to the filename + */ + function load_file($file_name, $prepend_path = true) + { + if ($prepend_path && $this->_config_path != "") + $config_file = $this->_config_path . $file_name; + else + $config_file = $file_name; + + ini_set('track_errors', true); + $fp = @fopen($config_file, "r"); + if (!is_resource($fp)) { + $this->_trigger_error_msg("Could not open config file '$config_file'"); + return false; + } + + $contents = ($size = filesize($config_file)) ? fread($fp, $size) : ''; + fclose($fp); + + $this->_config_data[$config_file] = $this->parse_contents($contents); + return true; + } + + /** + * Store the contents of a file manually. + * + * @param string $config_file file name of the related contents + * @param string $contents the file-contents to parse + */ + function set_file_contents($config_file, $contents) + { + $this->_config_data[$config_file] = $this->parse_contents($contents); + return true; + } + + /** + * parse the source of a configuration file manually. + * + * @param string $contents the file-contents to parse + */ + function parse_contents($contents) + { + if($this->fix_newlines) { + // fix mac/dos formatted newlines + $contents = preg_replace('!\r\n?!', "\n", $contents); + } + + $config_data = array(); + $config_data['sections'] = array(); + $config_data['vars'] = array(); + + /* reference to fill with data */ + $vars =& $config_data['vars']; + + /* parse file line by line */ + preg_match_all('!^.*\r?\n?!m', $contents, $match); + $lines = $match[0]; + for ($i=0, $count=count($lines); $i<$count; $i++) { + $line = $lines[$i]; + if (empty($line)) continue; + + if ( substr($line, 0, 1) == '[' && preg_match('!^\[(.*?)\]!', $line, $match) ) { + /* section found */ + if (substr($match[1], 0, 1) == '.') { + /* hidden section */ + if ($this->read_hidden) { + $section_name = substr($match[1], 1); + } else { + /* break reference to $vars to ignore hidden section */ + unset($vars); + $vars = array(); + continue; + } + } else { + $section_name = $match[1]; + } + if (!isset($config_data['sections'][$section_name])) + $config_data['sections'][$section_name] = array('vars' => array()); + $vars =& $config_data['sections'][$section_name]['vars']; + continue; + } + + if (preg_match('/^\s*(\.?\w+)\s*=\s*(.*)/s', $line, $match)) { + /* variable found */ + $var_name = rtrim($match[1]); + if (strpos($match[2], '"""') === 0) { + /* handle multiline-value */ + $lines[$i] = substr($match[2], 3); + $var_value = ''; + while ($i<$count) { + if (($pos = strpos($lines[$i], '"""')) === false) { + $var_value .= $lines[$i++]; + } else { + /* end of multiline-value */ + $var_value .= substr($lines[$i], 0, $pos); + break; + } + } + $booleanize = false; + + } else { + /* handle simple value */ + $var_value = preg_replace('/^([\'"])(.*)\1$/', '\2', rtrim($match[2])); + $booleanize = $this->booleanize; + + } + $this->_set_config_var($vars, $var_name, $var_value, $booleanize); + } + /* else unparsable line / means it is a comment / means ignore it */ + } + return $config_data; + } + + /**#@+ @access private */ + /** + * @param array &$container + * @param string $var_name + * @param mixed $var_value + * @param boolean $booleanize determines whether $var_value is converted to + * to true/false + */ + function _set_config_var(&$container, $var_name, $var_value, $booleanize) + { + if (substr($var_name, 0, 1) == '.') { + if (!$this->read_hidden) + return; + else + $var_name = substr($var_name, 1); + } + + if (!preg_match("/^[a-zA-Z_]\w*$/", $var_name)) { + $this->_trigger_error_msg("Bad variable name '$var_name'"); + return; + } + + if ($booleanize) { + if (preg_match("/^(on|true|yes)$/i", $var_value)) + $var_value = true; + else if (preg_match("/^(off|false|no)$/i", $var_value)) + $var_value = false; + } + + if (!isset($container[$var_name]) || $this->overwrite) + $container[$var_name] = $var_value; + else { + settype($container[$var_name], 'array'); + $container[$var_name][] = $var_value; + } + } + + /** + * @uses trigger_error() creates a PHP warning/error + * @param string $error_msg + * @param integer $error_type one of + */ + function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING) + { + trigger_error("Config_File error: $error_msg", $error_type); + } + /**#@-*/ +} + +?> diff --git a/BSF/include/smarty/libs/Smarty.class.php b/BSF/include/smarty/libs/Smarty.class.php new file mode 100644 index 000000000..6b893dec8 --- /dev/null +++ b/BSF/include/smarty/libs/Smarty.class.php @@ -0,0 +1,1968 @@ + + * @author Andrei Zmievski + * @package Smarty + * @version 2.6.19 + */ + +/* $Id$ */ + +/** + * DIR_SEP isn't used anymore, but third party apps might + */ +if(!defined('DIR_SEP')) { + define('DIR_SEP', DIRECTORY_SEPARATOR); +} + +/** + * set SMARTY_DIR to absolute path to Smarty library files. + * if not defined, include_path will be used. Sets SMARTY_DIR only if user + * application has not already defined it. + */ + +if (!defined('SMARTY_DIR')) { + define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); +} + +if (!defined('SMARTY_CORE_DIR')) { + define('SMARTY_CORE_DIR', SMARTY_DIR . 'internals' . DIRECTORY_SEPARATOR); +} + +define('SMARTY_PHP_PASSTHRU', 0); +define('SMARTY_PHP_QUOTE', 1); +define('SMARTY_PHP_REMOVE', 2); +define('SMARTY_PHP_ALLOW', 3); + +/** + * @package Smarty + */ +class Smarty +{ + /**#@+ + * Smarty Configuration Section + */ + + /** + * The name of the directory where templates are located. + * + * @var string + */ + var $template_dir = 'templates'; + + /** + * The directory where compiled templates are located. + * + * @var string + */ + var $compile_dir = 'templates_c'; + + /** + * The directory where config files are located. + * + * @var string + */ + var $config_dir = 'configs'; + + /** + * An array of directories searched for plugins. + * + * @var array + */ + var $plugins_dir = array('plugins'); + + /** + * If debugging is enabled, a debug console window will display + * when the page loads (make sure your browser allows unrequested + * popup windows) + * + * @var boolean + */ + var $debugging = false; + + /** + * When set, smarty does uses this value as error_reporting-level. + * + * @var boolean + */ + var $error_reporting = null; + + /** + * This is the path to the debug console template. If not set, + * the default one will be used. + * + * @var string + */ + var $debug_tpl = ''; + + /** + * This determines if debugging is enable-able from the browser. + *
      + *
    • NONE => no debugging control allowed
    • + *
    • URL => enable debugging when SMARTY_DEBUG is found in the URL.
    • + *
    + * @link http://www.foo.dom/index.php?SMARTY_DEBUG + * @var string + */ + var $debugging_ctrl = 'NONE'; + + /** + * This tells Smarty whether to check for recompiling or not. Recompiling + * does not need to happen unless a template or config file is changed. + * Typically you enable this during development, and disable for + * production. + * + * @var boolean + */ + var $compile_check = true; + + /** + * This forces templates to compile every time. Useful for development + * or debugging. + * + * @var boolean + */ + var $force_compile = false; + + /** + * This enables template caching. + *
      + *
    • 0 = no caching
    • + *
    • 1 = use class cache_lifetime value
    • + *
    • 2 = use cache_lifetime in cache file
    • + *
    + * @var integer + */ + var $caching = 0; + + /** + * The name of the directory for cache files. + * + * @var string + */ + var $cache_dir = 'cache'; + + /** + * This is the number of seconds cached content will persist. + *
      + *
    • 0 = always regenerate cache
    • + *
    • -1 = never expires
    • + *
    + * + * @var integer + */ + var $cache_lifetime = 3600; + + /** + * Only used when $caching is enabled. If true, then If-Modified-Since headers + * are respected with cached content, and appropriate HTTP headers are sent. + * This way repeated hits to a cached page do not send the entire page to the + * client every time. + * + * @var boolean + */ + var $cache_modified_check = false; + + /** + * This determines how Smarty handles "" tags in templates. + * possible values: + *
      + *
    • SMARTY_PHP_PASSTHRU -> print tags as plain text
    • + *
    • SMARTY_PHP_QUOTE -> escape tags as entities
    • + *
    • SMARTY_PHP_REMOVE -> remove php tags
    • + *
    • SMARTY_PHP_ALLOW -> execute php tags
    • + *
    + * + * @var integer + */ + var $php_handling = SMARTY_PHP_PASSTHRU; + + /** + * This enables template security. When enabled, many things are restricted + * in the templates that normally would go unchecked. This is useful when + * untrusted parties are editing templates and you want a reasonable level + * of security. (no direct execution of PHP in templates for example) + * + * @var boolean + */ + var $security = false; + + /** + * This is the list of template directories that are considered secure. This + * is used only if {@link $security} is enabled. One directory per array + * element. {@link $template_dir} is in this list implicitly. + * + * @var array + */ + var $secure_dir = array(); + + /** + * These are the security settings for Smarty. They are used only when + * {@link $security} is enabled. + * + * @var array + */ + var $security_settings = array( + 'PHP_HANDLING' => false, + 'IF_FUNCS' => array('array', 'list', + 'isset', 'empty', + 'count', 'sizeof', + 'in_array', 'is_array', + 'true', 'false', 'null'), + 'INCLUDE_ANY' => false, + 'PHP_TAGS' => false, + 'MODIFIER_FUNCS' => array('count'), + 'ALLOW_CONSTANTS' => false + ); + + /** + * This is an array of directories where trusted php scripts reside. + * {@link $security} is disabled during their inclusion/execution. + * + * @var array + */ + var $trusted_dir = array(); + + /** + * The left delimiter used for the template tags. + * + * @var string + */ + var $left_delimiter = '{'; + + /** + * The right delimiter used for the template tags. + * + * @var string + */ + var $right_delimiter = '}'; + + /** + * The order in which request variables are registered, similar to + * variables_order in php.ini E = Environment, G = GET, P = POST, + * C = Cookies, S = Server + * + * @var string + */ + var $request_vars_order = 'EGPCS'; + + /** + * Indicates wether $HTTP_*_VARS[] (request_use_auto_globals=false) + * are uses as request-vars or $_*[]-vars. note: if + * request_use_auto_globals is true, then $request_vars_order has + * no effect, but the php-ini-value "gpc_order" + * + * @var boolean + */ + var $request_use_auto_globals = true; + + /** + * Set this if you want different sets of compiled files for the same + * templates. This is useful for things like different languages. + * Instead of creating separate sets of templates per language, you + * set different compile_ids like 'en' and 'de'. + * + * @var string + */ + var $compile_id = null; + + /** + * This tells Smarty whether or not to use sub dirs in the cache/ and + * templates_c/ directories. sub directories better organized, but + * may not work well with PHP safe mode enabled. + * + * @var boolean + * + */ + var $use_sub_dirs = false; + + /** + * This is a list of the modifiers to apply to all template variables. + * Put each modifier in a separate array element in the order you want + * them applied. example: array('escape:"htmlall"'); + * + * @var array + */ + var $default_modifiers = array(); + + /** + * This is the resource type to be used when not specified + * at the beginning of the resource path. examples: + * $smarty->display('file:index.tpl'); + * $smarty->display('db:index.tpl'); + * $smarty->display('index.tpl'); // will use default resource type + * {include file="file:index.tpl"} + * {include file="db:index.tpl"} + * {include file="index.tpl"} {* will use default resource type *} + * + * @var array + */ + var $default_resource_type = 'file'; + + /** + * The function used for cache file handling. If not set, built-in caching is used. + * + * @var null|string function name + */ + var $cache_handler_func = null; + + /** + * This indicates which filters are automatically loaded into Smarty. + * + * @var array array of filter names + */ + var $autoload_filters = array(); + + /**#@+ + * @var boolean + */ + /** + * This tells if config file vars of the same name overwrite each other or not. + * if disabled, same name variables are accumulated in an array. + */ + var $config_overwrite = true; + + /** + * This tells whether or not to automatically booleanize config file variables. + * If enabled, then the strings "on", "true", and "yes" are treated as boolean + * true, and "off", "false" and "no" are treated as boolean false. + */ + var $config_booleanize = true; + + /** + * This tells whether hidden sections [.foobar] are readable from the + * tempalates or not. Normally you would never allow this since that is + * the point behind hidden sections: the application can access them, but + * the templates cannot. + */ + var $config_read_hidden = false; + + /** + * This tells whether or not automatically fix newlines in config files. + * It basically converts \r (mac) or \r\n (dos) to \n + */ + var $config_fix_newlines = true; + /**#@-*/ + + /** + * If a template cannot be found, this PHP function will be executed. + * Useful for creating templates on-the-fly or other special action. + * + * @var string function name + */ + var $default_template_handler_func = ''; + + /** + * The file that contains the compiler class. This can a full + * pathname, or relative to the php_include path. + * + * @var string + */ + var $compiler_file = 'Smarty_Compiler.class.php'; + + /** + * The class used for compiling templates. + * + * @var string + */ + var $compiler_class = 'Smarty_Compiler'; + + /** + * The class used to load config vars. + * + * @var string + */ + var $config_class = 'Config_File'; + +/**#@+ + * END Smarty Configuration Section + * There should be no need to touch anything below this line. + * @access private + */ + /** + * where assigned template vars are kept + * + * @var array + */ + var $_tpl_vars = array(); + + /** + * stores run-time $smarty.* vars + * + * @var null|array + */ + var $_smarty_vars = null; + + /** + * keeps track of sections + * + * @var array + */ + var $_sections = array(); + + /** + * keeps track of foreach blocks + * + * @var array + */ + var $_foreach = array(); + + /** + * keeps track of tag hierarchy + * + * @var array + */ + var $_tag_stack = array(); + + /** + * configuration object + * + * @var Config_file + */ + var $_conf_obj = null; + + /** + * loaded configuration settings + * + * @var array + */ + var $_config = array(array('vars' => array(), 'files' => array())); + + /** + * md5 checksum of the string 'Smarty' + * + * @var string + */ + var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; + + /** + * Smarty version number + * + * @var string + */ + var $_version = '2.6.19'; + + /** + * current template inclusion depth + * + * @var integer + */ + var $_inclusion_depth = 0; + + /** + * for different compiled templates + * + * @var string + */ + var $_compile_id = null; + + /** + * text in URL to enable debug mode + * + * @var string + */ + var $_smarty_debug_id = 'SMARTY_DEBUG'; + + /** + * debugging information for debug console + * + * @var array + */ + var $_smarty_debug_info = array(); + + /** + * info that makes up a cache file + * + * @var array + */ + var $_cache_info = array(); + + /** + * default file permissions + * + * @var integer + */ + var $_file_perms = 0644; + + /** + * default dir permissions + * + * @var integer + */ + var $_dir_perms = 0771; + + /** + * registered objects + * + * @var array + */ + var $_reg_objects = array(); + + /** + * table keeping track of plugins + * + * @var array + */ + var $_plugins = array( + 'modifier' => array(), + 'function' => array(), + 'block' => array(), + 'compiler' => array(), + 'prefilter' => array(), + 'postfilter' => array(), + 'outputfilter' => array(), + 'resource' => array(), + 'insert' => array()); + + + /** + * cache serials + * + * @var array + */ + var $_cache_serials = array(); + + /** + * name of optional cache include file + * + * @var string + */ + var $_cache_include = null; + + /** + * indicate if the current code is used in a compiled + * include + * + * @var string + */ + var $_cache_including = false; + + /**#@-*/ + /** + * The class constructor. + */ + function Smarty() + { + $this->assign('SCRIPT_NAME', isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] + : @$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_NAME']); + } + + /** + * assigns values to template variables + * + * @param array|string $tpl_var the template variable name(s) + * @param mixed $value the value to assign + */ + function assign($tpl_var, $value = null) + { + if (is_array($tpl_var)){ + foreach ($tpl_var as $key => $val) { + if ($key != '') { + $this->_tpl_vars[$key] = $val; + } + } + } else { + if ($tpl_var != '') + $this->_tpl_vars[$tpl_var] = $value; + } + } + + /** + * assigns values to template variables by reference + * + * @param string $tpl_var the template variable name + * @param mixed $value the referenced value to assign + */ + function assign_by_ref($tpl_var, &$value) + { + if ($tpl_var != '') + $this->_tpl_vars[$tpl_var] = &$value; + } + + /** + * appends values to template variables + * + * @param array|string $tpl_var the template variable name(s) + * @param mixed $value the value to append + */ + function append($tpl_var, $value=null, $merge=false) + { + if (is_array($tpl_var)) { + // $tpl_var is an array, ignore $value + foreach ($tpl_var as $_key => $_val) { + if ($_key != '') { + if(!@is_array($this->_tpl_vars[$_key])) { + settype($this->_tpl_vars[$_key],'array'); + } + if($merge && is_array($_val)) { + foreach($_val as $_mkey => $_mval) { + $this->_tpl_vars[$_key][$_mkey] = $_mval; + } + } else { + $this->_tpl_vars[$_key][] = $_val; + } + } + } + } else { + if ($tpl_var != '' && isset($value)) { + if(!@is_array($this->_tpl_vars[$tpl_var])) { + settype($this->_tpl_vars[$tpl_var],'array'); + } + if($merge && is_array($value)) { + foreach($value as $_mkey => $_mval) { + $this->_tpl_vars[$tpl_var][$_mkey] = $_mval; + } + } else { + $this->_tpl_vars[$tpl_var][] = $value; + } + } + } + } + + /** + * appends values to template variables by reference + * + * @param string $tpl_var the template variable name + * @param mixed $value the referenced value to append + */ + function append_by_ref($tpl_var, &$value, $merge=false) + { + if ($tpl_var != '' && isset($value)) { + if(!@is_array($this->_tpl_vars[$tpl_var])) { + settype($this->_tpl_vars[$tpl_var],'array'); + } + if ($merge && is_array($value)) { + foreach($value as $_key => $_val) { + $this->_tpl_vars[$tpl_var][$_key] = &$value[$_key]; + } + } else { + $this->_tpl_vars[$tpl_var][] = &$value; + } + } + } + + + /** + * clear the given assigned template variable. + * + * @param string $tpl_var the template variable to clear + */ + function clear_assign($tpl_var) + { + if (is_array($tpl_var)) + foreach ($tpl_var as $curr_var) + unset($this->_tpl_vars[$curr_var]); + else + unset($this->_tpl_vars[$tpl_var]); + } + + + /** + * Registers custom function to be used in templates + * + * @param string $function the name of the template function + * @param string $function_impl the name of the PHP function to register + */ + function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null) + { + $this->_plugins['function'][$function] = + array($function_impl, null, null, false, $cacheable, $cache_attrs); + + } + + /** + * Unregisters custom function + * + * @param string $function name of template function + */ + function unregister_function($function) + { + unset($this->_plugins['function'][$function]); + } + + /** + * Registers object to be used in templates + * + * @param string $object name of template object + * @param object &$object_impl the referenced PHP object to register + * @param null|array $allowed list of allowed methods (empty = all) + * @param boolean $smarty_args smarty argument format, else traditional + * @param null|array $block_functs list of methods that are block format + */ + function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) + { + settype($allowed, 'array'); + settype($smarty_args, 'boolean'); + $this->_reg_objects[$object] = + array(&$object_impl, $allowed, $smarty_args, $block_methods); + } + + /** + * Unregisters object + * + * @param string $object name of template object + */ + function unregister_object($object) + { + unset($this->_reg_objects[$object]); + } + + + /** + * Registers block function to be used in templates + * + * @param string $block name of template block + * @param string $block_impl PHP function to register + */ + function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null) + { + $this->_plugins['block'][$block] = + array($block_impl, null, null, false, $cacheable, $cache_attrs); + } + + /** + * Unregisters block function + * + * @param string $block name of template function + */ + function unregister_block($block) + { + unset($this->_plugins['block'][$block]); + } + + /** + * Registers compiler function + * + * @param string $function name of template function + * @param string $function_impl name of PHP function to register + */ + function register_compiler_function($function, $function_impl, $cacheable=true) + { + $this->_plugins['compiler'][$function] = + array($function_impl, null, null, false, $cacheable); + } + + /** + * Unregisters compiler function + * + * @param string $function name of template function + */ + function unregister_compiler_function($function) + { + unset($this->_plugins['compiler'][$function]); + } + + /** + * Registers modifier to be used in templates + * + * @param string $modifier name of template modifier + * @param string $modifier_impl name of PHP function to register + */ + function register_modifier($modifier, $modifier_impl) + { + $this->_plugins['modifier'][$modifier] = + array($modifier_impl, null, null, false); + } + + /** + * Unregisters modifier + * + * @param string $modifier name of template modifier + */ + function unregister_modifier($modifier) + { + unset($this->_plugins['modifier'][$modifier]); + } + + /** + * Registers a resource to fetch a template + * + * @param string $type name of resource + * @param array $functions array of functions to handle resource + */ + function register_resource($type, $functions) + { + if (count($functions)==4) { + $this->_plugins['resource'][$type] = + array($functions, false); + + } elseif (count($functions)==5) { + $this->_plugins['resource'][$type] = + array(array(array(&$functions[0], $functions[1]) + ,array(&$functions[0], $functions[2]) + ,array(&$functions[0], $functions[3]) + ,array(&$functions[0], $functions[4])) + ,false); + + } else { + $this->trigger_error("malformed function-list for '$type' in register_resource"); + + } + } + + /** + * Unregisters a resource + * + * @param string $type name of resource + */ + function unregister_resource($type) + { + unset($this->_plugins['resource'][$type]); + } + + /** + * Registers a prefilter function to apply + * to a template before compiling + * + * @param callback $function + */ + function register_prefilter($function) + { + $this->_plugins['prefilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters a prefilter function + * + * @param callback $function + */ + function unregister_prefilter($function) + { + unset($this->_plugins['prefilter'][$this->_get_filter_name($function)]); + } + + /** + * Registers a postfilter function to apply + * to a compiled template after compilation + * + * @param callback $function + */ + function register_postfilter($function) + { + $this->_plugins['postfilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters a postfilter function + * + * @param callback $function + */ + function unregister_postfilter($function) + { + unset($this->_plugins['postfilter'][$this->_get_filter_name($function)]); + } + + /** + * Registers an output filter function to apply + * to a template output + * + * @param callback $function + */ + function register_outputfilter($function) + { + $this->_plugins['outputfilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters an outputfilter function + * + * @param callback $function + */ + function unregister_outputfilter($function) + { + unset($this->_plugins['outputfilter'][$this->_get_filter_name($function)]); + } + + /** + * load a filter of specified type and name + * + * @param string $type filter type + * @param string $name filter name + */ + function load_filter($type, $name) + { + switch ($type) { + case 'output': + $_params = array('plugins' => array(array($type . 'filter', $name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + break; + + case 'pre': + case 'post': + if (!isset($this->_plugins[$type . 'filter'][$name])) + $this->_plugins[$type . 'filter'][$name] = false; + break; + } + } + + /** + * clear cached content for the given template and cache id + * + * @param string $tpl_file name of template file + * @param string $cache_id name of cache_id + * @param string $compile_id name of compile_id + * @param string $exp_time expiration time + * @return boolean + */ + function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null) + { + + if (!isset($compile_id)) + $compile_id = $this->compile_id; + + if (!isset($tpl_file)) + $compile_id = null; + + $_auto_id = $this->_get_auto_id($cache_id, $compile_id); + + if (!empty($this->cache_handler_func)) { + return call_user_func_array($this->cache_handler_func, + array('clear', &$this, &$dummy, $tpl_file, $cache_id, $compile_id, $exp_time)); + } else { + $_params = array('auto_base' => $this->cache_dir, + 'auto_source' => $tpl_file, + 'auto_id' => $_auto_id, + 'exp_time' => $exp_time); + require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + + } + + + /** + * clear the entire contents of cache (all templates) + * + * @param string $exp_time expire time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + function clear_all_cache($exp_time = null) + { + return $this->clear_cache(null, null, null, $exp_time); + } + + + /** + * test to see if valid cache exists for this template + * + * @param string $tpl_file name of template file + * @param string $cache_id + * @param string $compile_id + * @return string|false results of {@link _read_cache_file()} + */ + function is_cached($tpl_file, $cache_id = null, $compile_id = null) + { + if (!$this->caching) + return false; + + if (!isset($compile_id)) + $compile_id = $this->compile_id; + + $_params = array( + 'tpl_file' => $tpl_file, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id + ); + require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); + return smarty_core_read_cache_file($_params, $this); + } + + + /** + * clear all the assigned template variables. + * + */ + function clear_all_assign() + { + $this->_tpl_vars = array(); + } + + /** + * clears compiled version of specified template resource, + * or all compiled template files if one is not specified. + * This function is for advanced use only, not normally needed. + * + * @param string $tpl_file + * @param string $compile_id + * @param string $exp_time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null) + { + if (!isset($compile_id)) { + $compile_id = $this->compile_id; + } + $_params = array('auto_base' => $this->compile_dir, + 'auto_source' => $tpl_file, + 'auto_id' => $compile_id, + 'exp_time' => $exp_time, + 'extensions' => array('.inc', '.php')); + require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + + /** + * Checks whether requested template exists. + * + * @param string $tpl_file + * @return boolean + */ + function template_exists($tpl_file) + { + $_params = array('resource_name' => $tpl_file, 'quiet'=>true, 'get_source'=>false); + return $this->_fetch_resource_info($_params); + } + + /** + * Returns an array containing template variables + * + * @param string $name + * @param string $type + * @return array + */ + function &get_template_vars($name=null) + { + if(!isset($name)) { + return $this->_tpl_vars; + } elseif(isset($this->_tpl_vars[$name])) { + return $this->_tpl_vars[$name]; + } else { + // var non-existant, return valid reference + $_tmp = null; + return $_tmp; + } + } + + /** + * Returns an array containing config variables + * + * @param string $name + * @param string $type + * @return array + */ + function &get_config_vars($name=null) + { + if(!isset($name) && is_array($this->_config[0])) { + return $this->_config[0]['vars']; + } else if(isset($this->_config[0]['vars'][$name])) { + return $this->_config[0]['vars'][$name]; + } else { + // var non-existant, return valid reference + $_tmp = null; + return $_tmp; + } + } + + /** + * trigger Smarty error + * + * @param string $error_msg + * @param integer $error_type + */ + function trigger_error($error_msg, $error_type = E_USER_WARNING) + { + trigger_error("Smarty error: $error_msg", $error_type); + } + + + /** + * executes & displays the template results + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + */ + function display($resource_name, $cache_id = null, $compile_id = null) + { + $this->fetch($resource_name, $cache_id, $compile_id, true); + } + + /** + * executes & returns or displays the template results + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + * @param boolean $display + */ + function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false) + { + static $_cache_info = array(); + + $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting) + ? $this->error_reporting : error_reporting() & ~E_NOTICE); + + if (!$this->debugging && $this->debugging_ctrl == 'URL') { + $_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']; + if (@strstr($_query_string, $this->_smarty_debug_id)) { + if (@strstr($_query_string, $this->_smarty_debug_id . '=on')) { + // enable debugging for this browser session + @setcookie('SMARTY_DEBUG', true); + $this->debugging = true; + } elseif (@strstr($_query_string, $this->_smarty_debug_id . '=off')) { + // disable debugging for this browser session + @setcookie('SMARTY_DEBUG', false); + $this->debugging = false; + } else { + // enable debugging for this page + $this->debugging = true; + } + } else { + $this->debugging = (bool)($this->request_use_auto_globals ? @$_COOKIE['SMARTY_DEBUG'] : @$GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG']); + } + } + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $_debug_start_time = smarty_core_get_microtime($_params, $this); + $this->_smarty_debug_info[] = array('type' => 'template', + 'filename' => $resource_name, + 'depth' => 0); + $_included_tpls_idx = count($this->_smarty_debug_info) - 1; + } + + if (!isset($compile_id)) { + $compile_id = $this->compile_id; + } + + $this->_compile_id = $compile_id; + $this->_inclusion_depth = 0; + + if ($this->caching) { + // save old cache_info, initialize cache_info + array_push($_cache_info, $this->_cache_info); + $this->_cache_info = array(); + $_params = array( + 'tpl_file' => $resource_name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'results' => null + ); + require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); + if (smarty_core_read_cache_file($_params, $this)) { + $_smarty_results = $_params['results']; + if (!empty($this->_cache_info['insert_tags'])) { + $_params = array('plugins' => $this->_cache_info['insert_tags']); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + $_params = array('results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); + $_smarty_results = smarty_core_process_cached_inserts($_params, $this); + } + if (!empty($this->_cache_info['cache_serials'])) { + $_params = array('results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.process_compiled_include.php'); + $_smarty_results = smarty_core_process_compiled_include($_params, $this); + } + + + if ($display) { + if ($this->debugging) + { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $_debug_start_time; + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + $_smarty_results .= smarty_core_display_debug_console($_params, $this); + } + if ($this->cache_modified_check) { + $_server_vars = ($this->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; + $_last_modified_date = @substr($_server_vars['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_server_vars['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3); + $_gmt_mtime = gmdate('D, d M Y H:i:s', $this->_cache_info['timestamp']).' GMT'; + if (@count($this->_cache_info['insert_tags']) == 0 + && !$this->_cache_serials + && $_gmt_mtime == $_last_modified_date) { + if (php_sapi_name()=='cgi') + header('Status: 304 Not Modified'); + else + header('HTTP/1.1 304 Not Modified'); + + } else { + header('Last-Modified: '.$_gmt_mtime); + echo $_smarty_results; + } + } else { + echo $_smarty_results; + } + error_reporting($_smarty_old_error_level); + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + return true; + } else { + error_reporting($_smarty_old_error_level); + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + return $_smarty_results; + } + } else { + $this->_cache_info['template'][$resource_name] = true; + if ($this->cache_modified_check && $display) { + header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT'); + } + } + } + + // load filters that are marked as autoload + if (count($this->autoload_filters)) { + foreach ($this->autoload_filters as $_filter_type => $_filters) { + foreach ($_filters as $_filter) { + $this->load_filter($_filter_type, $_filter); + } + } + } + + $_smarty_compile_path = $this->_get_compile_path($resource_name); + + // if we just need to display the results, don't perform output + // buffering - for speed + $_cache_including = $this->_cache_including; + $this->_cache_including = false; + if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) { + if ($this->_is_compiled($resource_name, $_smarty_compile_path) + || $this->_compile_resource($resource_name, $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + } else { + ob_start(); + if ($this->_is_compiled($resource_name, $_smarty_compile_path) + || $this->_compile_resource($resource_name, $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + $_smarty_results = ob_get_contents(); + ob_end_clean(); + + foreach ((array)$this->_plugins['outputfilter'] as $_output_filter) { + $_smarty_results = call_user_func_array($_output_filter[0], array($_smarty_results, &$this)); + } + } + + if ($this->caching) { + $_params = array('tpl_file' => $resource_name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php'); + smarty_core_write_cache_file($_params, $this); + require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); + $_smarty_results = smarty_core_process_cached_inserts($_params, $this); + + if ($this->_cache_serials) { + // strip nocache-tags from output + $_smarty_results = preg_replace('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!s' + ,'' + ,$_smarty_results); + } + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + } + $this->_cache_including = $_cache_including; + + if ($display) { + if (isset($_smarty_results)) { echo $_smarty_results; } + } + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = (smarty_core_get_microtime($_params, $this) - $_debug_start_time); + } + + if ($display) { + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + echo smarty_core_display_debug_console($_params, $this); + } + error_reporting($_smarty_old_error_level); + return; + } else { + error_reporting($_smarty_old_error_level); + if (isset($_smarty_results)) { return $_smarty_results; } + } + } + + /** + * load configuration values + * + * @param string $file + * @param string $section + * @param string $scope + */ + function config_load($file, $section = null, $scope = 'global') + { + require_once($this->_get_plugin_filepath('function', 'config_load')); + smarty_function_config_load(array('file' => $file, 'section' => $section, 'scope' => $scope), $this); + } + + /** + * return a reference to a registered object + * + * @param string $name + * @return object + */ + function &get_registered_object($name) { + if (!isset($this->_reg_objects[$name])) + $this->_trigger_fatal_error("'$name' is not a registered object"); + + if (!is_object($this->_reg_objects[$name][0])) + $this->_trigger_fatal_error("registered '$name' is not an object"); + + return $this->_reg_objects[$name][0]; + } + + /** + * clear configuration values + * + * @param string $var + */ + function clear_config($var = null) + { + if(!isset($var)) { + // clear all values + $this->_config = array(array('vars' => array(), + 'files' => array())); + } else { + unset($this->_config[0]['vars'][$var]); + } + } + + /** + * get filepath of requested plugin + * + * @param string $type + * @param string $name + * @return string|false + */ + function _get_plugin_filepath($type, $name) + { + $_params = array('type' => $type, 'name' => $name); + require_once(SMARTY_CORE_DIR . 'core.assemble_plugin_filepath.php'); + return smarty_core_assemble_plugin_filepath($_params, $this); + } + + /** + * test if resource needs compiling + * + * @param string $resource_name + * @param string $compile_path + * @return boolean + */ + function _is_compiled($resource_name, $compile_path) + { + if (!$this->force_compile && file_exists($compile_path)) { + if (!$this->compile_check) { + // no need to check compiled file + return true; + } else { + // get file source and timestamp + $_params = array('resource_name' => $resource_name, 'get_source'=>false); + if (!$this->_fetch_resource_info($_params)) { + return false; + } + if ($_params['resource_timestamp'] <= filemtime($compile_path)) { + // template not expired, no recompile + return true; + } else { + // compile template + return false; + } + } + } else { + // compiled template does not exist, or forced compile + return false; + } + } + + /** + * compile the template + * + * @param string $resource_name + * @param string $compile_path + * @return boolean + */ + function _compile_resource($resource_name, $compile_path) + { + + $_params = array('resource_name' => $resource_name); + if (!$this->_fetch_resource_info($_params)) { + return false; + } + + $_source_content = $_params['source_content']; + $_cache_include = substr($compile_path, 0, -4).'.inc'; + + if ($this->_compile_source($resource_name, $_source_content, $_compiled_content, $_cache_include)) { + // if a _cache_serial was set, we also have to write an include-file: + if ($this->_cache_include_info) { + require_once(SMARTY_CORE_DIR . 'core.write_compiled_include.php'); + smarty_core_write_compiled_include(array_merge($this->_cache_include_info, array('compiled_content'=>$_compiled_content, 'resource_name'=>$resource_name)), $this); + } + + $_params = array('compile_path'=>$compile_path, 'compiled_content' => $_compiled_content); + require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); + smarty_core_write_compiled_resource($_params, $this); + + return true; + } else { + return false; + } + + } + + /** + * compile the given source + * + * @param string $resource_name + * @param string $source_content + * @param string $compiled_content + * @return boolean + */ + function _compile_source($resource_name, &$source_content, &$compiled_content, $cache_include_path=null) + { + if (file_exists(SMARTY_DIR . $this->compiler_file)) { + require_once(SMARTY_DIR . $this->compiler_file); + } else { + // use include_path + require_once($this->compiler_file); + } + + + $smarty_compiler = new $this->compiler_class; + + $smarty_compiler->template_dir = $this->template_dir; + $smarty_compiler->compile_dir = $this->compile_dir; + $smarty_compiler->plugins_dir = $this->plugins_dir; + $smarty_compiler->config_dir = $this->config_dir; + $smarty_compiler->force_compile = $this->force_compile; + $smarty_compiler->caching = $this->caching; + $smarty_compiler->php_handling = $this->php_handling; + $smarty_compiler->left_delimiter = $this->left_delimiter; + $smarty_compiler->right_delimiter = $this->right_delimiter; + $smarty_compiler->_version = $this->_version; + $smarty_compiler->security = $this->security; + $smarty_compiler->secure_dir = $this->secure_dir; + $smarty_compiler->security_settings = $this->security_settings; + $smarty_compiler->trusted_dir = $this->trusted_dir; + $smarty_compiler->use_sub_dirs = $this->use_sub_dirs; + $smarty_compiler->_reg_objects = &$this->_reg_objects; + $smarty_compiler->_plugins = &$this->_plugins; + $smarty_compiler->_tpl_vars = &$this->_tpl_vars; + $smarty_compiler->default_modifiers = $this->default_modifiers; + $smarty_compiler->compile_id = $this->_compile_id; + $smarty_compiler->_config = $this->_config; + $smarty_compiler->request_use_auto_globals = $this->request_use_auto_globals; + + if (isset($cache_include_path) && isset($this->_cache_serials[$cache_include_path])) { + $smarty_compiler->_cache_serial = $this->_cache_serials[$cache_include_path]; + } + $smarty_compiler->_cache_include = $cache_include_path; + + + $_results = $smarty_compiler->_compile_file($resource_name, $source_content, $compiled_content); + + if ($smarty_compiler->_cache_serial) { + $this->_cache_include_info = array( + 'cache_serial'=>$smarty_compiler->_cache_serial + ,'plugins_code'=>$smarty_compiler->_plugins_code + ,'include_file_path' => $cache_include_path); + + } else { + $this->_cache_include_info = null; + + } + + return $_results; + } + + /** + * Get the compile path for this resource + * + * @param string $resource_name + * @return string results of {@link _get_auto_filename()} + */ + function _get_compile_path($resource_name) + { + return $this->_get_auto_filename($this->compile_dir, $resource_name, + $this->_compile_id) . '.php'; + } + + /** + * fetch the template info. Gets timestamp, and source + * if get_source is true + * + * sets $source_content to the source of the template, and + * $resource_timestamp to its time stamp + * @param string $resource_name + * @param string $source_content + * @param integer $resource_timestamp + * @param boolean $get_source + * @param boolean $quiet + * @return boolean + */ + + function _fetch_resource_info(&$params) + { + if(!isset($params['get_source'])) { $params['get_source'] = true; } + if(!isset($params['quiet'])) { $params['quiet'] = false; } + + $_return = false; + $_params = array('resource_name' => $params['resource_name']) ; + if (isset($params['resource_base_path'])) + $_params['resource_base_path'] = $params['resource_base_path']; + else + $_params['resource_base_path'] = $this->template_dir; + + if ($this->_parse_resource_name($_params)) { + $_resource_type = $_params['resource_type']; + $_resource_name = $_params['resource_name']; + switch ($_resource_type) { + case 'file': + if ($params['get_source']) { + $params['source_content'] = $this->_read_file($_resource_name); + } + $params['resource_timestamp'] = filemtime($_resource_name); + $_return = is_file($_resource_name); + break; + + default: + // call resource functions to fetch the template source and timestamp + if ($params['get_source']) { + $_source_return = isset($this->_plugins['resource'][$_resource_type]) && + call_user_func_array($this->_plugins['resource'][$_resource_type][0][0], + array($_resource_name, &$params['source_content'], &$this)); + } else { + $_source_return = true; + } + + $_timestamp_return = isset($this->_plugins['resource'][$_resource_type]) && + call_user_func_array($this->_plugins['resource'][$_resource_type][0][1], + array($_resource_name, &$params['resource_timestamp'], &$this)); + + $_return = $_source_return && $_timestamp_return; + break; + } + } + + if (!$_return) { + // see if we can get a template with the default template handler + if (!empty($this->default_template_handler_func)) { + if (!is_callable($this->default_template_handler_func)) { + $this->trigger_error("default template handler function \"$this->default_template_handler_func\" doesn't exist."); + } else { + $_return = call_user_func_array( + $this->default_template_handler_func, + array($_params['resource_type'], $_params['resource_name'], &$params['source_content'], &$params['resource_timestamp'], &$this)); + } + } + } + + if (!$_return) { + if (!$params['quiet']) { + $this->trigger_error('unable to read resource: "' . $params['resource_name'] . '"'); + } + } else if ($_return && $this->security) { + require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); + if (!smarty_core_is_secure($_params, $this)) { + if (!$params['quiet']) + $this->trigger_error('(secure mode) accessing "' . $params['resource_name'] . '" is not allowed'); + $params['source_content'] = null; + $params['resource_timestamp'] = null; + return false; + } + } + return $_return; + } + + + /** + * parse out the type and name from the resource + * + * @param string $resource_base_path + * @param string $resource_name + * @param string $resource_type + * @param string $resource_name + * @return boolean + */ + + function _parse_resource_name(&$params) + { + + // split tpl_path by the first colon + $_resource_name_parts = explode(':', $params['resource_name'], 2); + + if (count($_resource_name_parts) == 1) { + // no resource type given + $params['resource_type'] = $this->default_resource_type; + $params['resource_name'] = $_resource_name_parts[0]; + } else { + if(strlen($_resource_name_parts[0]) == 1) { + // 1 char is not resource type, but part of filepath + $params['resource_type'] = $this->default_resource_type; + $params['resource_name'] = $params['resource_name']; + } else { + $params['resource_type'] = $_resource_name_parts[0]; + $params['resource_name'] = $_resource_name_parts[1]; + } + } + + if ($params['resource_type'] == 'file') { + if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $params['resource_name'])) { + // relative pathname to $params['resource_base_path'] + // use the first directory where the file is found + foreach ((array)$params['resource_base_path'] as $_curr_path) { + $_fullpath = $_curr_path . DIRECTORY_SEPARATOR . $params['resource_name']; + if (file_exists($_fullpath) && is_file($_fullpath)) { + $params['resource_name'] = $_fullpath; + return true; + } + // didn't find the file, try include_path + $_params = array('file_path' => $_fullpath); + require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $this)) { + $params['resource_name'] = $_params['new_file_path']; + return true; + } + } + return false; + } else { + /* absolute path */ + return file_exists($params['resource_name']); + } + } elseif (empty($this->_plugins['resource'][$params['resource_type']])) { + $_params = array('type' => $params['resource_type']); + require_once(SMARTY_CORE_DIR . 'core.load_resource_plugin.php'); + smarty_core_load_resource_plugin($_params, $this); + } + + return true; + } + + + /** + * Handle modifiers + * + * @param string|null $modifier_name + * @param array|null $map_array + * @return string result of modifiers + */ + function _run_mod_handler() + { + $_args = func_get_args(); + list($_modifier_name, $_map_array) = array_splice($_args, 0, 2); + list($_func_name, $_tpl_file, $_tpl_line) = + $this->_plugins['modifier'][$_modifier_name]; + + $_var = $_args[0]; + foreach ($_var as $_key => $_val) { + $_args[0] = $_val; + $_var[$_key] = call_user_func_array($_func_name, $_args); + } + return $_var; + } + + /** + * Remove starting and ending quotes from the string + * + * @param string $string + * @return string + */ + function _dequote($string) + { + if ((substr($string, 0, 1) == "'" || substr($string, 0, 1) == '"') && + substr($string, -1) == substr($string, 0, 1)) + return substr($string, 1, -1); + else + return $string; + } + + + /** + * read in a file + * + * @param string $filename + * @return string + */ + function _read_file($filename) + { + if ( file_exists($filename) && ($fd = @fopen($filename, 'rb')) ) { + $contents = ''; + while (!feof($fd)) { + $contents .= fread($fd, 8192); + } + fclose($fd); + return $contents; + } else { + return false; + } + } + + /** + * get a concrete filename for automagically created content + * + * @param string $auto_base + * @param string $auto_source + * @param string $auto_id + * @return string + * @staticvar string|null + * @staticvar string|null + */ + function _get_auto_filename($auto_base, $auto_source = null, $auto_id = null) + { + $_compile_dir_sep = $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'; + $_return = $auto_base . DIRECTORY_SEPARATOR; + + if(isset($auto_id)) { + // make auto_id safe for directory names + $auto_id = str_replace('%7C',$_compile_dir_sep,(urlencode($auto_id))); + // split into separate directories + $_return .= $auto_id . $_compile_dir_sep; + } + + if(isset($auto_source)) { + // make source name safe for filename + $_filename = urlencode(basename($auto_source)); + $_crc32 = sprintf('%08X', crc32($auto_source)); + // prepend %% to avoid name conflicts with + // with $params['auto_id'] names + $_crc32 = substr($_crc32, 0, 2) . $_compile_dir_sep . + substr($_crc32, 0, 3) . $_compile_dir_sep . $_crc32; + $_return .= '%%' . $_crc32 . '%%' . $_filename; + } + + return $_return; + } + + /** + * unlink a file, possibly using expiration time + * + * @param string $resource + * @param integer $exp_time + */ + function _unlink($resource, $exp_time = null) + { + if(isset($exp_time)) { + if(time() - @filemtime($resource) >= $exp_time) { + return @unlink($resource); + } + } else { + return @unlink($resource); + } + } + + /** + * returns an auto_id for auto-file-functions + * + * @param string $cache_id + * @param string $compile_id + * @return string|null + */ + function _get_auto_id($cache_id=null, $compile_id=null) { + if (isset($cache_id)) + return (isset($compile_id)) ? $cache_id . '|' . $compile_id : $cache_id; + elseif(isset($compile_id)) + return $compile_id; + else + return null; + } + + /** + * trigger Smarty plugin error + * + * @param string $error_msg + * @param string $tpl_file + * @param integer $tpl_line + * @param string $file + * @param integer $line + * @param integer $error_type + */ + function _trigger_fatal_error($error_msg, $tpl_file = null, $tpl_line = null, + $file = null, $line = null, $error_type = E_USER_ERROR) + { + if(isset($file) && isset($line)) { + $info = ' ('.basename($file).", line $line)"; + } else { + $info = ''; + } + if (isset($tpl_line) && isset($tpl_file)) { + $this->trigger_error('[in ' . $tpl_file . ' line ' . $tpl_line . "]: $error_msg$info", $error_type); + } else { + $this->trigger_error($error_msg . $info, $error_type); + } + } + + + /** + * callback function for preg_replace, to call a non-cacheable block + * @return string + */ + function _process_compiled_include_callback($match) { + $_func = '_smarty_tplfunc_'.$match[2].'_'.$match[3]; + ob_start(); + $_func($this); + $_ret = ob_get_contents(); + ob_end_clean(); + return $_ret; + } + + + /** + * called for included templates + * + * @param string $_smarty_include_tpl_file + * @param string $_smarty_include_vars + */ + + // $_smarty_include_tpl_file, $_smarty_include_vars + + function _smarty_include($params) + { + if ($this->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $debug_start_time = smarty_core_get_microtime($_params, $this); + $this->_smarty_debug_info[] = array('type' => 'template', + 'filename' => $params['smarty_include_tpl_file'], + 'depth' => ++$this->_inclusion_depth); + $included_tpls_idx = count($this->_smarty_debug_info) - 1; + } + + $this->_tpl_vars = array_merge($this->_tpl_vars, $params['smarty_include_vars']); + + // config vars are treated as local, so push a copy of the + // current ones onto the front of the stack + array_unshift($this->_config, $this->_config[0]); + + $_smarty_compile_path = $this->_get_compile_path($params['smarty_include_tpl_file']); + + + if ($this->_is_compiled($params['smarty_include_tpl_file'], $_smarty_compile_path) + || $this->_compile_resource($params['smarty_include_tpl_file'], $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + + // pop the local vars off the front of the stack + array_shift($this->_config); + + $this->_inclusion_depth--; + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $debug_start_time; + } + + if ($this->caching) { + $this->_cache_info['template'][$params['smarty_include_tpl_file']] = true; + } + } + + + /** + * get or set an array of cached attributes for function that is + * not cacheable + * @return array + */ + function &_smarty_cache_attrs($cache_serial, $count) { + $_cache_attrs =& $this->_cache_info['cache_attrs'][$cache_serial][$count]; + + if ($this->_cache_including) { + /* return next set of cache_attrs */ + $_return = current($_cache_attrs); + next($_cache_attrs); + return $_return; + + } else { + /* add a reference to a new set of cache_attrs */ + $_cache_attrs[] = array(); + return $_cache_attrs[count($_cache_attrs)-1]; + + } + + } + + + /** + * wrapper for include() retaining $this + * @return mixed + */ + function _include($filename, $once=false, $params=null) + { + if ($once) { + return include_once($filename); + } else { + return include($filename); + } + } + + + /** + * wrapper for eval() retaining $this + * @return mixed + */ + function _eval($code, $params=null) + { + return eval($code); + } + + /** + * Extracts the filter name from the given callback + * + * @param callback $function + * @return string + */ + function _get_filter_name($function) + { + if (is_array($function)) { + $_class_name = (is_object($function[0]) ? + get_class($function[0]) : $function[0]); + return $_class_name . '_' . $function[1]; + } + else { + return $function; + } + } + + /**#@-*/ + +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/Smarty_Compiler.class.php b/BSF/include/smarty/libs/Smarty_Compiler.class.php new file mode 100644 index 000000000..d5f877f7b --- /dev/null +++ b/BSF/include/smarty/libs/Smarty_Compiler.class.php @@ -0,0 +1,2325 @@ + + * @author Andrei Zmievski + * @version 2.6.19 + * @copyright 2001-2005 New Digital Group, Inc. + * @package Smarty + */ + +/* $Id$ */ + +/** + * Template compiling class + * @package Smarty + */ +class Smarty_Compiler extends Smarty { + + // internal vars + /**#@+ + * @access private + */ + var $_folded_blocks = array(); // keeps folded template blocks + var $_current_file = null; // the current template being compiled + var $_current_line_no = 1; // line number for error messages + var $_capture_stack = array(); // keeps track of nested capture buffers + var $_plugin_info = array(); // keeps track of plugins to load + var $_init_smarty_vars = false; + var $_permitted_tokens = array('true','false','yes','no','on','off','null'); + var $_db_qstr_regexp = null; // regexps are setup in the constructor + var $_si_qstr_regexp = null; + var $_qstr_regexp = null; + var $_func_regexp = null; + var $_reg_obj_regexp = null; + var $_var_bracket_regexp = null; + var $_num_const_regexp = null; + var $_dvar_guts_regexp = null; + var $_dvar_regexp = null; + var $_cvar_regexp = null; + var $_svar_regexp = null; + var $_avar_regexp = null; + var $_mod_regexp = null; + var $_var_regexp = null; + var $_parenth_param_regexp = null; + var $_func_call_regexp = null; + var $_obj_ext_regexp = null; + var $_obj_start_regexp = null; + var $_obj_params_regexp = null; + var $_obj_call_regexp = null; + var $_cacheable_state = 0; + var $_cache_attrs_count = 0; + var $_nocache_count = 0; + var $_cache_serial = null; + var $_cache_include = null; + + var $_strip_depth = 0; + var $_additional_newline = "\n"; + + /**#@-*/ + /** + * The class constructor. + */ + function Smarty_Compiler() + { + // matches double quoted strings: + // "foobar" + // "foo\"bar" + $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'; + + // matches single quoted strings: + // 'foobar' + // 'foo\'bar' + $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''; + + // matches single or double quoted strings + $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')'; + + // matches bracket portion of vars + // [0] + // [foo] + // [$bar] + $this->_var_bracket_regexp = '\[\$?[\w\.]+\]'; + + // matches numerical constants + // 30 + // -12 + // 13.22 + $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)'; + + // matches $ vars (not objects): + // $foo + // $foo.bar + // $foo.bar.foobar + // $foo[0] + // $foo[$bar] + // $foo[5][blah] + // $foo[5].bar[$foobar][4] + $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))'; + $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]'; + $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp + . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?'; + $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp; + + // matches config vars: + // #foo# + // #foobar123_foo# + $this->_cvar_regexp = '\#\w+\#'; + + // matches section vars: + // %foo.bar% + $this->_svar_regexp = '\%\w+\.\w+\%'; + + // matches all valid variables (no quotes, no modifiers) + $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|' + . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')'; + + // matches valid variable syntax: + // $foo + // $foo + // #foo# + // #foo# + // "text" + // "text" + $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')'; + + // matches valid object call (one level of object nesting allowed in parameters): + // $foo->bar + // $foo->bar() + // $foo->bar("text") + // $foo->bar($foo, $bar, "text") + // $foo->bar($foo, "foo") + // $foo->bar->foo() + // $foo->bar->foo->bar() + // $foo->bar($foo->bar) + // $foo->bar($foo->bar()) + // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar)) + $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')'; + $this->_obj_restricted_param_regexp = '(?:' + . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')' + . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)'; + $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|' + . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)'; + $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp + . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)'; + $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)'; + $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)'; + + // matches valid modifier syntax: + // |foo + // |@foo + // |foo:"bar" + // |foo:$bar + // |foo:"bar":$foobar + // |foo|bar + // |foo:$foo->bar + $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|' + . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)'; + + // matches valid function name: + // foo123 + // _foo_bar + $this->_func_regexp = '[a-zA-Z_]\w*'; + + // matches valid registered object: + // foo->bar + $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*'; + + // matches valid parameter values: + // true + // $foo + // $foo|bar + // #foo# + // #foo#|bar + // "text" + // "text"|bar + // $foo->bar + $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' + . $this->_var_regexp . '|' . $this->_num_const_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)'; + + // matches valid parenthesised function parameters: + // + // "text" + // $foo, $bar, "text" + // $foo|bar, "foo"|bar, $foo->bar($foo)|bar + $this->_parenth_param_regexp = '(?:\((?:\w+|' + . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|' + . $this->_param_regexp . ')))*)?\))'; + + // matches valid function call: + // foo() + // foo_bar($foo) + // _foo_bar($foo,"bar") + // foo123($foo,$foo->bar(),"foo") + $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:' + . $this->_parenth_param_regexp . '))'; + } + + /** + * compile a resource + * + * sets $compiled_content to the compiled source + * @param string $resource_name + * @param string $source_content + * @param string $compiled_content + * @return true + */ + function _compile_file($resource_name, $source_content, &$compiled_content) + { + + if ($this->security) { + // do not allow php syntax to be executed unless specified + if ($this->php_handling == SMARTY_PHP_ALLOW && + !$this->security_settings['PHP_HANDLING']) { + $this->php_handling = SMARTY_PHP_PASSTHRU; + } + } + + $this->_load_filters(); + + $this->_current_file = $resource_name; + $this->_current_line_no = 1; + $ldq = preg_quote($this->left_delimiter, '~'); + $rdq = preg_quote($this->right_delimiter, '~'); + + // run template source through prefilter functions + if (count($this->_plugins['prefilter']) > 0) { + foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { + if ($prefilter === false) continue; + if ($prefilter[3] || is_callable($prefilter[0])) { + $source_content = call_user_func_array($prefilter[0], + array($source_content, &$this)); + $this->_plugins['prefilter'][$filter_name][3] = true; + } else { + $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented"); + } + } + } + + /* fetch all special blocks */ + $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s"; + + preg_match_all($search, $source_content, $match, PREG_SET_ORDER); + $this->_folded_blocks = $match; + reset($this->_folded_blocks); + + /* replace special blocks by "{php}" */ + $source_content = preg_replace($search.'e', "'" + . $this->_quote_replace($this->left_delimiter) . 'php' + . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'" + . $this->_quote_replace($this->right_delimiter) + . "'" + , $source_content); + + /* Gather all template tags. */ + preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match); + $template_tags = $_match[1]; + /* Split content by template tags to obtain non-template content. */ + $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content); + + /* loop through text blocks */ + for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) { + /* match anything resembling php tags */ + if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?\s*php\s*[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) { + /* replace tags with placeholders to prevent recursive replacements */ + $sp_match[1] = array_unique($sp_match[1]); + usort($sp_match[1], '_smarty_sort_length'); + for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { + $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]); + } + /* process each one */ + for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { + if ($this->php_handling == SMARTY_PHP_PASSTHRU) { + /* echo php contents */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', ''."\n", $text_blocks[$curr_tb]); + } else if ($this->php_handling == SMARTY_PHP_QUOTE) { + /* quote php tags */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]); + } else if ($this->php_handling == SMARTY_PHP_REMOVE) { + /* remove php tags */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]); + } else { + /* SMARTY_PHP_ALLOW, but echo non php starting tags */ + $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', ''."\n", $sp_match[1][$curr_sp]); + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]); + } + } + } + } + + /* Compile the template tags into PHP code. */ + $compiled_tags = array(); + for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) { + $this->_current_line_no += substr_count($text_blocks[$i], "\n"); + $compiled_tags[] = $this->_compile_tag($template_tags[$i]); + $this->_current_line_no += substr_count($template_tags[$i], "\n"); + } + if (count($this->_tag_stack)>0) { + list($_open_tag, $_line_no) = end($this->_tag_stack); + $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__); + return; + } + + /* Reformat $text_blocks between 'strip' and '/strip' tags, + removing spaces, tabs and newlines. */ + $strip = false; + for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { + if ($compiled_tags[$i] == '{strip}') { + $compiled_tags[$i] = ''; + $strip = true; + /* remove leading whitespaces */ + $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]); + } + if ($strip) { + /* strip all $text_blocks before the next '/strip' */ + for ($j = $i + 1; $j < $for_max; $j++) { + /* remove leading and trailing whitespaces of each line */ + $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]); + if ($compiled_tags[$j] == '{/strip}') { + /* remove trailing whitespaces from the last text_block */ + $text_blocks[$j] = rtrim($text_blocks[$j]); + } + $text_blocks[$j] = ""\'", "\\"=>"\\\\")) . "'; ?>"; + if ($compiled_tags[$j] == '{/strip}') { + $compiled_tags[$j] = "\n"; /* slurped by php, but necessary + if a newline is following the closing strip-tag */ + $strip = false; + $i = $j; + break; + } + } + } + } + $compiled_content = ''; + + $tag_guard = '%%%SMARTYOTG' . md5(uniqid(rand(), true)) . '%%%'; + + /* Interleave the compiled contents and text blocks to get the final result. */ + for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { + if ($compiled_tags[$i] == '') { + // tag result empty, remove first newline from following text block + $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]); + } + // replace legit PHP tags with placeholder + $text_blocks[$i] = str_replace('\n", $compiled_content); + $compiled_content = preg_replace("~(?\n", $compiled_content); + + // recover legit tags + $compiled_content = str_replace($tag_guard, '_cache_serial)) { + $compiled_content = "_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content; + } + + // run compiled template through postfilter functions + if (count($this->_plugins['postfilter']) > 0) { + foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { + if ($postfilter === false) continue; + if ($postfilter[3] || is_callable($postfilter[0])) { + $compiled_content = call_user_func_array($postfilter[0], + array($compiled_content, &$this)); + $this->_plugins['postfilter'][$filter_name][3] = true; + } else { + $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented"); + } + } + } + + // put header at the top of the compiled template + $template_header = "_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; + $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n"; + + /* Emit code to load needed plugins. */ + $this->_plugins_code = ''; + if (count($this->_plugin_info)) { + $_plugins_params = "array('plugins' => array("; + foreach ($this->_plugin_info as $plugin_type => $plugins) { + foreach ($plugins as $plugin_name => $plugin_info) { + $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], "; + $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),'; + } + } + $_plugins_params .= '))'; + $plugins_code = "\n"; + $template_header .= $plugins_code; + $this->_plugin_info = array(); + $this->_plugins_code = $plugins_code; + } + + if ($this->_init_smarty_vars) { + $template_header .= "\n"; + $this->_init_smarty_vars = false; + } + + $compiled_content = $template_header . $compiled_content; + return true; + } + + /** + * Compile a template tag + * + * @param string $template_tag + * @return string + */ + function _compile_tag($template_tag) + { + /* Matched comment. */ + if (substr($template_tag, 0, 1) == '*' && substr($template_tag, -1) == '*') + return ''; + + /* Split tag into two three parts: command, command modifiers and the arguments. */ + if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp + . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)) + (?:\s+(.*))?$ + ~xs', $template_tag, $match)) { + $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__); + } + + $tag_command = $match[1]; + $tag_modifier = isset($match[2]) ? $match[2] : null; + $tag_args = isset($match[3]) ? $match[3] : null; + + if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) { + /* tag name is a variable or object */ + $_return = $this->_parse_var_props($tag_command . $tag_modifier); + return "" . $this->_additional_newline; + } + + /* If the tag name is a registered object, we process it. */ + if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) { + return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier); + } + + switch ($tag_command) { + case 'include': + return $this->_compile_include_tag($tag_args); + + case 'include_php': + return $this->_compile_include_php_tag($tag_args); + + case 'if': + $this->_push_tag('if'); + return $this->_compile_if_tag($tag_args); + + case 'else': + list($_open_tag) = end($this->_tag_stack); + if ($_open_tag != 'if' && $_open_tag != 'elseif') + $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__); + else + $this->_push_tag('else'); + return ''; + + case 'elseif': + list($_open_tag) = end($this->_tag_stack); + if ($_open_tag != 'if' && $_open_tag != 'elseif') + $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__); + if ($_open_tag == 'if') + $this->_push_tag('elseif'); + return $this->_compile_if_tag($tag_args, true); + + case '/if': + $this->_pop_tag('if'); + return ''; + + case 'capture': + return $this->_compile_capture_tag(true, $tag_args); + + case '/capture': + return $this->_compile_capture_tag(false); + + case 'ldelim': + return $this->left_delimiter; + + case 'rdelim': + return $this->right_delimiter; + + case 'section': + $this->_push_tag('section'); + return $this->_compile_section_start($tag_args); + + case 'sectionelse': + $this->_push_tag('sectionelse'); + return ""; + break; + + case '/section': + $_open_tag = $this->_pop_tag('section'); + if ($_open_tag == 'sectionelse') + return ""; + else + return ""; + + case 'foreach': + $this->_push_tag('foreach'); + return $this->_compile_foreach_start($tag_args); + break; + + case 'foreachelse': + $this->_push_tag('foreachelse'); + return ""; + + case '/foreach': + $_open_tag = $this->_pop_tag('foreach'); + if ($_open_tag == 'foreachelse') + return ""; + else + return ""; + break; + + case 'strip': + case '/strip': + if (substr($tag_command, 0, 1)=='/') { + $this->_pop_tag('strip'); + if (--$this->_strip_depth==0) { /* outermost closing {/strip} */ + $this->_additional_newline = "\n"; + return '{' . $tag_command . '}'; + } + } else { + $this->_push_tag('strip'); + if ($this->_strip_depth++==0) { /* outermost opening {strip} */ + $this->_additional_newline = ""; + return '{' . $tag_command . '}'; + } + } + return ''; + + case 'php': + /* handle folded tags replaced by {php} */ + list(, $block) = each($this->_folded_blocks); + $this->_current_line_no += substr_count($block[0], "\n"); + /* the number of matched elements in the regexp in _compile_file() + determins the type of folded tag that was found */ + switch (count($block)) { + case 2: /* comment */ + return ''; + + case 3: /* literal */ + return ""\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline; + + case 4: /* php */ + if ($this->security && !$this->security_settings['PHP_TAGS']) { + $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__); + return; + } + return ''; + } + break; + + case 'insert': + return $this->_compile_insert_tag($tag_args); + + default: + if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) { + return $output; + } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) { + return $output; + } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) { + return $output; + } else { + $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__); + } + + } + } + + + /** + * compile the custom compiler tag + * + * sets $output to the compiled custom compiler tag + * @param string $tag_command + * @param string $tag_args + * @param string $output + * @return boolean + */ + function _compile_compiler_tag($tag_command, $tag_args, &$output) + { + $found = false; + $have_function = true; + + /* + * First we check if the compiler function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['compiler'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['compiler'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "compiler function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_compiler_' . $tag_command; + if (!is_callable($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true); + } + } + + /* + * True return value means that we either found a plugin or a + * dynamically registered function. False means that we didn't and the + * compiler should now emit code to load custom function plugin for this + * tag. + */ + if ($found) { + if ($have_function) { + $output = call_user_func_array($plugin_func, array($tag_args, &$this)); + if($output != '') { + $output = '_push_cacheable_state('compiler', $tag_command) + . $output + . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>'; + } + } else { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + } + return true; + } else { + return false; + } + } + + + /** + * compile block function tag + * + * sets $output to compiled block function tag + * @param string $tag_command + * @param string $tag_args + * @param string $tag_modifier + * @param string $output + * @return boolean + */ + function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output) + { + if (substr($tag_command, 0, 1) == '/') { + $start_tag = false; + $tag_command = substr($tag_command, 1); + } else + $start_tag = true; + + $found = false; + $have_function = true; + + /* + * First we check if the block function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['block'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['block'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "block function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_block_' . $tag_command; + if (!function_exists($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true); + + } + } + + if (!$found) { + return false; + } else if (!$have_function) { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + return true; + } + + /* + * Even though we've located the plugin function, compilation + * happens only once, so the plugin will still need to be loaded + * at runtime for future requests. + */ + $this->_add_plugin('block', $tag_command); + + if ($start_tag) + $this->_push_tag($tag_command); + else + $this->_pop_tag($tag_command); + + if ($start_tag) { + $output = '_push_cacheable_state('block', $tag_command); + $attrs = $this->_parse_attrs($tag_args); + $_cache_attrs=''; + $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs); + $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); '; + $output .= '$_block_repeat=true;' . $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat);'; + $output .= 'while ($_block_repeat) { ob_start(); ?>'; + } else { + $output = '_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat)'; + if ($tag_modifier != '') { + $this->_parse_modifiers($_out_tag_text, $tag_modifier); + } + $output .= '$_block_repeat=false;echo ' . $_out_tag_text . '; } '; + $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>'; + } + + return true; + } + + + /** + * compile custom function tag + * + * @param string $tag_command + * @param string $tag_args + * @param string $tag_modifier + * @return string + */ + function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output) + { + $found = false; + $have_function = true; + + /* + * First we check if the custom function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['function'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['function'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "custom function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_function_' . $tag_command; + if (!function_exists($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true); + + } + } + + if (!$found) { + return false; + } else if (!$have_function) { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + return true; + } + + /* declare plugin to be loaded on display of the template that + we compile right now */ + $this->_add_plugin('function', $tag_command); + + $_cacheable_state = $this->_push_cacheable_state('function', $tag_command); + $attrs = $this->_parse_attrs($tag_args); + $_cache_attrs = ''; + $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs); + + $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)"; + if($tag_modifier != '') { + $this->_parse_modifiers($output, $tag_modifier); + } + + if($output != '') { + $output = '_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline; + } + + return true; + } + + /** + * compile a registered object tag + * + * @param string $tag_command + * @param array $attrs + * @param string $tag_modifier + * @return string + */ + function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier) + { + if (substr($tag_command, 0, 1) == '/') { + $start_tag = false; + $tag_command = substr($tag_command, 1); + } else { + $start_tag = true; + } + + list($object, $obj_comp) = explode('->', $tag_command); + + $arg_list = array(); + if(count($attrs)) { + $_assign_var = false; + foreach ($attrs as $arg_name => $arg_value) { + if($arg_name == 'assign') { + $_assign_var = $arg_value; + unset($attrs['assign']); + continue; + } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + + if($this->_reg_objects[$object][2]) { + // smarty object argument format + $args = "array(".implode(',', (array)$arg_list)."), \$this"; + } else { + // traditional argument format + $args = implode(',', array_values($attrs)); + if (empty($args)) { + $args = ''; + } + } + + $prefix = ''; + $postfix = ''; + $newline = ''; + if(!is_object($this->_reg_objects[$object][0])) { + $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) { + $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) { + // method + if(in_array($obj_comp, $this->_reg_objects[$object][3])) { + // block method + if ($start_tag) { + $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); "; + $prefix .= "\$_block_repeat=true; \$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat); "; + $prefix .= "while (\$_block_repeat) { ob_start();"; + $return = null; + $postfix = ''; + } else { + $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); \$_block_repeat=false;"; + $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat)"; + $postfix = "} array_pop(\$this->_tag_stack);"; + } + } else { + // non-block method + $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)"; + } + } else { + // property + $return = "\$this->_reg_objects['$object'][0]->$obj_comp"; + } + + if($return != null) { + if($tag_modifier != '') { + $this->_parse_modifiers($return, $tag_modifier); + } + + if(!empty($_assign_var)) { + $output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);"; + } else { + $output = 'echo ' . $return . ';'; + $newline = $this->_additional_newline; + } + } else { + $output = ''; + } + + return '" . $newline; + } + + /** + * Compile {insert ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_insert_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $name = $this->_dequote($attrs['name']); + + if (empty($name)) { + return $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__); + } + + if (!preg_match('~^\w+$~', $name)) { + return $this->_syntax_error("'insert: 'name' must be an insert function name", E_USER_ERROR, __FILE__, __LINE__); + } + + if (!empty($attrs['script'])) { + $delayed_loading = true; + } else { + $delayed_loading = false; + } + + foreach ($attrs as $arg_name => $arg_value) { + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + + $this->_add_plugin('insert', $name, $delayed_loading); + + $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))"; + + return "" . $this->_additional_newline; + } + + /** + * Compile {include ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_include_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + if (empty($attrs['file'])) { + $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__); + } + + foreach ($attrs as $arg_name => $arg_value) { + if ($arg_name == 'file') { + $include_file = $arg_value; + continue; + } else if ($arg_name == 'assign') { + $assign_var = $arg_value; + continue; + } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + + $output = '_tpl_vars;\n"; + + + $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))"; + $output .= "\$this->_smarty_include($_params);\n" . + "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . + "unset(\$_smarty_tpl_vars);\n"; + + if (isset($assign_var)) { + $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n"; + } + + $output .= ' ?>'; + + return $output; + + } + + /** + * Compile {include ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_include_php_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + + if (empty($attrs['file'])) { + $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__); + } + + $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']); + $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true'; + + $arg_list = array(); + foreach($attrs as $arg_name => $arg_value) { + if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') { + if(is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + + $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))"; + + return "" . $this->_additional_newline; + } + + + /** + * Compile {section ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_section_start($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + $output = '_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__); + } + + $output .= "unset(\$this->_sections[$section_name]);\n"; + $section_props = "\$this->_sections[$section_name]"; + + foreach ($attrs as $attr_name => $attr_value) { + switch ($attr_name) { + case 'loop': + $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n"; + break; + + case 'show': + if (is_bool($attr_value)) + $show_attr_value = $attr_value ? 'true' : 'false'; + else + $show_attr_value = "(bool)$attr_value"; + $output .= "{$section_props}['show'] = $show_attr_value;\n"; + break; + + case 'name': + $output .= "{$section_props}['$attr_name'] = $attr_value;\n"; + break; + + case 'max': + case 'start': + $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n"; + break; + + case 'step': + $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n"; + break; + + default: + $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__); + break; + } + } + + if (!isset($attrs['show'])) + $output .= "{$section_props}['show'] = true;\n"; + + if (!isset($attrs['loop'])) + $output .= "{$section_props}['loop'] = 1;\n"; + + if (!isset($attrs['max'])) + $output .= "{$section_props}['max'] = {$section_props}['loop'];\n"; + else + $output .= "if ({$section_props}['max'] < 0)\n" . + " {$section_props}['max'] = {$section_props}['loop'];\n"; + + if (!isset($attrs['step'])) + $output .= "{$section_props}['step'] = 1;\n"; + + if (!isset($attrs['start'])) + $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n"; + else { + $output .= "if ({$section_props}['start'] < 0)\n" . + " {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" . + "else\n" . + " {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n"; + } + + $output .= "if ({$section_props}['show']) {\n"; + if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) { + $output .= " {$section_props}['total'] = {$section_props}['loop'];\n"; + } else { + $output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n"; + } + $output .= " if ({$section_props}['total'] == 0)\n" . + " {$section_props}['show'] = false;\n" . + "} else\n" . + " {$section_props}['total'] = 0;\n"; + + $output .= "if ({$section_props}['show']):\n"; + $output .= " + for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1; + {$section_props}['iteration'] <= {$section_props}['total']; + {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n"; + $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n"; + $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n"; + $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n"; + $output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n"; + $output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n"; + + $output .= "?>"; + + return $output; + } + + + /** + * Compile {foreach ...} tag. + * + * @param string $tag_args + * @return string + */ + function _compile_foreach_start($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + if (empty($attrs['from'])) { + return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__); + } + $from = $attrs['from']; + + if (empty($attrs['item'])) { + return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__); + } + $item = $this->_dequote($attrs['item']); + if (!preg_match('~^\w+$~', $item)) { + return $this->_syntax_error("foreach: 'item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); + } + + if (isset($attrs['key'])) { + $key = $this->_dequote($attrs['key']); + if (!preg_match('~^\w+$~', $key)) { + return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); + } + $key_part = "\$this->_tpl_vars['$key'] => "; + } else { + $key = null; + $key_part = ''; + } + + if (isset($attrs['name'])) { + $name = $attrs['name']; + } else { + $name = null; + } + + $output = '_foreach[$name]"; + $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n"; + $output .= "if ({$foreach_props}['total'] > 0):\n"; + $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; + $output .= " {$foreach_props}['iteration']++;\n"; + } else { + $output .= "if (count(\$_from)):\n"; + $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; + } + $output .= '?>'; + + return $output; + } + + + /** + * Compile {capture} .. {/capture} tags + * + * @param boolean $start true if this is the {capture} tag + * @param string $tag_args + * @return string + */ + + function _compile_capture_tag($start, $tag_args = '') + { + $attrs = $this->_parse_attrs($tag_args); + + if ($start) { + $buffer = isset($attrs['name']) ? $attrs['name'] : "'default'"; + $assign = isset($attrs['assign']) ? $attrs['assign'] : null; + $append = isset($attrs['append']) ? $attrs['append'] : null; + + $output = ""; + $this->_capture_stack[] = array($buffer, $assign, $append); + } else { + list($buffer, $assign, $append) = array_pop($this->_capture_stack); + $output = "_smarty_vars['capture'][$buffer] = ob_get_contents(); "; + if (isset($assign)) { + $output .= " \$this->assign($assign, ob_get_contents());"; + } + if (isset($append)) { + $output .= " \$this->append($append, ob_get_contents());"; + } + $output .= "ob_end_clean(); ?>"; + } + + return $output; + } + + /** + * Compile {if ...} tag + * + * @param string $tag_args + * @param boolean $elseif if true, uses elseif instead of if + * @return string + */ + function _compile_if_tag($tag_args, $elseif = false) + { + + /* Tokenize args for 'if' tag. */ + preg_match_all('~(?> + ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call + ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string + \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token + \b\w+\b | # valid word token + \S+ # anything else + )~x', $tag_args, $match); + + $tokens = $match[0]; + + if(empty($tokens)) { + $_error_msg = $elseif ? "'elseif'" : "'if'"; + $_error_msg .= ' statement requires arguments'; + $this->_syntax_error($_error_msg, E_USER_ERROR, __FILE__, __LINE__); + } + + + // make sure we have balanced parenthesis + $token_count = array_count_values($tokens); + if(isset($token_count['(']) && $token_count['('] != $token_count[')']) { + $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__); + } + + $is_arg_stack = array(); + + for ($i = 0; $i < count($tokens); $i++) { + + $token = &$tokens[$i]; + + switch (strtolower($token)) { + case '!': + case '%': + case '!==': + case '==': + case '===': + case '>': + case '<': + case '!=': + case '<>': + case '<<': + case '>>': + case '<=': + case '>=': + case '&&': + case '||': + case '|': + case '^': + case '&': + case '~': + case ')': + case ',': + case '+': + case '-': + case '*': + case '/': + case '@': + break; + + case 'eq': + $token = '=='; + break; + + case 'ne': + case 'neq': + $token = '!='; + break; + + case 'lt': + $token = '<'; + break; + + case 'le': + case 'lte': + $token = '<='; + break; + + case 'gt': + $token = '>'; + break; + + case 'ge': + case 'gte': + $token = '>='; + break; + + case 'and': + $token = '&&'; + break; + + case 'or': + $token = '||'; + break; + + case 'not': + $token = '!'; + break; + + case 'mod': + $token = '%'; + break; + + case '(': + array_push($is_arg_stack, $i); + break; + + case 'is': + /* If last token was a ')', we operate on the parenthesized + expression. The start of the expression is on the stack. + Otherwise, we operate on the last encountered token. */ + if ($tokens[$i-1] == ')') + $is_arg_start = array_pop($is_arg_stack); + else + $is_arg_start = $i-1; + /* Construct the argument for 'is' expression, so it knows + what to operate on. */ + $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); + + /* Pass all tokens from next one until the end to the + 'is' expression parsing function. The function will + return modified tokens, where the first one is the result + of the 'is' expression and the rest are the tokens it + didn't touch. */ + $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); + + /* Replace the old tokens with the new ones. */ + array_splice($tokens, $is_arg_start, count($tokens), $new_tokens); + + /* Adjust argument start so that it won't change from the + current position for the next iteration. */ + $i = $is_arg_start; + break; + + default: + if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) { + // function call + if($this->security && + !in_array($token, $this->security_settings['IF_FUNCS'])) { + $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); + } + } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && (strpos('+-*/^%&|', substr($token, -1)) === false) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') { + // variable function call + $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); + } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) { + // object or variable + $token = $this->_parse_var_props($token); + } elseif(is_numeric($token)) { + // number, skip it + } else { + $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__); + } + break; + } + } + + if ($elseif) + return ''; + else + return ''; + } + + + function _compile_arg_list($type, $name, $attrs, &$cache_code) { + $arg_list = array(); + + if (isset($type) && isset($name) + && isset($this->_plugins[$type]) + && isset($this->_plugins[$type][$name]) + && empty($this->_plugins[$type][$name][4]) + && is_array($this->_plugins[$type][$name][5]) + ) { + /* we have a list of parameters that should be cached */ + $_cache_attrs = $this->_plugins[$type][$name][5]; + $_count = $this->_cache_attrs_count++; + $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');"; + + } else { + /* no parameters are cached */ + $_cache_attrs = null; + } + + foreach ($attrs as $arg_name => $arg_value) { + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + if (is_null($arg_value)) + $arg_value = 'null'; + if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) { + $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)"; + } else { + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + return $arg_list; + } + + /** + * Parse is expression + * + * @param string $is_arg + * @param array $tokens + * @return array + */ + function _parse_is_expr($is_arg, $tokens) + { + $expr_end = 0; + $negate_expr = false; + + if (($first_token = array_shift($tokens)) == 'not') { + $negate_expr = true; + $expr_type = array_shift($tokens); + } else + $expr_type = $first_token; + + switch ($expr_type) { + case 'even': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; + } else + $expr = "!(1 & $is_arg)"; + break; + + case 'odd': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; + } else + $expr = "(1 & $is_arg)"; + break; + + case 'div': + if (@$tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")"; + } else { + $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__); + } + break; + + default: + $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__); + break; + } + + if ($negate_expr) { + $expr = "!($expr)"; + } + + array_splice($tokens, 0, $expr_end, $expr); + + return $tokens; + } + + + /** + * Parse attribute string + * + * @param string $tag_args + * @return array + */ + function _parse_attrs($tag_args) + { + + /* Tokenize tag attributes. */ + preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) + )+ | + [=] + ~x', $tag_args, $match); + $tokens = $match[0]; + + $attrs = array(); + /* Parse state: + 0 - expecting attribute name + 1 - expecting '=' + 2 - expecting attribute value (not '=') */ + $state = 0; + + foreach ($tokens as $token) { + switch ($state) { + case 0: + /* If the token is a valid identifier, we set attribute name + and go to state 1. */ + if (preg_match('~^\w+$~', $token)) { + $attr_name = $token; + $state = 1; + } else + $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); + break; + + case 1: + /* If the token is '=', then we go to state 2. */ + if ($token == '=') { + $state = 2; + } else + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + break; + + case 2: + /* If token is not '=', we set the attribute value and go to + state 0. */ + if ($token != '=') { + /* We booleanize the token if it's a non-quoted possible + boolean value. */ + if (preg_match('~^(on|yes|true)$~', $token)) { + $token = 'true'; + } else if (preg_match('~^(off|no|false)$~', $token)) { + $token = 'false'; + } else if ($token == 'null') { + $token = 'null'; + } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) { + /* treat integer literally */ + } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) { + /* treat as a string, double-quote it escaping quotes */ + $token = '"'.addslashes($token).'"'; + } + + $attrs[$attr_name] = $token; + $state = 0; + } else + $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); + break; + } + $last_token = $token; + } + + if($state != 0) { + if($state == 1) { + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + } else { + $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); + } + } + + $this->_parse_vars_props($attrs); + + return $attrs; + } + + /** + * compile multiple variables and section properties tokens into + * PHP code + * + * @param array $tokens + */ + function _parse_vars_props(&$tokens) + { + foreach($tokens as $key => $val) { + $tokens[$key] = $this->_parse_var_props($val); + } + } + + /** + * compile single variable and section properties token into + * PHP code + * + * @param string $val + * @param string $tag_attrs + * @return string + */ + function _parse_var_props($val) + { + $val = trim($val); + + if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) { + // $ variable or object + $return = $this->_parse_var($match[1]); + $modifiers = $match[2]; + if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) { + $_default_mod_string = implode('|',(array)$this->default_modifiers); + $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers; + } + $this->_parse_modifiers($return, $modifiers); + return $return; + } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // double quoted text + preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + $return = $this->_expand_quoted_text($match[1]); + if($match[2] != '') { + $this->_parse_modifiers($return, $match[2]); + } + return $return; + } + elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // numerical constant + preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + if($match[2] != '') { + $this->_parse_modifiers($match[1], $match[2]); + return $match[1]; + } + } + elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // single quoted text + preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + if($match[2] != '') { + $this->_parse_modifiers($match[1], $match[2]); + return $match[1]; + } + } + elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // config var + return $this->_parse_conf_var($val); + } + elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // section var + return $this->_parse_section_prop($val); + } + elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) { + // literal string + return $this->_expand_quoted_text('"' . strtr($val, array('\\' => '\\\\', '"' => '\\"')) .'"'); + } + return $val; + } + + /** + * expand quoted text with embedded variables + * + * @param string $var_expr + * @return string + */ + function _expand_quoted_text($var_expr) + { + // if contains unescaped $, expand it + if(preg_match_all('~(?:\`(?_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?_parse_var(str_replace('`','',$_var)) . ')."'; + } + $var_expr = strtr($var_expr, $_replace); + $_return = preg_replace('~\.""|(?_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE); + + if(count($_math_vars) > 1) { + $_first_var = ""; + $_complete_var = ""; + $_output = ""; + // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter) + foreach($_math_vars as $_k => $_math_var) { + $_math_var = $_math_vars[$_k]; + + if(!empty($_math_var) || is_numeric($_math_var)) { + // hit a math operator, so process the stuff which came before it + if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) { + $_has_math = true; + if(!empty($_complete_var) || is_numeric($_complete_var)) { + $_output .= $this->_parse_var($_complete_var); + } + + // just output the math operator to php + $_output .= $_math_var; + + if(empty($_first_var)) + $_first_var = $_complete_var; + + $_complete_var = ""; + } else { + $_complete_var .= $_math_var; + } + } + } + if($_has_math) { + if(!empty($_complete_var) || is_numeric($_complete_var)) + $_output .= $this->_parse_var($_complete_var); + + // get the modifiers working (only the last var from math + modifier is left) + $var_expr = $_complete_var; + } + } + + // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit) + if(is_numeric(substr($var_expr, 0, 1))) + $_var_ref = $var_expr; + else + $_var_ref = substr($var_expr, 1); + + if(!$_has_math) { + + // get [foo] and .foo and ->foo and (...) pieces + preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match); + + $_indexes = $match[0]; + $_var_name = array_shift($_indexes); + + /* Handle $smarty.* variable references as a special case. */ + if ($_var_name == 'smarty') { + /* + * If the reference could be compiled, use the compiled output; + * otherwise, fall back on the $smarty variable generated at + * run-time. + */ + if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) { + $_output = $smarty_ref; + } else { + $_var_name = substr(array_shift($_indexes), 1); + $_output = "\$this->_smarty_vars['$_var_name']"; + } + } elseif(is_numeric($_var_name) && is_numeric(substr($var_expr, 0, 1))) { + // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers + if(count($_indexes) > 0) + { + $_var_name .= implode("", $_indexes); + $_indexes = array(); + } + $_output = $_var_name; + } else { + $_output = "\$this->_tpl_vars['$_var_name']"; + } + + foreach ($_indexes as $_index) { + if (substr($_index, 0, 1) == '[') { + $_index = substr($_index, 1, -1); + if (is_numeric($_index)) { + $_output .= "[$_index]"; + } elseif (substr($_index, 0, 1) == '$') { + if (strpos($_index, '.') !== false) { + $_output .= '[' . $this->_parse_var($_index) . ']'; + } else { + $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]"; + } + } else { + $_var_parts = explode('.', $_index); + $_var_section = $_var_parts[0]; + $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index'; + $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]"; + } + } else if (substr($_index, 0, 1) == '.') { + if (substr($_index, 1, 1) == '$') + $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]"; + else + $_output .= "['" . substr($_index, 1) . "']"; + } else if (substr($_index,0,2) == '->') { + if(substr($_index,2,2) == '__') { + $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } elseif($this->security && substr($_index, 2, 1) == '_') { + $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } elseif (substr($_index, 2, 1) == '$') { + if ($this->security) { + $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } else { + $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}'; + } + } else { + $_output .= $_index; + } + } elseif (substr($_index, 0, 1) == '(') { + $_index = $this->_parse_parenth_args($_index); + $_output .= $_index; + } else { + $_output .= $_index; + } + } + } + + return $_output; + } + + /** + * parse arguments in function call parenthesis + * + * @param string $parenth_args + * @return string + */ + function _parse_parenth_args($parenth_args) + { + preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match); + $orig_vals = $match = $match[0]; + $this->_parse_vars_props($match); + $replace = array(); + for ($i = 0, $count = count($match); $i < $count; $i++) { + $replace[$orig_vals[$i]] = $match[$i]; + } + return strtr($parenth_args, $replace); + } + + /** + * parse configuration variable expression into PHP code + * + * @param string $conf_var_expr + */ + function _parse_conf_var($conf_var_expr) + { + $parts = explode('|', $conf_var_expr, 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; + + $var_name = substr($var_ref, 1, -1); + + $output = "\$this->_config[0]['vars']['$var_name']"; + + $this->_parse_modifiers($output, $modifiers); + + return $output; + } + + /** + * parse section property expression into PHP code + * + * @param string $section_prop_expr + * @return string + */ + function _parse_section_prop($section_prop_expr) + { + $parts = explode('|', $section_prop_expr, 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; + + preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); + $section_name = $match[1]; + $prop_name = $match[2]; + + $output = "\$this->_sections['$section_name']['$prop_name']"; + + $this->_parse_modifiers($output, $modifiers); + + return $output; + } + + + /** + * parse modifier chain into PHP code + * + * sets $output to parsed modified chain + * @param string $output + * @param string $modifier_string + */ + function _parse_modifiers(&$output, $modifier_string) + { + preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match); + list(, $_modifiers, $modifier_arg_strings) = $_match; + + for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) { + $_modifier_name = $_modifiers[$_i]; + + if($_modifier_name == 'smarty') { + // skip smarty modifier + continue; + } + + preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match); + $_modifier_args = $_match[1]; + + if (substr($_modifier_name, 0, 1) == '@') { + $_map_array = false; + $_modifier_name = substr($_modifier_name, 1); + } else { + $_map_array = true; + } + + if (empty($this->_plugins['modifier'][$_modifier_name]) + && !$this->_get_plugin_filepath('modifier', $_modifier_name) + && function_exists($_modifier_name)) { + if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { + $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } else { + $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false); + } + } + $this->_add_plugin('modifier', $_modifier_name); + + $this->_parse_vars_props($_modifier_args); + + if($_modifier_name == 'default') { + // supress notifications of default modifier vars and args + if(substr($output, 0, 1) == '$') { + $output = '@' . $output; + } + if(isset($_modifier_args[0]) && substr($_modifier_args[0], 0, 1) == '$') { + $_modifier_args[0] = '@' . $_modifier_args[0]; + } + } + if (count($_modifier_args) > 0) + $_modifier_args = ', '.implode(', ', $_modifier_args); + else + $_modifier_args = ''; + + if ($_map_array) { + $output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))"; + + } else { + + $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)"; + + } + } + } + + + /** + * add plugin + * + * @param string $type + * @param string $name + * @param boolean? $delayed_loading + */ + function _add_plugin($type, $name, $delayed_loading = null) + { + if (!isset($this->_plugin_info[$type])) { + $this->_plugin_info[$type] = array(); + } + if (!isset($this->_plugin_info[$type][$name])) { + $this->_plugin_info[$type][$name] = array($this->_current_file, + $this->_current_line_no, + $delayed_loading); + } + } + + + /** + * Compiles references of type $smarty.foo + * + * @param string $indexes + * @return string + */ + function _compile_smarty_ref(&$indexes) + { + /* Extract the reference name. */ + $_ref = substr($indexes[0], 1); + foreach($indexes as $_index_no=>$_index) { + if (substr($_index, 0, 1) != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) { + $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); + } + } + + switch ($_ref) { + case 'now': + $compiled_ref = 'time()'; + $_max_index = 1; + break; + + case 'foreach': + array_shift($indexes); + $_var = $this->_parse_var_props(substr($indexes[0], 1)); + $_propname = substr($indexes[1], 1); + $_max_index = 1; + switch ($_propname) { + case 'index': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)"; + break; + + case 'first': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)"; + break; + + case 'last': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])"; + break; + + case 'show': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)"; + break; + + default: + unset($_max_index); + $compiled_ref = "\$this->_foreach[$_var]"; + } + break; + + case 'section': + array_shift($indexes); + $_var = $this->_parse_var_props(substr($indexes[0], 1)); + $compiled_ref = "\$this->_sections[$_var]"; + break; + + case 'get': + $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']"; + break; + + case 'post': + $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']"; + break; + + case 'cookies': + $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']"; + break; + + case 'env': + $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']"; + break; + + case 'server': + $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']"; + break; + + case 'session': + $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']"; + break; + + /* + * These cases are handled either at run-time or elsewhere in the + * compiler. + */ + case 'request': + if ($this->request_use_auto_globals) { + $compiled_ref = '$_REQUEST'; + break; + } else { + $this->_init_smarty_vars = true; + } + return null; + + case 'capture': + return null; + + case 'template': + $compiled_ref = "'$this->_current_file'"; + $_max_index = 1; + break; + + case 'version': + $compiled_ref = "'$this->_version'"; + $_max_index = 1; + break; + + case 'const': + if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) { + $this->_syntax_error("(secure mode) constants not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + array_shift($indexes); + if (preg_match('!^\.\w+$!', $indexes[0])) { + $compiled_ref = '@' . substr($indexes[0], 1); + } else { + $_val = $this->_parse_var_props(substr($indexes[0], 1)); + $compiled_ref = '@constant(' . $_val . ')'; + } + $_max_index = 1; + break; + + case 'config': + $compiled_ref = "\$this->_config[0]['vars']"; + $_max_index = 3; + break; + + case 'ldelim': + $compiled_ref = "'$this->left_delimiter'"; + break; + + case 'rdelim': + $compiled_ref = "'$this->right_delimiter'"; + break; + + default: + $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__); + break; + } + + if (isset($_max_index) && count($indexes) > $_max_index) { + $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); + } + + array_shift($indexes); + return $compiled_ref; + } + + /** + * compiles call to plugin of type $type with name $name + * returns a string containing the function-name or method call + * without the paramter-list that would have follow to make the + * call valid php-syntax + * + * @param string $type + * @param string $name + * @return string + */ + function _compile_plugin_call($type, $name) { + if (isset($this->_plugins[$type][$name])) { + /* plugin loaded */ + if (is_array($this->_plugins[$type][$name][0])) { + return ((is_object($this->_plugins[$type][$name][0][0])) ? + "\$this->_plugins['$type']['$name'][0][0]->" /* method callback */ + : (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */ + ). $this->_plugins[$type][$name][0][1]; + + } else { + /* function callback */ + return $this->_plugins[$type][$name][0]; + + } + } else { + /* plugin not loaded -> auto-loadable-plugin */ + return 'smarty_'.$type.'_'.$name; + + } + } + + /** + * load pre- and post-filters + */ + function _load_filters() + { + if (count($this->_plugins['prefilter']) > 0) { + foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { + if ($prefilter === false) { + unset($this->_plugins['prefilter'][$filter_name]); + $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + } + } + } + if (count($this->_plugins['postfilter']) > 0) { + foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { + if ($postfilter === false) { + unset($this->_plugins['postfilter'][$filter_name]); + $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + } + } + } + } + + + /** + * Quote subpattern references + * + * @param string $string + * @return string + */ + function _quote_replace($string) + { + return strtr($string, array('\\' => '\\\\', '$' => '\\$')); + } + + /** + * display Smarty syntax error + * + * @param string $error_msg + * @param integer $error_type + * @param string $file + * @param integer $line + */ + function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null) + { + $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type); + } + + + /** + * check if the compilation changes from cacheable to + * non-cacheable state with the beginning of the current + * plugin. return php-code to reflect the transition. + * @return string + */ + function _push_cacheable_state($type, $name) { + $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; + if ($_cacheable + || 0<$this->_cacheable_state++) return ''; + if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty')); + $_ret = 'if ($this->caching && !$this->_cache_including): echo \'{nocache:' + . $this->_cache_serial . '#' . $this->_nocache_count + . '}\'; endif;'; + return $_ret; + } + + + /** + * check if the compilation changes from non-cacheable to + * cacheable state with the end of the current plugin return + * php-code to reflect the transition. + * @return string + */ + function _pop_cacheable_state($type, $name) { + $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; + if ($_cacheable + || --$this->_cacheable_state>0) return ''; + return 'if ($this->caching && !$this->_cache_including): echo \'{/nocache:' + . $this->_cache_serial . '#' . ($this->_nocache_count++) + . '}\'; endif;'; + } + + + /** + * push opening tag-name, file-name and line-number on the tag-stack + * @param string the opening tag's name + */ + function _push_tag($open_tag) + { + array_push($this->_tag_stack, array($open_tag, $this->_current_line_no)); + } + + /** + * pop closing tag-name + * raise an error if this stack-top doesn't match with the closing tag + * @param string the closing tag's name + * @return string the opening tag's name + */ + function _pop_tag($close_tag) + { + $message = ''; + if (count($this->_tag_stack)>0) { + list($_open_tag, $_line_no) = array_pop($this->_tag_stack); + if ($close_tag == $_open_tag) { + return $_open_tag; + } + if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) { + return $this->_pop_tag($close_tag); + } + if ($close_tag == 'section' && $_open_tag == 'sectionelse') { + $this->_pop_tag($close_tag); + return $_open_tag; + } + if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') { + $this->_pop_tag($close_tag); + return $_open_tag; + } + if ($_open_tag == 'else' || $_open_tag == 'elseif') { + $_open_tag = 'if'; + } elseif ($_open_tag == 'sectionelse') { + $_open_tag = 'section'; + } elseif ($_open_tag == 'foreachelse') { + $_open_tag = 'foreach'; + } + $message = " expected {/$_open_tag} (opened line $_line_no)."; + } + $this->_syntax_error("mismatched tag {/$close_tag}.$message", + E_USER_ERROR, __FILE__, __LINE__); + } + +} + +/** + * compare to values by their string length + * + * @access private + * @param string $a + * @param string $b + * @return 0|-1|1 + */ +function _smarty_sort_length($a, $b) +{ + if($a == $b) + return 0; + + if(strlen($a) == strlen($b)) + return ($a > $b) ? -1 : 1; + + return (strlen($a) > strlen($b)) ? -1 : 1; +} + + +/* vim: set et: */ + +?> diff --git a/BSF/include/smarty/libs/debug.tpl b/BSF/include/smarty/libs/debug.tpl new file mode 100644 index 000000000..c05ef5d0b --- /dev/null +++ b/BSF/include/smarty/libs/debug.tpl @@ -0,0 +1,157 @@ +{* Smarty *} +{* debug.tpl, last updated version 2.1.0 *} +{assign_debug_info} +{capture assign=debug_output} + + + + Smarty Debug Console +{literal} + +{/literal} + + + +

    Smarty Debug Console

    + +

    included templates & config files (load time in seconds)

    + +
    +{section name=templates loop=$_debug_tpls} + {section name=indent loop=$_debug_tpls[templates].depth}   {/section} + + {$_debug_tpls[templates].filename|escape:html} + {if isset($_debug_tpls[templates].exec_time)} + + ({$_debug_tpls[templates].exec_time|string_format:"%.5f"}) + {if %templates.index% eq 0}(total){/if} + + {/if} +
    +{sectionelse} +

    no templates included

    +{/section} +
    + +

    assigned template variables

    + + + {section name=vars loop=$_debug_keys} + + + + {sectionelse} + + {/section} +
    {ldelim}${$_debug_keys[vars]|escape:'html'}{rdelim}{$_debug_vals[vars]|@debug_print_var}

    no template variables assigned

    + +

    assigned config file variables (outer template scope)

    + + + {section name=config_vars loop=$_debug_config_keys} + + + + {sectionelse} + + {/section} +
    {ldelim}#{$_debug_config_keys[config_vars]|escape:'html'}#{rdelim}{$_debug_config_vals[config_vars]|@debug_print_var}

    no config vars assigned

    + + +{/capture} +{if isset($_smarty_debug_output) and $_smarty_debug_output eq "html"} + {$debug_output} +{else} + +{/if} \ No newline at end of file diff --git a/BSF/include/smarty/libs/internals/core.assemble_plugin_filepath.php b/BSF/include/smarty/libs/internals/core.assemble_plugin_filepath.php new file mode 100644 index 000000000..690d3ddbc --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.assemble_plugin_filepath.php @@ -0,0 +1,67 @@ +plugins_dir as $_plugin_dir) { + + $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename; + + // see if path is relative + if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/", $_plugin_dir)) { + $_relative_paths[] = $_plugin_dir; + // relative path, see if it is in the SMARTY_DIR + if (@is_readable(SMARTY_DIR . $_plugin_filepath)) { + $_return = SMARTY_DIR . $_plugin_filepath; + break; + } + } + // try relative to cwd (or absolute) + if (@is_readable($_plugin_filepath)) { + $_return = $_plugin_filepath; + break; + } + } + + if($_return === false) { + // still not found, try PHP include_path + if(isset($_relative_paths)) { + foreach ((array)$_relative_paths as $_plugin_dir) { + + $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename; + + $_params = array('file_path' => $_plugin_filepath); + require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $smarty)) { + $_return = $_params['new_file_path']; + break; + } + } + } + } + $_filepaths_cache[$_plugin_filename] = $_return; + return $_return; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.assign_smarty_interface.php b/BSF/include/smarty/libs/internals/core.assign_smarty_interface.php new file mode 100644 index 000000000..7e65a73ec --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.assign_smarty_interface.php @@ -0,0 +1,43 @@ + + * Name: assign_smarty_interface
    + * Purpose: assign the $smarty interface variable + * @param array Format: null + * @param Smarty + */ +function smarty_core_assign_smarty_interface($params, &$smarty) +{ + if (isset($smarty->_smarty_vars) && isset($smarty->_smarty_vars['request'])) { + return; + } + + $_globals_map = array('g' => 'HTTP_GET_VARS', + 'p' => 'HTTP_POST_VARS', + 'c' => 'HTTP_COOKIE_VARS', + 's' => 'HTTP_SERVER_VARS', + 'e' => 'HTTP_ENV_VARS'); + + $_smarty_vars_request = array(); + + foreach (preg_split('!!', strtolower($smarty->request_vars_order)) as $_c) { + if (isset($_globals_map[$_c])) { + $_smarty_vars_request = array_merge($_smarty_vars_request, $GLOBALS[$_globals_map[$_c]]); + } + } + $_smarty_vars_request = @array_merge($_smarty_vars_request, $GLOBALS['HTTP_SESSION_VARS']); + + $smarty->_smarty_vars['request'] = $_smarty_vars_request; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.create_dir_structure.php b/BSF/include/smarty/libs/internals/core.create_dir_structure.php new file mode 100644 index 000000000..3eecc4972 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.create_dir_structure.php @@ -0,0 +1,79 @@ +_dir_perms) && !is_dir($_new_dir)) { + $smarty->trigger_error("problem creating directory '" . $_new_dir . "'"); + return false; + } + $_new_dir .= '/'; + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.display_debug_console.php b/BSF/include/smarty/libs/internals/core.display_debug_console.php new file mode 100644 index 000000000..1a80f3909 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.display_debug_console.php @@ -0,0 +1,61 @@ + + * Name: display_debug_console
    + * Purpose: display the javascript debug console window + * @param array Format: null + * @param Smarty + */ +function smarty_core_display_debug_console($params, &$smarty) +{ + // we must force compile the debug template in case the environment + // changed between separate applications. + + if(empty($smarty->debug_tpl)) { + // set path to debug template from SMARTY_DIR + $smarty->debug_tpl = SMARTY_DIR . 'debug.tpl'; + if($smarty->security && is_file($smarty->debug_tpl)) { + $smarty->secure_dir[] = realpath($smarty->debug_tpl); + } + $smarty->debug_tpl = 'file:' . SMARTY_DIR . 'debug.tpl'; + } + + $_ldelim_orig = $smarty->left_delimiter; + $_rdelim_orig = $smarty->right_delimiter; + + $smarty->left_delimiter = '{'; + $smarty->right_delimiter = '}'; + + $_compile_id_orig = $smarty->_compile_id; + $smarty->_compile_id = null; + + $_compile_path = $smarty->_get_compile_path($smarty->debug_tpl); + if ($smarty->_compile_resource($smarty->debug_tpl, $_compile_path)) + { + ob_start(); + $smarty->_include($_compile_path); + $_results = ob_get_contents(); + ob_end_clean(); + } else { + $_results = ''; + } + + $smarty->_compile_id = $_compile_id_orig; + + $smarty->left_delimiter = $_ldelim_orig; + $smarty->right_delimiter = $_rdelim_orig; + + return $_results; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.get_include_path.php b/BSF/include/smarty/libs/internals/core.get_include_path.php new file mode 100644 index 000000000..43432412b --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.get_include_path.php @@ -0,0 +1,44 @@ + diff --git a/BSF/include/smarty/libs/internals/core.get_microtime.php b/BSF/include/smarty/libs/internals/core.get_microtime.php new file mode 100644 index 000000000..f1a28e042 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.get_microtime.php @@ -0,0 +1,23 @@ + diff --git a/BSF/include/smarty/libs/internals/core.get_php_resource.php b/BSF/include/smarty/libs/internals/core.get_php_resource.php new file mode 100644 index 000000000..786d4e78e --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.get_php_resource.php @@ -0,0 +1,80 @@ +trusted_dir; + $smarty->_parse_resource_name($params, $smarty); + + /* + * Find out if the resource exists. + */ + + if ($params['resource_type'] == 'file') { + $_readable = false; + if(file_exists($params['resource_name']) && is_readable($params['resource_name'])) { + $_readable = true; + } else { + // test for file in include_path + $_params = array('file_path' => $params['resource_name']); + require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $smarty)) { + $_include_path = $_params['new_file_path']; + $_readable = true; + } + } + } else if ($params['resource_type'] != 'file') { + $_template_source = null; + $_readable = is_callable($smarty->_plugins['resource'][$params['resource_type']][0][0]) + && call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][0], + array($params['resource_name'], &$_template_source, &$smarty)); + } + + /* + * Set the error function, depending on which class calls us. + */ + if (method_exists($smarty, '_syntax_error')) { + $_error_funcc = '_syntax_error'; + } else { + $_error_funcc = 'trigger_error'; + } + + if ($_readable) { + if ($smarty->security) { + require_once(SMARTY_CORE_DIR . 'core.is_trusted.php'); + if (!smarty_core_is_trusted($params, $smarty)) { + $smarty->$_error_funcc('(secure mode) ' . $params['resource_type'] . ':' . $params['resource_name'] . ' is not trusted'); + return false; + } + } + } else { + $smarty->$_error_funcc($params['resource_type'] . ':' . $params['resource_name'] . ' is not readable'); + return false; + } + + if ($params['resource_type'] == 'file') { + $params['php_resource'] = $params['resource_name']; + } else { + $params['php_resource'] = $_template_source; + } + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.is_secure.php b/BSF/include/smarty/libs/internals/core.is_secure.php new file mode 100644 index 000000000..d54abd432 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.is_secure.php @@ -0,0 +1,59 @@ +security || $smarty->security_settings['INCLUDE_ANY']) { + return true; + } + + if ($params['resource_type'] == 'file') { + $_rp = realpath($params['resource_name']); + if (isset($params['resource_base_path'])) { + foreach ((array)$params['resource_base_path'] as $curr_dir) { + if ( ($_cd = realpath($curr_dir)) !== false && + strncmp($_rp, $_cd, strlen($_cd)) == 0 && + substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR ) { + return true; + } + } + } + if (!empty($smarty->secure_dir)) { + foreach ((array)$smarty->secure_dir as $curr_dir) { + if ( ($_cd = realpath($curr_dir)) !== false) { + if($_cd == $_rp) { + return true; + } elseif (strncmp($_rp, $_cd, strlen($_cd)) == 0 && + substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR) { + return true; + } + } + } + } + } else { + // resource is not on local file system + return call_user_func_array( + $smarty->_plugins['resource'][$params['resource_type']][0][2], + array($params['resource_name'], &$smarty)); + } + + return false; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.is_trusted.php b/BSF/include/smarty/libs/internals/core.is_trusted.php new file mode 100644 index 000000000..429973158 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.is_trusted.php @@ -0,0 +1,47 @@ +trusted_dir)) { + $_rp = realpath($params['resource_name']); + foreach ((array)$smarty->trusted_dir as $curr_dir) { + if (!empty($curr_dir) && is_readable ($curr_dir)) { + $_cd = realpath($curr_dir); + if (strncmp($_rp, $_cd, strlen($_cd)) == 0 + && substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR ) { + $_smarty_trusted = true; + break; + } + } + } + } + + } else { + // resource is not on local file system + $_smarty_trusted = call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][3], + array($params['resource_name'], $smarty)); + } + + return $_smarty_trusted; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.load_plugins.php b/BSF/include/smarty/libs/internals/core.load_plugins.php new file mode 100644 index 000000000..6db1dc51d --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.load_plugins.php @@ -0,0 +1,125 @@ +_plugins[$_type][$_name]; + + /* + * We do not load plugin more than once for each instance of Smarty. + * The following code checks for that. The plugin can also be + * registered dynamically at runtime, in which case template file + * and line number will be unknown, so we fill them in. + * + * The final element of the info array is a flag that indicates + * whether the dynamically registered plugin function has been + * checked for existence yet or not. + */ + if (isset($_plugin)) { + if (empty($_plugin[3])) { + if (!is_callable($_plugin[0])) { + $smarty->_trigger_fatal_error("[plugin] $_type '$_name' is not implemented", $_tpl_file, $_tpl_line, __FILE__, __LINE__); + } else { + $_plugin[1] = $_tpl_file; + $_plugin[2] = $_tpl_line; + $_plugin[3] = true; + if (!isset($_plugin[4])) $_plugin[4] = true; /* cacheable */ + } + } + continue; + } else if ($_type == 'insert') { + /* + * For backwards compatibility, we check for insert functions in + * the symbol table before trying to load them as a plugin. + */ + $_plugin_func = 'insert_' . $_name; + if (function_exists($_plugin_func)) { + $_plugin = array($_plugin_func, $_tpl_file, $_tpl_line, true, false); + continue; + } + } + + $_plugin_file = $smarty->_get_plugin_filepath($_type, $_name); + + if (! $_found = ($_plugin_file != false)) { + $_message = "could not load plugin file '$_type.$_name.php'\n"; + } + + /* + * If plugin file is found, it -must- provide the properly named + * plugin function. In case it doesn't, simply output the error and + * do not fall back on any other method. + */ + if ($_found) { + include_once $_plugin_file; + + $_plugin_func = 'smarty_' . $_type . '_' . $_name; + if (!function_exists($_plugin_func)) { + $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", $_tpl_file, $_tpl_line, __FILE__, __LINE__); + continue; + } + } + /* + * In case of insert plugins, their code may be loaded later via + * 'script' attribute. + */ + else if ($_type == 'insert' && $_delayed_loading) { + $_plugin_func = 'smarty_' . $_type . '_' . $_name; + $_found = true; + } + + /* + * Plugin specific processing and error checking. + */ + if (!$_found) { + if ($_type == 'modifier') { + /* + * In case modifier falls back on using PHP functions + * directly, we only allow those specified in the security + * context. + */ + if ($smarty->security && !in_array($_name, $smarty->security_settings['MODIFIER_FUNCS'])) { + $_message = "(secure mode) modifier '$_name' is not allowed"; + } else { + if (!function_exists($_name)) { + $_message = "modifier '$_name' is not implemented"; + } else { + $_plugin_func = $_name; + $_found = true; + } + } + } else if ($_type == 'function') { + /* + * This is a catch-all situation. + */ + $_message = "unknown tag - '$_name'"; + } + } + + if ($_found) { + $smarty->_plugins[$_type][$_name] = array($_plugin_func, $_tpl_file, $_tpl_line, true, true); + } else { + // output error + $smarty->_trigger_fatal_error('[plugin] ' . $_message, $_tpl_file, $_tpl_line, __FILE__, __LINE__); + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.load_resource_plugin.php b/BSF/include/smarty/libs/internals/core.load_resource_plugin.php new file mode 100644 index 000000000..a7d37d1af --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.load_resource_plugin.php @@ -0,0 +1,74 @@ +_plugins['resource'][$params['type']]; + if (isset($_plugin)) { + if (!$_plugin[1] && count($_plugin[0])) { + $_plugin[1] = true; + foreach ($_plugin[0] as $_plugin_func) { + if (!is_callable($_plugin_func)) { + $_plugin[1] = false; + break; + } + } + } + + if (!$_plugin[1]) { + $smarty->_trigger_fatal_error("[plugin] resource '" . $params['type'] . "' is not implemented", null, null, __FILE__, __LINE__); + } + + return; + } + + $_plugin_file = $smarty->_get_plugin_filepath('resource', $params['type']); + $_found = ($_plugin_file != false); + + if ($_found) { /* + * If the plugin file is found, it -must- provide the properly named + * plugin functions. + */ + include_once($_plugin_file); + + /* + * Locate functions that we require the plugin to provide. + */ + $_resource_ops = array('source', 'timestamp', 'secure', 'trusted'); + $_resource_funcs = array(); + foreach ($_resource_ops as $_op) { + $_plugin_func = 'smarty_resource_' . $params['type'] . '_' . $_op; + if (!function_exists($_plugin_func)) { + $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", null, null, __FILE__, __LINE__); + return; + } else { + $_resource_funcs[] = $_plugin_func; + } + } + + $smarty->_plugins['resource'][$params['type']] = array($_resource_funcs, true); + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.process_cached_inserts.php b/BSF/include/smarty/libs/internals/core.process_cached_inserts.php new file mode 100644 index 000000000..1d78edd93 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.process_cached_inserts.php @@ -0,0 +1,71 @@ +_smarty_md5.'{insert_cache (.*)}'.$smarty->_smarty_md5.'!Uis', + $params['results'], $match); + list($cached_inserts, $insert_args) = $match; + + for ($i = 0, $for_max = count($cached_inserts); $i < $for_max; $i++) { + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + $args = unserialize($insert_args[$i]); + $name = $args['name']; + + if (isset($args['script'])) { + $_params = array('resource_name' => $smarty->_dequote($args['script'])); + require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); + if(!smarty_core_get_php_resource($_params, $smarty)) { + return false; + } + $resource_type = $_params['resource_type']; + $php_resource = $_params['php_resource']; + + + if ($resource_type == 'file') { + $smarty->_include($php_resource, true); + } else { + $smarty->_eval($php_resource); + } + } + + $function_name = $smarty->_plugins['insert'][$name][0]; + if (empty($args['assign'])) { + $replace = $function_name($args, $smarty); + } else { + $smarty->assign($args['assign'], $function_name($args, $smarty)); + $replace = ''; + } + + $params['results'] = substr_replace($params['results'], $replace, strpos($params['results'], $cached_inserts[$i]), strlen($cached_inserts[$i])); + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'insert', + 'filename' => 'insert_'.$name, + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $debug_start_time); + } + } + + return $params['results']; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.process_compiled_include.php b/BSF/include/smarty/libs/internals/core.process_compiled_include.php new file mode 100644 index 000000000..d539423bf --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.process_compiled_include.php @@ -0,0 +1,37 @@ +_cache_including; + $smarty->_cache_including = true; + + $_return = $params['results']; + + foreach ($smarty->_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) { + $smarty->_include($_include_file_path, true); + } + + foreach ($smarty->_cache_serials as $_include_file_path=>$_cache_serial) { + $_return = preg_replace_callback('!(\{nocache\:('.$_cache_serial.')#(\d+)\})!s', + array(&$smarty, '_process_compiled_include_callback'), + $_return); + } + $smarty->_cache_including = $_cache_including; + return $_return; +} + +?> diff --git a/BSF/include/smarty/libs/internals/core.read_cache_file.php b/BSF/include/smarty/libs/internals/core.read_cache_file.php new file mode 100644 index 000000000..c60e113a7 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.read_cache_file.php @@ -0,0 +1,101 @@ +force_compile) { + // force compile enabled, always regenerate + return false; + } + + if (isset($content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']])) { + list($params['results'], $smarty->_cache_info) = $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']]; + return true; + } + + if (!empty($smarty->cache_handler_func)) { + // use cache_handler function + call_user_func_array($smarty->cache_handler_func, + array('read', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null)); + } else { + // use local cache file + $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']); + $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id); + $params['results'] = $smarty->_read_file($_cache_file); + } + + if (empty($params['results'])) { + // nothing to parse (error?), regenerate cache + return false; + } + + $_contents = $params['results']; + $_info_start = strpos($_contents, "\n") + 1; + $_info_len = (int)substr($_contents, 0, $_info_start - 1); + $_cache_info = unserialize(substr($_contents, $_info_start, $_info_len)); + $params['results'] = substr($_contents, $_info_start + $_info_len); + + if ($smarty->caching == 2 && isset ($_cache_info['expires'])){ + // caching by expiration time + if ($_cache_info['expires'] > -1 && (time() > $_cache_info['expires'])) { + // cache expired, regenerate + return false; + } + } else { + // caching by lifetime + if ($smarty->cache_lifetime > -1 && (time() - $_cache_info['timestamp'] > $smarty->cache_lifetime)) { + // cache expired, regenerate + return false; + } + } + + if ($smarty->compile_check) { + $_params = array('get_source' => false, 'quiet'=>true); + foreach (array_keys($_cache_info['template']) as $_template_dep) { + $_params['resource_name'] = $_template_dep; + if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) { + // template file has changed, regenerate cache + return false; + } + } + + if (isset($_cache_info['config'])) { + $_params = array('resource_base_path' => $smarty->config_dir, 'get_source' => false, 'quiet'=>true); + foreach (array_keys($_cache_info['config']) as $_config_dep) { + $_params['resource_name'] = $_config_dep; + if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) { + // config file has changed, regenerate cache + return false; + } + } + } + } + + $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']] = array($params['results'], $_cache_info); + + $smarty->_cache_info = $_cache_info; + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.rm_auto.php b/BSF/include/smarty/libs/internals/core.rm_auto.php new file mode 100644 index 000000000..b251f6491 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.rm_auto.php @@ -0,0 +1,71 @@ + $params['auto_base'], + 'level' => 0, + 'exp_time' => $params['exp_time'] + ); + require_once(SMARTY_CORE_DIR . 'core.rmdir.php'); + $_res = smarty_core_rmdir($_params, $smarty); + } else { + $_tname = $smarty->_get_auto_filename($params['auto_base'], $params['auto_source'], $params['auto_id']); + + if(isset($params['auto_source'])) { + if (isset($params['extensions'])) { + $_res = false; + foreach ((array)$params['extensions'] as $_extension) + $_res |= $smarty->_unlink($_tname.$_extension, $params['exp_time']); + } else { + $_res = $smarty->_unlink($_tname, $params['exp_time']); + } + } elseif ($smarty->use_sub_dirs) { + $_params = array( + 'dirname' => $_tname, + 'level' => 1, + 'exp_time' => $params['exp_time'] + ); + require_once(SMARTY_CORE_DIR . 'core.rmdir.php'); + $_res = smarty_core_rmdir($_params, $smarty); + } else { + // remove matching file names + $_handle = opendir($params['auto_base']); + $_res = true; + while (false !== ($_filename = readdir($_handle))) { + if($_filename == '.' || $_filename == '..') { + continue; + } elseif (substr($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, 0, strlen($_tname)) == $_tname) { + $_res &= (bool)$smarty->_unlink($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, $params['exp_time']); + } + } + } + } + + return $_res; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.rmdir.php b/BSF/include/smarty/libs/internals/core.rmdir.php new file mode 100644 index 000000000..2166c44d2 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.rmdir.php @@ -0,0 +1,54 @@ + keep root) + * WARNING: no tests, it will try to remove what you tell it! + * + * @param string $dirname + * @param integer $level + * @param integer $exp_time + * @return boolean + */ + +// $dirname, $level = 1, $exp_time = null + +function smarty_core_rmdir($params, &$smarty) +{ + if(!isset($params['level'])) { $params['level'] = 1; } + if(!isset($params['exp_time'])) { $params['exp_time'] = null; } + + if($_handle = @opendir($params['dirname'])) { + + while (false !== ($_entry = readdir($_handle))) { + if ($_entry != '.' && $_entry != '..') { + if (@is_dir($params['dirname'] . DIRECTORY_SEPARATOR . $_entry)) { + $_params = array( + 'dirname' => $params['dirname'] . DIRECTORY_SEPARATOR . $_entry, + 'level' => $params['level'] + 1, + 'exp_time' => $params['exp_time'] + ); + smarty_core_rmdir($_params, $smarty); + } + else { + $smarty->_unlink($params['dirname'] . DIRECTORY_SEPARATOR . $_entry, $params['exp_time']); + } + } + } + closedir($_handle); + } + + if ($params['level']) { + return @rmdir($params['dirname']); + } + return (bool)$_handle; + +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.run_insert_handler.php b/BSF/include/smarty/libs/internals/core.run_insert_handler.php new file mode 100644 index 000000000..71c384508 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.run_insert_handler.php @@ -0,0 +1,71 @@ +debugging) { + $_params = array(); + $_debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + if ($smarty->caching) { + $_arg_string = serialize($params['args']); + $_name = $params['args']['name']; + if (!isset($smarty->_cache_info['insert_tags'][$_name])) { + $smarty->_cache_info['insert_tags'][$_name] = array('insert', + $_name, + $smarty->_plugins['insert'][$_name][1], + $smarty->_plugins['insert'][$_name][2], + !empty($params['args']['script']) ? true : false); + } + return $smarty->_smarty_md5."{insert_cache $_arg_string}".$smarty->_smarty_md5; + } else { + if (isset($params['args']['script'])) { + $_params = array('resource_name' => $smarty->_dequote($params['args']['script'])); + require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); + if(!smarty_core_get_php_resource($_params, $smarty)) { + return false; + } + + if ($_params['resource_type'] == 'file') { + $smarty->_include($_params['php_resource'], true); + } else { + $smarty->_eval($_params['php_resource']); + } + unset($params['args']['script']); + } + + $_funcname = $smarty->_plugins['insert'][$params['args']['name']][0]; + $_content = $_funcname($params['args'], $smarty); + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'insert', + 'filename' => 'insert_'.$params['args']['name'], + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); + } + + if (!empty($params['args']["assign"])) { + $smarty->assign($params['args']["assign"], $_content); + } else { + return $_content; + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.smarty_include_php.php b/BSF/include/smarty/libs/internals/core.smarty_include_php.php new file mode 100644 index 000000000..30c6e7654 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.smarty_include_php.php @@ -0,0 +1,50 @@ + $params['smarty_file']); + require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); + smarty_core_get_php_resource($_params, $smarty); + $_smarty_resource_type = $_params['resource_type']; + $_smarty_php_resource = $_params['php_resource']; + + if (!empty($params['smarty_assign'])) { + ob_start(); + if ($_smarty_resource_type == 'file') { + $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']); + } else { + $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']); + } + $smarty->assign($params['smarty_assign'], ob_get_contents()); + ob_end_clean(); + } else { + if ($_smarty_resource_type == 'file') { + $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']); + } else { + $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']); + } + } +} + + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.write_cache_file.php b/BSF/include/smarty/libs/internals/core.write_cache_file.php new file mode 100644 index 000000000..72f785b74 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.write_cache_file.php @@ -0,0 +1,96 @@ +_cache_info['timestamp'] = time(); + if ($smarty->cache_lifetime > -1){ + // expiration set + $smarty->_cache_info['expires'] = $smarty->_cache_info['timestamp'] + $smarty->cache_lifetime; + } else { + // cache will never expire + $smarty->_cache_info['expires'] = -1; + } + + // collapse nocache.../nocache-tags + if (preg_match_all('!\{(/?)nocache\:[0-9a-f]{32}#\d+\}!', $params['results'], $match, PREG_PATTERN_ORDER)) { + // remove everything between every pair of outermost noache.../nocache-tags + // and replace it by a single nocache-tag + // this new nocache-tag will be replaced by dynamic contents in + // smarty_core_process_compiled_includes() on a cache-read + + $match_count = count($match[0]); + $results = preg_split('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!', $params['results'], -1, PREG_SPLIT_DELIM_CAPTURE); + + $level = 0; + $j = 0; + for ($i=0, $results_count = count($results); $i < $results_count && $j < $match_count; $i++) { + if ($results[$i] == $match[0][$j]) { + // nocache tag + if ($match[1][$j]) { // closing tag + $level--; + unset($results[$i]); + } else { // opening tag + if ($level++ > 0) unset($results[$i]); + } + $j++; + } elseif ($level > 0) { + unset($results[$i]); + } + } + $params['results'] = implode('', $results); + } + $smarty->_cache_info['cache_serials'] = $smarty->_cache_serials; + + // prepend the cache header info into cache file + $_cache_info = serialize($smarty->_cache_info); + $params['results'] = strlen($_cache_info) . "\n" . $_cache_info . $params['results']; + + if (!empty($smarty->cache_handler_func)) { + // use cache_handler function + call_user_func_array($smarty->cache_handler_func, + array('write', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null)); + } else { + // use local cache file + + if(!@is_writable($smarty->cache_dir)) { + // cache_dir not writable, see if it exists + if(!@is_dir($smarty->cache_dir)) { + $smarty->trigger_error('the $cache_dir \'' . $smarty->cache_dir . '\' does not exist, or is not a directory.', E_USER_ERROR); + return false; + } + $smarty->trigger_error('unable to write to $cache_dir \'' . realpath($smarty->cache_dir) . '\'. Be sure $cache_dir is writable by the web server user.', E_USER_ERROR); + return false; + } + + $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']); + $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id); + $_params = array('filename' => $_cache_file, 'contents' => $params['results'], 'create_dirs' => true); + require_once(SMARTY_CORE_DIR . 'core.write_file.php'); + smarty_core_write_file($_params, $smarty); + return true; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.write_compiled_include.php b/BSF/include/smarty/libs/internals/core.write_compiled_include.php new file mode 100644 index 000000000..c14adb5f4 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.write_compiled_include.php @@ -0,0 +1,91 @@ +caching && \!\$this->_cache_including\)\: echo \'\{nocache\:('.$params['cache_serial'].')#(\d+)\}\'; endif;'; + $_tag_end = 'if \(\$this->caching && \!\$this->_cache_including\)\: echo \'\{/nocache\:(\\2)#(\\3)\}\'; endif;'; + + preg_match_all('!('.$_tag_start.'(.*)'.$_tag_end.')!Us', + $params['compiled_content'], $_match_source, PREG_SET_ORDER); + + // no nocache-parts found: done + if (count($_match_source)==0) return; + + // convert the matched php-code to functions + $_include_compiled = "_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; + $_include_compiled .= " compiled from " . strtr(urlencode($params['resource_name']), array('%2F'=>'/', '%3A'=>':')) . " */\n\n"; + + $_compile_path = $params['include_file_path']; + + $smarty->_cache_serials[$_compile_path] = $params['cache_serial']; + $_include_compiled .= "\$this->_cache_serials['".$_compile_path."'] = '".$params['cache_serial']."';\n\n?>"; + + $_include_compiled .= $params['plugins_code']; + $_include_compiled .= "= 5.0) ? '_smarty' : 'this'; + for ($_i = 0, $_for_max = count($_match_source); $_i < $_for_max; $_i++) { + $_match =& $_match_source[$_i]; + $source = $_match[4]; + if ($this_varname == '_smarty') { + /* rename $this to $_smarty in the sourcecode */ + $tokens = token_get_all('\n"; + + $_params = array('filename' => $_compile_path, + 'contents' => $_include_compiled, 'create_dirs' => true); + + require_once(SMARTY_CORE_DIR . 'core.write_file.php'); + smarty_core_write_file($_params, $smarty); + return true; +} + + +?> diff --git a/BSF/include/smarty/libs/internals/core.write_compiled_resource.php b/BSF/include/smarty/libs/internals/core.write_compiled_resource.php new file mode 100644 index 000000000..b902eff3c --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.write_compiled_resource.php @@ -0,0 +1,35 @@ +compile_dir)) { + // compile_dir not writable, see if it exists + if(!@is_dir($smarty->compile_dir)) { + $smarty->trigger_error('the $compile_dir \'' . $smarty->compile_dir . '\' does not exist, or is not a directory.', E_USER_ERROR); + return false; + } + $smarty->trigger_error('unable to write to $compile_dir \'' . realpath($smarty->compile_dir) . '\'. Be sure $compile_dir is writable by the web server user.', E_USER_ERROR); + return false; + } + + $_params = array('filename' => $params['compile_path'], 'contents' => $params['compiled_content'], 'create_dirs' => true); + require_once(SMARTY_CORE_DIR . 'core.write_file.php'); + smarty_core_write_file($_params, $smarty); + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.write_file.php b/BSF/include/smarty/libs/internals/core.write_file.php new file mode 100644 index 000000000..8a3a3b398 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.write_file.php @@ -0,0 +1,54 @@ + $_dirname); + require_once(SMARTY_CORE_DIR . 'core.create_dir_structure.php'); + smarty_core_create_dir_structure($_params, $smarty); + } + + // write to tmp file, then rename it to avoid file locking race condition + $_tmp_file = tempnam($_dirname, 'wrt'); + + if (!($fd = @fopen($_tmp_file, 'wb'))) { + $_tmp_file = $_dirname . DIRECTORY_SEPARATOR . uniqid('wrt'); + if (!($fd = @fopen($_tmp_file, 'wb'))) { + $smarty->trigger_error("problem writing temporary file '$_tmp_file'"); + return false; + } + } + + fwrite($fd, $params['contents']); + fclose($fd); + + if (DIRECTORY_SEPARATOR == '\\' || !@rename($_tmp_file, $params['filename'])) { + // On platforms and filesystems that cannot overwrite with rename() + // delete the file before renaming it -- because windows always suffers + // this, it is short-circuited to avoid the initial rename() attempt + @unlink($params['filename']); + @rename($_tmp_file, $params['filename']); + } + @chmod($params['filename'], $smarty->_file_perms); + + return true; +} + +/* vim: set expandtab: */ + +?> \ No newline at end of file diff --git a/BSF/include/smarty/libs/plugins/block.textformat.php b/BSF/include/smarty/libs/plugins/block.textformat.php new file mode 100644 index 000000000..8cd010acb --- /dev/null +++ b/BSF/include/smarty/libs/plugins/block.textformat.php @@ -0,0 +1,103 @@ + + * Name: textformat
    + * Purpose: format text a certain way with preset styles + * or custom wrap/indent settings
    + * @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat} + * (Smarty online manual) + * @param array + *
    + * Params:   style: string (email)
    + *           indent: integer (0)
    + *           wrap: integer (80)
    + *           wrap_char string ("\n")
    + *           indent_char: string (" ")
    + *           wrap_boundary: boolean (true)
    + * 
    + * @author Monte Ohrt + * @param string contents of the block + * @param Smarty clever simulation of a method + * @return string string $content re-formatted + */ +function smarty_block_textformat($params, $content, &$smarty) +{ + if (is_null($content)) { + return; + } + + $style = null; + $indent = 0; + $indent_first = 0; + $indent_char = ' '; + $wrap = 80; + $wrap_char = "\n"; + $wrap_cut = false; + $assign = null; + + foreach ($params as $_key => $_val) { + switch ($_key) { + case 'style': + case 'indent_char': + case 'wrap_char': + case 'assign': + $$_key = (string)$_val; + break; + + case 'indent': + case 'indent_first': + case 'wrap': + $$_key = (int)$_val; + break; + + case 'wrap_cut': + $$_key = (bool)$_val; + break; + + default: + $smarty->trigger_error("textformat: unknown attribute '$_key'"); + } + } + + if ($style == 'email') { + $wrap = 72; + } + + // split into paragraphs + $_paragraphs = preg_split('![\r\n][\r\n]!',$content); + $_output = ''; + + for($_x = 0, $_y = count($_paragraphs); $_x < $_y; $_x++) { + if ($_paragraphs[$_x] == '') { + continue; + } + // convert mult. spaces & special chars to single space + $_paragraphs[$_x] = preg_replace(array('!\s+!','!(^\s+)|(\s+$)!'), array(' ',''), $_paragraphs[$_x]); + // indent first line + if($indent_first > 0) { + $_paragraphs[$_x] = str_repeat($indent_char, $indent_first) . $_paragraphs[$_x]; + } + // wordwrap sentences + $_paragraphs[$_x] = wordwrap($_paragraphs[$_x], $wrap - $indent, $wrap_char, $wrap_cut); + // indent lines + if($indent > 0) { + $_paragraphs[$_x] = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraphs[$_x]); + } + } + $_output = implode($wrap_char . $wrap_char, $_paragraphs); + + return $assign ? $smarty->assign($assign, $_output) : $_output; + +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/compiler.assign.php b/BSF/include/smarty/libs/plugins/compiler.assign.php new file mode 100644 index 000000000..abef377f8 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/compiler.assign.php @@ -0,0 +1,40 @@ + + * Name: assign
    + * Purpose: assign a value to a template variable + * @link http://smarty.php.net/manual/en/language.custom.functions.php#LANGUAGE.FUNCTION.ASSIGN {assign} + * (Smarty online manual) + * @author Monte Ohrt (initial author) + * @author messju mohr (conversion to compiler function) + * @param string containing var-attribute and value-attribute + * @param Smarty_Compiler + */ +function smarty_compiler_assign($tag_attrs, &$compiler) +{ + $_params = $compiler->_parse_attrs($tag_attrs); + + if (!isset($_params['var'])) { + $compiler->_syntax_error("assign: missing 'var' parameter", E_USER_WARNING); + return; + } + + if (!isset($_params['value'])) { + $compiler->_syntax_error("assign: missing 'value' parameter", E_USER_WARNING); + return; + } + + return "\$this->assign({$_params['var']}, {$_params['value']});"; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.assign_debug_info.php b/BSF/include/smarty/libs/plugins/function.assign_debug_info.php new file mode 100644 index 000000000..654049876 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.assign_debug_info.php @@ -0,0 +1,40 @@ + + * Name: assign_debug_info
    + * Purpose: assign debug info to the template
    + * @author Monte Ohrt + * @param array unused in this plugin, this plugin uses {@link Smarty::$_config}, + * {@link Smarty::$_tpl_vars} and {@link Smarty::$_smarty_debug_info} + * @param Smarty + */ +function smarty_function_assign_debug_info($params, &$smarty) +{ + $assigned_vars = $smarty->_tpl_vars; + ksort($assigned_vars); + if (@is_array($smarty->_config[0])) { + $config_vars = $smarty->_config[0]; + ksort($config_vars); + $smarty->assign("_debug_config_keys", array_keys($config_vars)); + $smarty->assign("_debug_config_vals", array_values($config_vars)); + } + + $included_templates = $smarty->_smarty_debug_info; + + $smarty->assign("_debug_keys", array_keys($assigned_vars)); + $smarty->assign("_debug_vals", array_values($assigned_vars)); + + $smarty->assign("_debug_tpls", $included_templates); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.config_load.php b/BSF/include/smarty/libs/plugins/function.config_load.php new file mode 100644 index 000000000..db89f638c --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.config_load.php @@ -0,0 +1,142 @@ + + * Name: config_load
    + * Purpose: load config file vars + * @link http://smarty.php.net/manual/en/language.function.config.load.php {config_load} + * (Smarty online manual) + * @author Monte Ohrt + * @author messju mohr (added use of resources) + * @param array Format: + *
    + * array('file' => required config file name,
    + *       'section' => optional config file section to load
    + *       'scope' => local/parent/global
    + *       'global' => overrides scope, setting to parent if true)
    + * 
    + * @param Smarty + */ +function smarty_function_config_load($params, &$smarty) +{ + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $_debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + $_file = isset($params['file']) ? $smarty->_dequote($params['file']) : null; + $_section = isset($params['section']) ? $smarty->_dequote($params['section']) : null; + $_scope = isset($params['scope']) ? $smarty->_dequote($params['scope']) : 'global'; + $_global = isset($params['global']) ? $smarty->_dequote($params['global']) : false; + + if (!isset($_file) || strlen($_file) == 0) { + $smarty->trigger_error("missing 'file' attribute in config_load tag", E_USER_ERROR, __FILE__, __LINE__); + } + + if (isset($_scope)) { + if ($_scope != 'local' && + $_scope != 'parent' && + $_scope != 'global') { + $smarty->trigger_error("invalid 'scope' attribute value", E_USER_ERROR, __FILE__, __LINE__); + } + } else { + if ($_global) { + $_scope = 'parent'; + } else { + $_scope = 'local'; + } + } + + $_params = array('resource_name' => $_file, + 'resource_base_path' => $smarty->config_dir, + 'get_source' => false); + $smarty->_parse_resource_name($_params); + $_file_path = $_params['resource_type'] . ':' . $_params['resource_name']; + if (isset($_section)) + $_compile_file = $smarty->_get_compile_path($_file_path.'|'.$_section); + else + $_compile_file = $smarty->_get_compile_path($_file_path); + + if($smarty->force_compile || !file_exists($_compile_file)) { + $_compile = true; + } elseif ($smarty->compile_check) { + $_params = array('resource_name' => $_file, + 'resource_base_path' => $smarty->config_dir, + 'get_source' => false); + $_compile = $smarty->_fetch_resource_info($_params) && + $_params['resource_timestamp'] > filemtime($_compile_file); + } else { + $_compile = false; + } + + if($_compile) { + // compile config file + if(!is_object($smarty->_conf_obj)) { + require_once SMARTY_DIR . $smarty->config_class . '.class.php'; + $smarty->_conf_obj = new $smarty->config_class(); + $smarty->_conf_obj->overwrite = $smarty->config_overwrite; + $smarty->_conf_obj->booleanize = $smarty->config_booleanize; + $smarty->_conf_obj->read_hidden = $smarty->config_read_hidden; + $smarty->_conf_obj->fix_newlines = $smarty->config_fix_newlines; + } + + $_params = array('resource_name' => $_file, + 'resource_base_path' => $smarty->config_dir, + $_params['get_source'] = true); + if (!$smarty->_fetch_resource_info($_params)) { + return; + } + $smarty->_conf_obj->set_file_contents($_file, $_params['source_content']); + $_config_vars = array_merge($smarty->_conf_obj->get($_file), + $smarty->_conf_obj->get($_file, $_section)); + if(function_exists('var_export')) { + $_output = ''; + } else { + $_output = ''\\\'', '\\'=>'\\\\')) . '\'); ?>'; + } + $_params = (array('compile_path' => $_compile_file, 'compiled_content' => $_output, 'resource_timestamp' => $_params['resource_timestamp'])); + require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); + smarty_core_write_compiled_resource($_params, $smarty); + } else { + include($_compile_file); + } + + if ($smarty->caching) { + $smarty->_cache_info['config'][$_file] = true; + } + + $smarty->_config[0]['vars'] = @array_merge($smarty->_config[0]['vars'], $_config_vars); + $smarty->_config[0]['files'][$_file] = true; + + if ($_scope == 'parent') { + $smarty->_config[1]['vars'] = @array_merge($smarty->_config[1]['vars'], $_config_vars); + $smarty->_config[1]['files'][$_file] = true; + } else if ($_scope == 'global') { + for ($i = 1, $for_max = count($smarty->_config); $i < $for_max; $i++) { + $smarty->_config[$i]['vars'] = @array_merge($smarty->_config[$i]['vars'], $_config_vars); + $smarty->_config[$i]['files'][$_file] = true; + } + } + + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'config', + 'filename' => $_file.' ['.$_section.'] '.$_scope, + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); + } + +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.counter.php b/BSF/include/smarty/libs/plugins/function.counter.php new file mode 100644 index 000000000..1f26db5fb --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.counter.php @@ -0,0 +1,80 @@ + + * Name: counter
    + * Purpose: print out a counter value + * @author Monte Ohrt + * @link http://smarty.php.net/manual/en/language.function.counter.php {counter} + * (Smarty online manual) + * @param array parameters + * @param Smarty + * @return string|null + */ +function smarty_function_counter($params, &$smarty) +{ + static $counters = array(); + + $name = (isset($params['name'])) ? $params['name'] : 'default'; + if (!isset($counters[$name])) { + $counters[$name] = array( + 'start'=>1, + 'skip'=>1, + 'direction'=>'up', + 'count'=>1 + ); + } + $counter =& $counters[$name]; + + if (isset($params['start'])) { + $counter['start'] = $counter['count'] = (int)$params['start']; + } + + if (!empty($params['assign'])) { + $counter['assign'] = $params['assign']; + } + + if (isset($counter['assign'])) { + $smarty->assign($counter['assign'], $counter['count']); + } + + if (isset($params['print'])) { + $print = (bool)$params['print']; + } else { + $print = empty($counter['assign']); + } + + if ($print) { + $retval = $counter['count']; + } else { + $retval = null; + } + + if (isset($params['skip'])) { + $counter['skip'] = $params['skip']; + } + + if (isset($params['direction'])) { + $counter['direction'] = $params['direction']; + } + + if ($counter['direction'] == "down") + $counter['count'] -= $counter['skip']; + else + $counter['count'] += $counter['skip']; + + return $retval; + +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.cycle.php b/BSF/include/smarty/libs/plugins/function.cycle.php new file mode 100644 index 000000000..fe78bb87d --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.cycle.php @@ -0,0 +1,102 @@ + + * Name: cycle
    + * Date: May 3, 2002
    + * Purpose: cycle through given values
    + * Input: + * - name = name of cycle (optional) + * - values = comma separated list of values to cycle, + * or an array of values to cycle + * (this can be left out for subsequent calls) + * - reset = boolean - resets given var to true + * - print = boolean - print var or not. default is true + * - advance = boolean - whether or not to advance the cycle + * - delimiter = the value delimiter, default is "," + * - assign = boolean, assigns to template var instead of + * printed. + * + * Examples:
    + *
    + * {cycle values="#eeeeee,#d0d0d0d"}
    + * {cycle name=row values="one,two,three" reset=true}
    + * {cycle name=row}
    + * 
    + * @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle} + * (Smarty online manual) + * @author Monte Ohrt + * @author credit to Mark Priatel + * @author credit to Gerard + * @author credit to Jason Sweat + * @version 1.3 + * @param array + * @param Smarty + * @return string|null + */ +function smarty_function_cycle($params, &$smarty) +{ + static $cycle_vars; + + $name = (empty($params['name'])) ? 'default' : $params['name']; + $print = (isset($params['print'])) ? (bool)$params['print'] : true; + $advance = (isset($params['advance'])) ? (bool)$params['advance'] : true; + $reset = (isset($params['reset'])) ? (bool)$params['reset'] : false; + + if (!in_array('values', array_keys($params))) { + if(!isset($cycle_vars[$name]['values'])) { + $smarty->trigger_error("cycle: missing 'values' parameter"); + return; + } + } else { + if(isset($cycle_vars[$name]['values']) + && $cycle_vars[$name]['values'] != $params['values'] ) { + $cycle_vars[$name]['index'] = 0; + } + $cycle_vars[$name]['values'] = $params['values']; + } + + $cycle_vars[$name]['delimiter'] = (isset($params['delimiter'])) ? $params['delimiter'] : ','; + + if(is_array($cycle_vars[$name]['values'])) { + $cycle_array = $cycle_vars[$name]['values']; + } else { + $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']); + } + + if(!isset($cycle_vars[$name]['index']) || $reset ) { + $cycle_vars[$name]['index'] = 0; + } + + if (isset($params['assign'])) { + $print = false; + $smarty->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]); + } + + if($print) { + $retval = $cycle_array[$cycle_vars[$name]['index']]; + } else { + $retval = null; + } + + if($advance) { + if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) { + $cycle_vars[$name]['index'] = 0; + } else { + $cycle_vars[$name]['index']++; + } + } + + return $retval; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.debug.php b/BSF/include/smarty/libs/plugins/function.debug.php new file mode 100644 index 000000000..43452307b --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.debug.php @@ -0,0 +1,35 @@ + + * Name: debug
    + * Date: July 1, 2002
    + * Purpose: popup debug window + * @link http://smarty.php.net/manual/en/language.function.debug.php {debug} + * (Smarty online manual) + * @author Monte Ohrt + * @version 1.0 + * @param array + * @param Smarty + * @return string output from {@link Smarty::_generate_debug_output()} + */ +function smarty_function_debug($params, &$smarty) +{ + if (isset($params['output'])) { + $smarty->assign('_smarty_debug_output', $params['output']); + } + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + return smarty_core_display_debug_console(null, $smarty); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.eval.php b/BSF/include/smarty/libs/plugins/function.eval.php new file mode 100644 index 000000000..ff0472de2 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.eval.php @@ -0,0 +1,49 @@ + + * Name: eval
    + * Purpose: evaluate a template variable as a template
    + * @link http://smarty.php.net/manual/en/language.function.eval.php {eval} + * (Smarty online manual) + * @author Monte Ohrt + * @param array + * @param Smarty + */ +function smarty_function_eval($params, &$smarty) +{ + + if (!isset($params['var'])) { + $smarty->trigger_error("eval: missing 'var' parameter"); + return; + } + + if($params['var'] == '') { + return; + } + + $smarty->_compile_source('evaluated template', $params['var'], $_var_compiled); + + ob_start(); + $smarty->_eval('?>' . $_var_compiled); + $_contents = ob_get_contents(); + ob_end_clean(); + + if (!empty($params['assign'])) { + $smarty->assign($params['assign'], $_contents); + } else { + return $_contents; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.fetch.php b/BSF/include/smarty/libs/plugins/function.fetch.php new file mode 100644 index 000000000..81b1bfc6b --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.fetch.php @@ -0,0 +1,221 @@ + + * Name: fetch
    + * Purpose: fetch file, web or ftp data and display results + * @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch} + * (Smarty online manual) + * @author Monte Ohrt + * @param array + * @param Smarty + * @return string|null if the assign parameter is passed, Smarty assigns the + * result to a template variable + */ +function smarty_function_fetch($params, &$smarty) +{ + if (empty($params['file'])) { + $smarty->_trigger_fatal_error("[plugin] parameter 'file' cannot be empty"); + return; + } + + $content = ''; + if ($smarty->security && !preg_match('!^(http|ftp)://!i', $params['file'])) { + $_params = array('resource_type' => 'file', 'resource_name' => $params['file']); + require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); + if(!smarty_core_is_secure($_params, $smarty)) { + $smarty->_trigger_fatal_error('[plugin] (secure mode) fetch \'' . $params['file'] . '\' is not allowed'); + return; + } + + // fetch the file + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] . '\''); + return; + } + } else { + // not a local file + if(preg_match('!^http://!i',$params['file'])) { + // http fetch + if($uri_parts = parse_url($params['file'])) { + // set defaults + $host = $server_name = $uri_parts['host']; + $timeout = 30; + $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; + $agent = "Smarty Template Engine ".$smarty->_version; + $referer = ""; + $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/'; + $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : ''; + $_is_proxy = false; + if(empty($uri_parts['port'])) { + $port = 80; + } else { + $port = $uri_parts['port']; + } + if(!empty($uri_parts['user'])) { + $user = $uri_parts['user']; + } + if(!empty($uri_parts['pass'])) { + $pass = $uri_parts['pass']; + } + // loop through parameters, setup headers + foreach($params as $param_key => $param_value) { + switch($param_key) { + case "file": + case "assign": + case "assign_headers": + break; + case "user": + if(!empty($param_value)) { + $user = $param_value; + } + break; + case "pass": + if(!empty($param_value)) { + $pass = $param_value; + } + break; + case "accept": + if(!empty($param_value)) { + $accept = $param_value; + } + break; + case "header": + if(!empty($param_value)) { + if(!preg_match('![\w\d-]+: .+!',$param_value)) { + $smarty->_trigger_fatal_error("[plugin] invalid header format '".$param_value."'"); + return; + } else { + $extra_headers[] = $param_value; + } + } + break; + case "proxy_host": + if(!empty($param_value)) { + $proxy_host = $param_value; + } + break; + case "proxy_port": + if(!preg_match('!\D!', $param_value)) { + $proxy_port = (int) $param_value; + } else { + $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); + return; + } + break; + case "agent": + if(!empty($param_value)) { + $agent = $param_value; + } + break; + case "referer": + if(!empty($param_value)) { + $referer = $param_value; + } + break; + case "timeout": + if(!preg_match('!\D!', $param_value)) { + $timeout = (int) $param_value; + } else { + $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); + return; + } + break; + default: + $smarty->_trigger_fatal_error("[plugin] unrecognized attribute '".$param_key."'"); + return; + } + } + if(!empty($proxy_host) && !empty($proxy_port)) { + $_is_proxy = true; + $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout); + } else { + $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout); + } + + if(!$fp) { + $smarty->_trigger_fatal_error("[plugin] unable to fetch: $errstr ($errno)"); + return; + } else { + if($_is_proxy) { + fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n"); + } else { + fputs($fp, "GET $uri HTTP/1.0\r\n"); + } + if(!empty($host)) { + fputs($fp, "Host: $host\r\n"); + } + if(!empty($accept)) { + fputs($fp, "Accept: $accept\r\n"); + } + if(!empty($agent)) { + fputs($fp, "User-Agent: $agent\r\n"); + } + if(!empty($referer)) { + fputs($fp, "Referer: $referer\r\n"); + } + if(isset($extra_headers) && is_array($extra_headers)) { + foreach($extra_headers as $curr_header) { + fputs($fp, $curr_header."\r\n"); + } + } + if(!empty($user) && !empty($pass)) { + fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n"); + } + + fputs($fp, "\r\n"); + while(!feof($fp)) { + $content .= fgets($fp,4096); + } + fclose($fp); + $csplit = split("\r\n\r\n",$content,2); + + $content = $csplit[1]; + + if(!empty($params['assign_headers'])) { + $smarty->assign($params['assign_headers'],split("\r\n",$csplit[0])); + } + } + } else { + $smarty->_trigger_fatal_error("[plugin] unable to parse URL, check syntax"); + return; + } + } else { + // ftp fetch + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] .'\''); + return; + } + } + + } + + + if (!empty($params['assign'])) { + $smarty->assign($params['assign'],$content); + } else { + return $content; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.html_checkboxes.php b/BSF/include/smarty/libs/plugins/function.html_checkboxes.php new file mode 100644 index 000000000..ed8ad7f33 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.html_checkboxes.php @@ -0,0 +1,143 @@ + + * Type: function
    + * Name: html_checkboxes
    + * Date: 24.Feb.2003
    + * Purpose: Prints out a list of checkbox input types
    + * Input:
    + * - name (optional) - string default "checkbox" + * - values (required) - array + * - options (optional) - associative array + * - checked (optional) - array default not set + * - separator (optional) - ie
    or   + * - output (optional) - the output next to each checkbox + * - assign (optional) - assign the output as an array to this variable + * Examples: + *
    + * {html_checkboxes values=$ids output=$names}
    + * {html_checkboxes values=$ids name='box' separator='
    ' output=$names} + * {html_checkboxes values=$ids checked=$checked separator='
    ' output=$names} + *
    + * @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} + * (Smarty online manual) + * @author Christopher Kvarme + * @author credits to Monte Ohrt + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_checkboxes($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $name = 'checkbox'; + $values = null; + $options = null; + $selected = null; + $separator = ''; + $labels = true; + $output = null; + + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + case 'separator': + $$_key = $_val; + break; + + case 'labels': + $$_key = (bool)$_val; + break; + + case 'options': + $$_key = (array)$_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array)$_val); + break; + + case 'checked': + case 'selected': + $selected = array_map('strval', array_values((array)$_val)); + break; + + case 'checkboxes': + $smarty->trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING); + $options = (array)$_val; + break; + + case 'assign': + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + settype($selected, 'array'); + $_html_result = array(); + + if (isset($options)) { + + foreach ($options as $_key=>$_val) + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + + + } else { + foreach ($values as $_i=>$_key) { + $_val = isset($output[$_i]) ? $output[$_i] : ''; + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + } + + } + + if(!empty($params['assign'])) { + $smarty->assign($params['assign'], $_html_result); + } else { + return implode("\n",$_html_result); + } + +} + +function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) { + $_output = ''; + if ($labels) $_output .= ''; + $_output .= $separator; + + return $_output; +} + +?> diff --git a/BSF/include/smarty/libs/plugins/function.html_image.php b/BSF/include/smarty/libs/plugins/function.html_image.php new file mode 100644 index 000000000..9abae72ef --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.html_image.php @@ -0,0 +1,142 @@ + + * Name: html_image
    + * Date: Feb 24, 2003
    + * Purpose: format HTML tags for the image
    + * Input:
    + * - file = file (and path) of image (required) + * - height = image height (optional, default actual height) + * - width = image width (optional, default actual width) + * - basedir = base directory for absolute paths, default + * is environment variable DOCUMENT_ROOT + * - path_prefix = prefix for path output (optional, default empty) + * + * Examples: {html_image file="/images/masthead.gif"} + * Output: + * @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image} + * (Smarty online manual) + * @author Monte Ohrt + * @author credits to Duda - wrote first image function + * in repository, helped with lots of functionality + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_image($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $alt = ''; + $file = ''; + $height = ''; + $width = ''; + $extra = ''; + $prefix = ''; + $suffix = ''; + $path_prefix = ''; + $server_vars = ($smarty->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; + $basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : ''; + foreach($params as $_key => $_val) { + switch($_key) { + case 'file': + case 'height': + case 'width': + case 'dpi': + case 'path_prefix': + case 'basedir': + $$_key = $_val; + break; + + case 'alt': + if(!is_array($_val)) { + $$_key = smarty_function_escape_special_chars($_val); + } else { + $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + + case 'link': + case 'href': + $prefix = ''; + $suffix = ''; + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (empty($file)) { + $smarty->trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE); + return; + } + + if (substr($file,0,1) == '/') { + $_image_path = $basedir . $file; + } else { + $_image_path = $file; + } + + if(!isset($params['width']) || !isset($params['height'])) { + if(!$_image_data = @getimagesize($_image_path)) { + if(!file_exists($_image_path)) { + $smarty->trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE); + return; + } else if(!is_readable($_image_path)) { + $smarty->trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE); + return; + } else { + $smarty->trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE); + return; + } + } + if ($smarty->security && + ($_params = array('resource_type' => 'file', 'resource_name' => $_image_path)) && + (require_once(SMARTY_CORE_DIR . 'core.is_secure.php')) && + (!smarty_core_is_secure($_params, $smarty)) ) { + $smarty->trigger_error("html_image: (secure) '$_image_path' not in secure directory", E_USER_NOTICE); + } + + if(!isset($params['width'])) { + $width = $_image_data[0]; + } + if(!isset($params['height'])) { + $height = $_image_data[1]; + } + + } + + if(isset($params['dpi'])) { + if(strstr($server_vars['HTTP_USER_AGENT'], 'Mac')) { + $dpi_default = 72; + } else { + $dpi_default = 96; + } + $_resize = $dpi_default/$params['dpi']; + $width = round($width * $_resize); + $height = round($height * $_resize); + } + + return $prefix . ''.$alt.'' . $suffix; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.html_options.php b/BSF/include/smarty/libs/plugins/function.html_options.php new file mode 100644 index 000000000..cebadde47 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.html_options.php @@ -0,0 +1,122 @@ + + * Name: html_options
    + * Input:
    + * - name (optional) - string default "select" + * - values (required if no options supplied) - array + * - options (required if no values supplied) - associative array + * - selected (optional) - string default not set + * - output (required if not options supplied) - array + * Purpose: Prints the list of