From ec831471ba50f7a7b703a2b944c19966886d3ae5 Mon Sep 17 00:00:00 2001 From: Exile Date: Fri, 24 Oct 2014 21:10:33 +0400 Subject: [PATCH 01/32] =?UTF-8?q?=D0=A0=D0=BE=D1=81=D1=81=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D1=85=D0=BE=D0=B4=D0=B8=D1=82=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=B7=D0=B8=D0=BC=D0=BD=D0=B5=D0=B5=20=D0=B2=D1=80?= =?UTF-8?q?=D0=B5=D0=BC=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- upload/library/language/ru/main.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/upload/library/language/ru/main.php b/upload/library/language/ru/main.php index e021e08a2..a0536731a 100644 --- a/upload/library/language/ru/main.php +++ b/upload/library/language/ru/main.php @@ -901,9 +901,9 @@ $lang['TZ']['-1'] = 'UTC - 1'; $lang['TZ']['0'] = 'UTC ± 0'; $lang['TZ']['1'] = 'UTC + 1'; $lang['TZ']['2'] = 'UTC + 2'; -$lang['TZ']['3'] = 'UTC + 3'; +$lang['TZ']['3'] = 'UTC + 3 (Московское время)'; $lang['TZ']['3.5'] = 'UTC + 3:30'; -$lang['TZ']['4'] = 'UTC + 4 (Московское время)'; +$lang['TZ']['4'] = 'UTC + 4'; $lang['TZ']['4.5'] = 'UTC + 4:30'; $lang['TZ']['5'] = 'UTC + 5'; $lang['TZ']['5.5'] = 'UTC + 5:30'; From d4c77489c746db97621577cede3f4015db60e140 Mon Sep 17 00:00:00 2001 From: Exile Date: Sat, 25 Oct 2014 14:00:30 +0400 Subject: [PATCH 02/32] =?UTF-8?q?=D0=A0=D0=BE=D1=81=D1=81=D0=BA=D0=B8?= =?UTF-8?q?=D0=B9=D1=81=D0=BA=D0=B8=D0=B5=20=D1=87=D0=B0=D1=81=D0=BE=D0=B2?= =?UTF-8?q?=D1=8B=D0=B5=20=D0=BF=D0=BE=D1=8F=D1=81=D0=B0=20=D0=B2=20=D0=B2?= =?UTF-8?q?=D1=8B=D0=BF=D0=B0=D0=B4=D0=B0=D1=8E=D1=89=D0=B8=D0=B9=20=D1=81?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D0=BE=D0=BA=20=D0=B4=D0=BB=D1=8F=20=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=B5=D0=BD=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- upload/library/language/ru/main.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/upload/library/language/ru/main.php b/upload/library/language/ru/main.php index a0536731a..a45dacbb1 100644 --- a/upload/library/language/ru/main.php +++ b/upload/library/language/ru/main.php @@ -884,7 +884,7 @@ $lang['LOOKUP_IP'] = 'Посмотреть хост для IP'; // Timezones ... for display on each page $lang['ALL_TIMES'] = 'Часовой пояс: %s'; // This is followed by UTC and the timezone offset -// это для выпадающего меню, раньше тут еще были города +// это для выпадающего меню часовых поясов $lang['TZ']['-12'] = 'UTC - 12'; $lang['TZ']['-11'] = 'UTC - 11'; $lang['TZ']['-10'] = 'UTC - 10'; @@ -900,22 +900,22 @@ $lang['TZ']['-2'] = 'UTC - 2'; $lang['TZ']['-1'] = 'UTC - 1'; $lang['TZ']['0'] = 'UTC ± 0'; $lang['TZ']['1'] = 'UTC + 1'; -$lang['TZ']['2'] = 'UTC + 2'; -$lang['TZ']['3'] = 'UTC + 3 (Московское время)'; +$lang['TZ']['2'] = 'UTC + 2 (Калининградское время | USZ1)'; +$lang['TZ']['3'] = 'UTC + 3 (Московское время | MSK)'; $lang['TZ']['3.5'] = 'UTC + 3:30'; -$lang['TZ']['4'] = 'UTC + 4'; +$lang['TZ']['4'] = 'UTC + 4 (Самарское время | SAMT)'; $lang['TZ']['4.5'] = 'UTC + 4:30'; -$lang['TZ']['5'] = 'UTC + 5'; +$lang['TZ']['5'] = 'UTC + 5 (Екатеринбургское время | YEKT)'; $lang['TZ']['5.5'] = 'UTC + 5:30'; -$lang['TZ']['6'] = 'UTC + 6'; +$lang['TZ']['6'] = 'UTC + 6 (Омское время | OMST)'; $lang['TZ']['6.5'] = 'UTC + 6:30'; -$lang['TZ']['7'] = 'UTC + 7'; -$lang['TZ']['8'] = 'UTC + 8'; -$lang['TZ']['9'] = 'UTC + 9'; +$lang['TZ']['7'] = 'UTC + 7 (Красноярское время | KRAT)'; +$lang['TZ']['8'] = 'UTC + 8 (Иркутское время | IRKT)'; +$lang['TZ']['9'] = 'UTC + 9 (Якутское время | YAKT)'; $lang['TZ']['9.5'] = 'UTC + 9:30'; -$lang['TZ']['10'] = 'UTC + 10'; -$lang['TZ']['11'] = 'UTC + 11'; -$lang['TZ']['12'] = 'UTC + 12'; +$lang['TZ']['10'] = 'UTC + 10 (Владивостокское время | VLAT)'; +$lang['TZ']['11'] = 'UTC + 11 (Среднеколымское время | SRET)'; +$lang['TZ']['12'] = 'UTC + 12 (Камчатское время | PETT)'; $lang['TZ']['13'] = 'UTC + 13'; $lang['DATETIME']['TODAY'] = 'Сегодня, в'; From b370d8478691d1341a79073f90f6975ac49ea1d1 Mon Sep 17 00:00:00 2001 From: Dmitry Larchikov Date: Sun, 26 Oct 2014 23:13:05 +0300 Subject: [PATCH 03/32] develop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit При вызове из командной строки лезут нотисы. Пофиксил. --- upload/library/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upload/library/includes/functions.php b/upload/library/includes/functions.php index ff885e61c..bac63225a 100644 --- a/upload/library/includes/functions.php +++ b/upload/library/includes/functions.php @@ -1868,7 +1868,7 @@ function bb_realpath ($path) function login_redirect ($url = '') { - redirect(LOGIN_URL . '?redirect='. (($url) ? $url : $_SERVER['REQUEST_URI'])); + redirect(LOGIN_URL . '?redirect='. (($url) ? $url : (isset($_SERVER['REQUEST_URI']) ?: '/'))); } function meta_refresh ($url, $time = 5) From 584f6922885ec660ee9c88d97108ac64aa4475ed Mon Sep 17 00:00:00 2001 From: Dmitry Larchikov Date: Tue, 28 Oct 2014 18:06:22 +0300 Subject: [PATCH 04/32] develop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Подавление ошибок довольно медленная операция. Немножко убрал. --- upload/common.php | 14 ++++++++++--- upload/dl.php | 2 +- upload/dl_list.php | 12 +++++------ upload/feed.php | 6 +++--- upload/group.php | 4 ++-- upload/library/includes/functions.php | 2 +- upload/login.php | 4 ++-- upload/memberlist.php | 2 +- upload/modcp.php | 30 +++++++++++++++++++-------- 9 files changed, 48 insertions(+), 28 deletions(-) diff --git a/upload/common.php b/upload/common.php index 0062edf4e..68ae49dc5 100644 --- a/upload/common.php +++ b/upload/common.php @@ -2086,9 +2086,17 @@ function log_request ($file = '', $prepend_str = false, $add_post = true) if ($prepend_str !== false) $str[] = $prepend_str; if (!empty($user->data)) $str[] = $user->id ."\t". html_entity_decode($user->name); $str[] = sprintf('%-15s', $_SERVER['REMOTE_ADDR']); - $str[] = @$_SERVER['REQUEST_URI']; - $str[] = @$_SERVER['HTTP_USER_AGENT']; - $str[] = @$_SERVER['HTTP_REFERER']; + + if (isset($_SERVER['REQUEST_URI'])) { + $str[] = $_SERVER['REQUEST_URI']; + } + if (isset($_SERVER['HTTP_USER_AGENT'])) { + $str[] = $_SERVER['HTTP_USER_AGENT']; + } + if (isset($_SERVER['HTTP_REFERER'])) { + $str[] = $_SERVER['HTTP_REFERER']; + } + if (!empty($_POST) && $add_post) $str[] = "post: ". str_compact(urldecode(http_build_query($_POST))); $str = join("\t", $str) . "\n"; bb_log($str, $file); diff --git a/upload/dl.php b/upload/dl.php index 29f72bd3f..52045d945 100644 --- a/upload/dl.php +++ b/upload/dl.php @@ -207,7 +207,7 @@ else { global $template; - $redirect_url = !empty($_POST['redirect_url']) ? $_POST['redirect_url'] : @$_SERVER['HTTP_REFERER']; + $redirect_url = isset($_POST['redirect_url']) ? $_POST['redirect_url'] : (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/' ); $message = '
'; $message .= $lang['CONFIRM_CODE']; $message .= '
'. CAPTCHA()->get_html() .'
'; diff --git a/upload/dl_list.php b/upload/dl_list.php index 574c014a0..d4db8fd9c 100644 --- a/upload/dl_list.php +++ b/upload/dl_list.php @@ -5,9 +5,9 @@ define('BB_SCRIPT', 'dl_list'); define('BB_ROOT', './'); require(BB_ROOT .'common.php'); -$forum_id = (@$_REQUEST[POST_FORUM_URL]) ? (int) $_REQUEST[POST_FORUM_URL] : 0; -$topic_id = (@$_REQUEST[POST_TOPIC_URL]) ? (int) $_REQUEST[POST_TOPIC_URL] : 0; -$mode = (@$_REQUEST['mode']) ? (string) $_REQUEST['mode'] : ''; +$forum_id = isset($_REQUEST[POST_FORUM_URL]) ? (int) $_REQUEST[POST_FORUM_URL] : 0; +$topic_id = isset($_REQUEST[POST_TOPIC_URL]) ? (int) $_REQUEST[POST_TOPIC_URL] : 0; +$mode = isset($_REQUEST['mode']) ? (string) $_REQUEST['mode'] : ''; $confirmed = isset($_POST['confirm']); // Get new DL-status @@ -40,9 +40,9 @@ if ($mode == 'set_dl_status' || $mode == 'set_topics_dl_status') } // Define redirect URL -$full_url = (@$_POST['full_url']) ? str_replace('&', '&', htmlspecialchars($_POST['full_url'])) : ''; +$full_url = isset($_POST['full_url']) ? str_replace('&', '&', htmlspecialchars($_POST['full_url'])) : ''; -if (@$_POST['redirect_type'] == 'search') +if (isset($_POST['redirect_type']) && $_POST['redirect_type'] == 'search') { $redirect_type = "search.php"; $redirect = ($full_url) ? $full_url : "$dl_key=1"; @@ -65,7 +65,7 @@ if (!$userdata['session_logged_in']) } // Check if user did not confirm -if (@$_POST['cancel']) +if (isset($_POST['cancel']) && $_POST['cancel']) { redirect("$redirect_type?$redirect"); } diff --git a/upload/feed.php b/upload/feed.php index 87b981957..454c6dd56 100644 --- a/upload/feed.php +++ b/upload/feed.php @@ -7,9 +7,9 @@ require(BB_ROOT .'common.php'); $user->session_start(array('req_login' => true)); -$mode = (string) @$_REQUEST['mode']; -$type = (string) @$_POST['type']; -$id = (int) @$_POST['id']; +$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : ''; +$type = isset($_POST['type']) ? $_POST['type'] : ''; +$id = isset($_POST['id']) ? $_POST['id'] : 0; $timecheck = TIMENOW - 600; if (!$mode) bb_simple_die($lang['ATOM_NO_MODE']); diff --git a/upload/group.php b/upload/group.php index 07fc133d6..38778d453 100644 --- a/upload/group.php +++ b/upload/group.php @@ -188,7 +188,7 @@ if (!$group_id) else bb_die($lang['NO_GROUPS_EXIST']); } } -else if (@$_POST['joingroup']) +else if (isset($_POST['joingroup']) && $_POST['joingroup']) { if ($group_info['group_type'] != GROUP_OPEN) { @@ -263,7 +263,7 @@ else if (!empty($_POST['add'])) { - if (!$row = get_userdata(@$_POST['username'], true)) + if (isset($_POST['username']) && !($row = get_userdata($_POST['username'], true))) { bb_die($lang['COULD_NOT_ADD_USER']); } diff --git a/upload/library/includes/functions.php b/upload/library/includes/functions.php index bac63225a..f10969194 100644 --- a/upload/library/includes/functions.php +++ b/upload/library/includes/functions.php @@ -1868,7 +1868,7 @@ function bb_realpath ($path) function login_redirect ($url = '') { - redirect(LOGIN_URL . '?redirect='. (($url) ? $url : (isset($_SERVER['REQUEST_URI']) ?: '/'))); + redirect(LOGIN_URL . '?redirect='. (($url) ? $url : (isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/'))); } function meta_refresh ($url, $time = 5) diff --git a/upload/login.php b/upload/login.php index e959e2eb5..0a4ab9c1f 100644 --- a/upload/login.php +++ b/upload/login.php @@ -57,8 +57,8 @@ if (isset($_REQUEST['admin']) && !IS_AM) bb_die($lang['NOT_ADMIN']); $mod_admin_login = (IS_AM && !$user->data['session_admin']); // login username & password -$login_username = ($mod_admin_login) ? $userdata['username'] : (string) @$_POST['login_username']; -$login_password = (string) @$_POST['login_password']; +$login_username = ($mod_admin_login) ? $userdata['username'] : (isset($_POST['login_username']) ? $_POST['login_username'] : ''); +$login_password = isset($_POST['login_password']) ? $_POST['login_password'] : ''; // Проверка на неверную комбинацию логин/пароль $need_captcha = false; diff --git a/upload/memberlist.php b/upload/memberlist.php index fc0ff96bd..7a55374d0 100644 --- a/upload/memberlist.php +++ b/upload/memberlist.php @@ -108,7 +108,7 @@ $letters_range .= '-'; $letters_range .= iconv('windows-1251', 'UTF-8', chr(255)); $select_letter = $letter_sql = ''; -$by_letter_req = (@$_REQUEST['letter']) ? strtolower(trim($_REQUEST['letter'])) : false; +$by_letter_req = isset($_REQUEST['letter']) ? strtolower(trim($_REQUEST['letter'])) : false; if ($by_letter_req) { diff --git a/upload/modcp.php b/upload/modcp.php index 0da5cffad..831e2a9fe 100644 --- a/upload/modcp.php +++ b/upload/modcp.php @@ -58,10 +58,22 @@ function validate_topics ($forum_id, &$req_topics, &$topic_titles) $topic_titles = $valid_titles; } +/** + * @param $request_index + * @param $mod_action + * @return bool + */ +function validate_mode_condition($request_index, $mod_action='') { + if (!$mod_action) { + $mod_action = $request_index; + } + return (isset($_REQUEST[$request_index]) || (isset($_POST['mod_action']) && $_POST['mod_action'] === $mod_action)); +} + // Obtain initial vars -$forum_id = (int) @$_REQUEST['f']; -$topic_id = (int) @$_REQUEST['t']; -$post_id = (int) @$_REQUEST['p']; +$forum_id = isset($_REQUEST['f']) ? $_REQUEST['f'] : 0; +$topic_id = isset($_REQUEST['t']) ? $_REQUEST['t'] : 0; +$post_id = isset($_REQUEST['p']) ? $_REQUEST['p'] : 0; $start = isset($_REQUEST['start']) ? abs(intval($_REQUEST['start'])) : 0; $confirmed = isset($_POST['confirm']); @@ -74,27 +86,27 @@ if (isset($_REQUEST['mode'])) } else { - if (isset($_REQUEST['delete']) || @$_POST['mod_action'] === 'topic_delete') + if (validate_mode_condition('delete', 'topic_delete')) { $mode = 'delete'; } - elseif (isset($_REQUEST['move']) || @$_POST['mod_action'] === 'topic_move') + elseif (validate_mode_condition('move', 'topic_move')) { $mode = 'move'; } - elseif (isset($_REQUEST['lock']) || @$_POST['mod_action'] === 'topic_lock') + elseif (validate_mode_condition('lock', 'topic_lock')) { $mode = 'lock'; } - elseif (isset($_REQUEST['unlock']) || @$_POST['mod_action'] === 'topic_unlock') + elseif (validate_mode_condition('unlock', 'topic_unlock')) { $mode = 'unlock'; } - elseif (isset($_REQUEST['post_pin']) || @$_POST['mod_action'] === 'post_pin') + elseif (validate_mode_condition('post_pin')) { $mode = 'post_pin'; } - elseif (isset($_REQUEST['post_unpin']) || @$_POST['mod_action'] === 'post_unpin') + elseif (validate_mode_condition('post_unpin')) { $mode = 'post_unpin'; } From f94c0dd2eedabd0fe1208f325cb74d0a6d95703d Mon Sep 17 00:00:00 2001 From: Exile Date: Tue, 28 Oct 2014 21:35:42 +0300 Subject: [PATCH 05/32] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2=20=D0=B4=D0=B2?= =?UTF-8?q?=D0=B8=D0=B6=D0=BA=D0=B0=20=D0=B2=20=D0=BA=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- upload/.htaccess => .htaccess | 0 README.md | 2 +- {upload/admin => admin}/admin_attach_cp.php | 0 {upload/admin => admin}/admin_attachments.php | 0 {upload/admin => admin}/admin_board.php | 0 {upload/admin => admin}/admin_bt_forum_cfg.php | 0 {upload/admin => admin}/admin_bt_tracker_cfg.php | 0 {upload/admin => admin}/admin_cron.php | 0 {upload/admin => admin}/admin_disallow.php | 0 {upload/admin => admin}/admin_extensions.php | 0 {upload/admin => admin}/admin_forum_prune.php | 0 {upload/admin => admin}/admin_forumauth.php | 0 {upload/admin => admin}/admin_forumauth_list.php | 0 {upload/admin => admin}/admin_forums.php | 0 {upload/admin => admin}/admin_groups.php | 0 {upload/admin => admin}/admin_log.php | 0 {upload/admin => admin}/admin_mass_email.php | 0 {upload/admin => admin}/admin_phpinfo.php | 0 {upload/admin => admin}/admin_ranks.php | 0 {upload/admin => admin}/admin_rebuild_search.php | 0 {upload/admin => admin}/admin_sitemap.php | 0 {upload/admin => admin}/admin_smilies.php | 0 {upload/admin => admin}/admin_terms.php | 0 {upload/admin => admin}/admin_ug_auth.php | 0 {upload/admin => admin}/admin_user_ban.php | 0 {upload/admin => admin}/admin_user_search.php | 0 {upload/admin => admin}/admin_words.php | 0 {upload/admin => admin}/index.php | 0 {upload/admin => admin}/pagestart.php | 0 {upload/admin => admin}/stats/tr_stats.php | 0 {upload/admin => admin}/stats/tracker.php | 0 upload/ajax.php => ajax.php | 0 {upload/bt => bt}/announce.php | 2 +- {upload/bt => bt}/includes/.htaccess | 0 {upload/bt => bt}/includes/init_tr.php | 0 {upload/bt => bt}/index.php | 0 {upload/bt => bt}/robots.txt | 0 {upload/bt => bt}/scrape.php | 2 +- upload/callseed.php => callseed.php | 0 upload/common.php => common.php | 2 +- upload/cron.php => cron.php | 0 upload/crossdomain.xml => crossdomain.xml | 0 {upload/data => data}/avatars/gallery/bot.gif | Bin {upload/data => data}/avatars/gallery/noavatar.png | Bin {upload/data => data}/old_files/.htaccess | 0 {upload/data => data}/torrent_files/.htaccess | 0 upload/dl.php => dl.php | 0 upload/dl_list.php => dl_list.php | 0 upload/favicon.ico => favicon.ico | Bin upload/feed.php => feed.php | 0 upload/group.php => group.php | 0 upload/group_edit.php => group_edit.php | 0 upload/index.php => index.php | 0 upload/info.php => info.php | 2 +- .../other}/converter/TBDevYSE_pre6/ReadMe.txt | 0 .../converter/TBDevYSE_pre6/for_tbdev/announce.php | 2 +- .../converter/TBDevYSE_pre6/for_tbdev/pass.php | 0 .../other}/converter/TBDevYSE_pre6/root/convert.php | 6 +++--- .../TBDevYSE_pre6/root/converter/constants.php | 0 .../TBDevYSE_pre6/root/converter/functions.php | 0 .../TBDevYSE_pre6/root/converter/passwords.php | 0 .../TBDevYSE_pre6/root/converter/settings.php | 0 .../other}/converter/TBDevYSE_pre6/root/recover.php | 4 ++-- .../other}/recover/converter/constants.php | 0 .../other}/recover/converter/functions.php | 0 .../other}/recover/converter/passwords.php | 0 .../other}/recover/converter/settings.php | 0 {other => install/other}/recover/recover.php | 4 ++-- install/php-fpm+nginx/nginx.conf | 2 +- {upgrade => install/upgrade}/changes.txt | 0 {upgrade => install/upgrade}/r496-user_birthday.php | 0 {upgrade => install/upgrade}/r571-dl_upgrade.php | 0 {upgrade => install/upgrade}/r575-poll_upgrade.php | 0 .../upgrade}/r583-convert_avatars.php | 0 {upgrade => install/upgrade}/r588-short_lang.php | 0 {upgrade => install/upgrade}/r600-stable.php | 0 .../ajax_html/jumpbox_guest.html | 0 .../ajax_html/jumpbox_user.html | 0 {upload/internal_data => internal_data}/atom/.keep | 0 .../internal_data => internal_data}/cache/.htaccess | 0 .../internal_data => internal_data}/captcha/.keep | 0 .../internal_data => internal_data}/log/.htaccess | 0 .../log/cron/.htaccess | 0 .../internal_data => internal_data}/sitemap/.keep | 0 .../internal_data => internal_data}/triggers/$on | 0 .../triggers/.htaccess | 0 .../triggers/cron_allowed | 0 {upload/library => library}/ajax/avatar.php | 0 .../library => library}/ajax/change_tor_status.php | 0 {upload/library => library}/ajax/change_torrent.php | 0 .../library => library}/ajax/change_user_opt.php | 0 .../library => library}/ajax/change_user_rank.php | 0 .../library => library}/ajax/edit_group_profile.php | 0 .../library => library}/ajax/edit_user_profile.php | 0 {upload/library => library}/ajax/gen_passkey.php | 0 .../library => library}/ajax/group_membership.php | 0 {upload/library => library}/ajax/index_data.php | 0 {upload/library => library}/ajax/manage_admin.php | 0 {upload/library => library}/ajax/manage_user.php | 0 {upload/library => library}/ajax/mod_action.php | 0 .../library => library}/ajax/post_mod_comment.php | 0 {upload/library => library}/ajax/posts.php | 0 {upload/library => library}/ajax/sitemap.php | 0 {upload/library => library}/ajax/topic_tpl.php | 0 {upload/library => library}/ajax/user_register.php | 0 {upload/library => library}/ajax/view_post.php | 0 {upload/library => library}/ajax/view_torrent.php | 0 {upload/library => library}/attach_mod/.htaccess | 0 .../attach_mod/attachment_mod.php | 0 .../library => library}/attach_mod/displaying.php | 0 .../attach_mod/displaying_torrent.php | 0 .../attach_mod/includes/.htaccess | 0 .../attach_mod/includes/functions_admin.php | 0 .../attach_mod/includes/functions_attach.php | 0 .../attach_mod/includes/functions_delete.php | 0 .../attach_mod/includes/functions_filetypes.php | 0 .../attach_mod/includes/functions_includes.php | 0 .../attach_mod/includes/functions_selects.php | 0 .../attach_mod/includes/functions_thumbs.php | 0 .../attach_mod/posting_attachments.php | 0 {upload/library => library}/config.php | 0 {upload/library => library}/includes/.htaccess | 0 {upload/library => library}/includes/api/sphinx.php | 0 {upload/library => library}/includes/bbcode.php | 0 .../library => library}/includes/captcha/.htaccess | 0 .../includes/captcha/captcha.php | 0 .../includes/captcha/kcaptcha/fonts/antiqua.png | Bin .../includes/captcha/kcaptcha/fonts/baskerville.png | Bin .../includes/captcha/kcaptcha/fonts/batang.png | Bin .../includes/captcha/kcaptcha/fonts/bookman.png | Bin .../includes/captcha/kcaptcha/fonts/calisto.png | Bin .../includes/captcha/kcaptcha/fonts/cambria.png | Bin .../includes/captcha/kcaptcha/fonts/centaur.png | Bin .../includes/captcha/kcaptcha/fonts/century.png | Bin .../includes/captcha/kcaptcha/fonts/chaparral.png | Bin .../includes/captcha/kcaptcha/fonts/constantia.png | Bin .../includes/captcha/kcaptcha/fonts/footlight.png | Bin .../includes/captcha/kcaptcha/fonts/garamond.png | Bin .../includes/captcha/kcaptcha/fonts/georgia.png | Bin .../includes/captcha/kcaptcha/fonts/goudy_old.png | Bin .../includes/captcha/kcaptcha/fonts/kozuka.png | Bin .../includes/captcha/kcaptcha/fonts/lucida.png | Bin .../includes/captcha/kcaptcha/fonts/minion.png | Bin .../includes/captcha/kcaptcha/fonts/palatino.png | Bin .../includes/captcha/kcaptcha/fonts/perpetua.png | Bin .../includes/captcha/kcaptcha/fonts/rockwell.png | Bin .../includes/captcha/kcaptcha/fonts/times.png | Bin .../includes/captcha/kcaptcha/fonts/warnock.png | Bin .../library => library}/includes/classes/.htaccess | 0 .../includes/classes/correct.php | 0 .../includes/classes/emailer.php | 0 .../includes/classes/reflection.php | 0 .../includes/classes/sitemap.php | 0 .../library => library}/includes/classes/utf8.php | 0 {upload/library => library}/includes/core/mysql.php | 0 {upload/library => library}/includes/cron/.htaccess | 0 .../includes/cron/cron_check.php | 0 .../library => library}/includes/cron/cron_init.php | 0 .../library => library}/includes/cron/cron_run.php | 0 .../includes/cron/jobs/.htaccess | 0 .../includes/cron/jobs/attach_maintenance.php | 0 .../includes/cron/jobs/board_maintenance.php | 0 .../includes/cron/jobs/cache_gc.php | 0 .../includes/cron/jobs/captcha_gen_gc.php | 0 .../includes/cron/jobs/clean_dlstat.php | 0 .../includes/cron/jobs/clean_log.php | 0 .../includes/cron/jobs/clean_search_results.php | 0 .../includes/cron/jobs/ds_update_cat_forums.php | 0 .../includes/cron/jobs/ds_update_stats.php | 0 .../includes/cron/jobs/flash_topic_view.php | 0 .../includes/cron/jobs/prune_forums.php | 0 .../includes/cron/jobs/prune_inactive_users.php | 0 .../includes/cron/jobs/prune_topic_moved.php | 0 .../includes/cron/jobs/sessions_cleanup.php | 0 .../includes/cron/jobs/sitemap.php | 0 .../includes/cron/jobs/tr_cleanup_and_dlstat.php | 0 .../includes/cron/jobs/tr_complete_count.php | 0 .../includes/cron/jobs/tr_maintenance.php | 0 .../includes/cron/jobs/tr_make_snapshot.php | 0 .../cron/jobs/tr_update_seeder_last_seen.php | 0 .../includes/cron/jobs/update_forums_atom.php | 0 .../includes/datastore/.htaccess | 0 .../includes/datastore/build_attach_extensions.php | 0 .../includes/datastore/build_cat_forums.php | 0 .../includes/datastore/build_moderators.php | 0 .../includes/datastore/build_ranks.php | 0 .../includes/datastore/build_smilies.php | 0 .../includes/datastore/build_stats.php | 0 {upload/library => library}/includes/functions.php | 0 .../includes/functions_admin.php | 0 .../includes/functions_admin_cron.php | 0 .../includes/functions_admin_torrent.php | 0 .../library => library}/includes/functions_atom.php | 0 .../library => library}/includes/functions_dev.php | 0 .../includes/functions_group.php | 0 .../library => library}/includes/functions_post.php | 0 .../includes/functions_selects.php | 0 .../includes/functions_torrent.php | 0 .../includes/functions_upload.php | 0 .../includes/functions_validate.php | 0 {upload/library => library}/includes/init_bb.php | 0 .../includes/online_userlist.php | 0 .../library => library}/includes/page_footer.php | 0 .../includes/page_footer_dev.php | 0 .../library => library}/includes/page_header.php | 0 .../library => library}/includes/posting_tpl.php | 0 {upload/library => library}/includes/sessions.php | 0 {upload/library => library}/includes/smtp.php | 0 {upload/library => library}/includes/sql_parse.php | 0 {upload/library => library}/includes/template.php | 0 .../includes/torrent_announce_urls.php | 0 .../includes/torrent_show_dl_list.php | 0 {upload/library => library}/includes/ucp/.htaccess | 0 .../library => library}/includes/ucp/activate.php | 0 {upload/library => library}/includes/ucp/bonus.php | 0 {upload/library => library}/includes/ucp/email.php | 0 .../library => library}/includes/ucp/register.php | 0 .../library => library}/includes/ucp/sendpasswd.php | 0 .../includes/ucp/topic_watch.php | 0 .../includes/ucp/viewprofile.php | 0 .../includes/ucp/viewtorrent.php | 0 {upload/library => library}/language/.htaccess | 0 {upload/library => library}/language/en/.htaccess | 0 .../library => library}/language/en/email/.htaccess | 0 .../language/en/email/admin_send_email.tpl | 0 .../library => library}/language/en/email/blank.tpl | 0 .../language/en/email/group_added.tpl | 0 .../language/en/email/group_approved.tpl | 0 .../language/en/email/group_request.tpl | 0 .../language/en/email/privmsg_notify.tpl | 0 .../language/en/email/profile_send_email.tpl | 0 .../language/en/email/topic_notify.tpl | 0 .../language/en/email/user_activate.tpl | 0 .../language/en/email/user_activate_passwd.tpl | 0 .../language/en/email/user_welcome.tpl | 0 .../language/en/email/user_welcome_inactive.tpl | 0 .../library => library}/language/en/html/.htaccess | 0 .../language/en/html/advert.html | 0 .../language/en/html/copyright_holders.html | 0 .../language/en/html/not_found.html | 0 .../language/en/html/sidebar1.html | 0 .../language/en/html/sidebar2.html | 0 .../language/en/html/user_agreement.html | 0 {upload/library => library}/language/en/main.php | 0 .../language/en/search_stopwords.txt | 0 .../language/en/search_synonyms.txt | 0 {upload/library => library}/language/ru/.htaccess | 0 .../library => library}/language/ru/email/.htaccess | 0 .../language/ru/email/admin_send_email.tpl | 0 .../library => library}/language/ru/email/blank.tpl | 0 .../language/ru/email/group_added.tpl | 0 .../language/ru/email/group_approved.tpl | 0 .../language/ru/email/group_request.tpl | 0 .../language/ru/email/privmsg_notify.tpl | 0 .../language/ru/email/profile_send_email.tpl | 0 .../language/ru/email/topic_notify.tpl | 0 .../language/ru/email/user_activate.tpl | 0 .../language/ru/email/user_activate_passwd.tpl | 0 .../language/ru/email/user_welcome.tpl | 0 .../language/ru/email/user_welcome_inactive.tpl | 0 .../library => library}/language/ru/html/.htaccess | 0 .../language/ru/html/advert.html | 0 .../language/ru/html/copyright_holders.html | 0 .../language/ru/html/not_found.html | 0 .../language/ru/html/sidebar1.html | 0 .../language/ru/html/sidebar2.html | 0 .../language/ru/html/user_agreement.html | 0 {upload/library => library}/language/ru/main.php | 0 .../language/ru/search_stopwords.txt | 0 .../language/ru/search_synonyms.txt | 0 {upload/library => library}/language/uk/.htaccess | 0 .../library => library}/language/uk/email/.htaccess | 0 .../language/uk/email/admin_send_email.tpl | 0 .../library => library}/language/uk/email/blank.tpl | 0 .../language/uk/email/group_added.tpl | 0 .../language/uk/email/group_approved.tpl | 0 .../language/uk/email/group_request.tpl | 0 .../language/uk/email/privmsg_notify.tpl | 0 .../language/uk/email/profile_send_email.tpl | 0 .../language/uk/email/topic_notify.tpl | 0 .../language/uk/email/user_activate.tpl | 0 .../language/uk/email/user_activate_passwd.tpl | 0 .../language/uk/email/user_welcome.tpl | 0 .../language/uk/email/user_welcome_inactive.tpl | 0 .../library => library}/language/uk/html/.htaccess | 0 .../language/uk/html/advert.html | 0 .../language/uk/html/copyright_holders.html | 0 .../language/uk/html/not_found.html | 0 .../language/uk/html/sidebar1.html | 0 .../language/uk/html/sidebar2.html | 0 .../language/uk/html/user_agreement.html | 0 {upload/library => library}/language/uk/main.php | 0 .../language/uk/search_stopwords.txt | 0 .../language/uk/search_synonyms.txt | 0 upload/login.php => login.php | 0 upload/memberlist.php => memberlist.php | 0 upload/modcp.php => modcp.php | 0 upload/opensearch_desc.xml => opensearch_desc.xml | 0 ...opensearch_desc_bt.xml => opensearch_desc_bt.xml | 0 upload/poll.php => poll.php | 0 upload/posting.php => posting.php | 0 upload/privmsg.php => privmsg.php | 0 upload/profile.php => profile.php | 0 upload/robots.txt => robots.txt | 0 upload/search.php => search.php | 0 .../bootstrap/css/bootstrap-theme.css | 0 .../bootstrap/css/bootstrap-theme.css.map | 0 .../bootstrap/css/bootstrap-theme.min.css | 0 .../styles => styles}/bootstrap/css/bootstrap.css | 0 .../bootstrap/css/bootstrap.css.map | 0 .../bootstrap/css/bootstrap.min.css | 0 .../fonts/glyphicons-halflings-regular.eot | Bin .../fonts/glyphicons-halflings-regular.svg | 0 .../fonts/glyphicons-halflings-regular.ttf | Bin .../fonts/glyphicons-halflings-regular.woff | Bin {upload/styles => styles}/bootstrap/js/bootstrap.js | 0 .../styles => styles}/bootstrap/js/bootstrap.min.js | 0 {upload/styles => styles}/images/bad.gif | Bin {upload/styles => styles}/images/dc_magnet.png | Bin {upload/styles => styles}/images/dc_magnet_ext.png | Bin {upload/styles => styles}/images/folder.gif | Bin {upload/styles => styles}/images/good.gif | Bin {upload/styles => styles}/images/icon_clip.gif | Bin {upload/styles => styles}/images/icon_delete.gif | Bin {upload/styles => styles}/images/icon_dn.gif | Bin {upload/styles => styles}/images/icon_edit.gif | Bin {upload/styles => styles}/images/icon_external.png | Bin {upload/styles => styles}/images/icon_run.gif | Bin {upload/styles => styles}/images/icon_sync.gif | Bin {upload/styles => styles}/images/logo/logo.png | Bin .../styles => styles}/images/logo/logo_summer.png | Bin {upload/styles => styles}/images/magnet.png | Bin {upload/styles => styles}/images/page.gif | Bin {upload/styles => styles}/images/pic_loading.gif | Bin {upload/styles => styles}/images/ranks/admin.png | Bin {upload/styles => styles}/images/ranks/user.png | Bin {upload/styles => styles}/images/smiles/aa.gif | Bin {upload/styles => styles}/images/smiles/ab.gif | Bin {upload/styles => styles}/images/smiles/ac.gif | Bin {upload/styles => styles}/images/smiles/ad.gif | Bin {upload/styles => styles}/images/smiles/ae.gif | Bin {upload/styles => styles}/images/smiles/af.gif | Bin {upload/styles => styles}/images/smiles/ag.gif | Bin {upload/styles => styles}/images/smiles/ah.gif | Bin {upload/styles => styles}/images/smiles/ai.gif | Bin {upload/styles => styles}/images/smiles/aj.gif | Bin {upload/styles => styles}/images/smiles/ak.gif | Bin {upload/styles => styles}/images/smiles/al.gif | Bin {upload/styles => styles}/images/smiles/am.gif | Bin {upload/styles => styles}/images/smiles/an.gif | Bin {upload/styles => styles}/images/smiles/ao.gif | Bin {upload/styles => styles}/images/smiles/ap.gif | Bin {upload/styles => styles}/images/smiles/aq.gif | Bin {upload/styles => styles}/images/smiles/ar.gif | Bin {upload/styles => styles}/images/smiles/as.gif | Bin {upload/styles => styles}/images/smiles/at.gif | Bin {upload/styles => styles}/images/smiles/au.gif | Bin {upload/styles => styles}/images/smiles/av.gif | Bin {upload/styles => styles}/images/smiles/aw.gif | Bin {upload/styles => styles}/images/smiles/ax.gif | Bin {upload/styles => styles}/images/smiles/ay.gif | Bin {upload/styles => styles}/images/smiles/az.gif | Bin {upload/styles => styles}/images/smiles/ba.gif | Bin {upload/styles => styles}/images/smiles/bb.gif | Bin {upload/styles => styles}/images/smiles/bc.gif | Bin {upload/styles => styles}/images/smiles/bd.gif | Bin {upload/styles => styles}/images/smiles/be.gif | Bin {upload/styles => styles}/images/smiles/bf.gif | Bin {upload/styles => styles}/images/smiles/bg.gif | Bin {upload/styles => styles}/images/smiles/bh.gif | Bin {upload/styles => styles}/images/smiles/bi.gif | Bin {upload/styles => styles}/images/smiles/bj.gif | Bin {upload/styles => styles}/images/smiles/bk.gif | Bin {upload/styles => styles}/images/smiles/bl.gif | Bin {upload/styles => styles}/images/smiles/bm.gif | Bin {upload/styles => styles}/images/smiles/bn.gif | Bin {upload/styles => styles}/images/smiles/bo.gif | Bin {upload/styles => styles}/images/smiles/bp.gif | Bin {upload/styles => styles}/images/smiles/bq.gif | Bin {upload/styles => styles}/images/smiles/br.gif | Bin {upload/styles => styles}/images/smiles/bs.gif | Bin {upload/styles => styles}/images/smiles/bt.gif | Bin {upload/styles => styles}/images/smiles/bu.gif | Bin {upload/styles => styles}/images/smiles/bv.gif | Bin {upload/styles => styles}/images/smiles/bw.gif | Bin {upload/styles => styles}/images/smiles/bx.gif | Bin {upload/styles => styles}/images/smiles/by.gif | Bin {upload/styles => styles}/images/smiles/bz.gif | Bin {upload/styles => styles}/images/smiles/ca.gif | Bin {upload/styles => styles}/images/smiles/cb.gif | Bin {upload/styles => styles}/images/smiles/cc.gif | Bin {upload/styles => styles}/images/smiles/tr_oops.gif | Bin {upload/styles => styles}/images/spacer.gif | Bin {upload/styles => styles}/images/tor_gold.gif | Bin {upload/styles => styles}/images/tor_silver.gif | Bin {upload/styles => styles}/images/user_offline.gif | Bin {upload/styles => styles}/images/user_online.gif | Bin {upload/styles => styles}/js/bbcode.js | 0 {upload/styles => styles}/js/jquery.pack.js | 0 {upload/styles => styles}/js/main.js | 0 .../templates/admin/admin_attach_cp.tpl | 0 .../templates/admin/admin_attachments.tpl | 0 .../templates/admin/admin_board.tpl | 0 .../templates/admin/admin_bt_forum_cfg.tpl | 0 .../templates/admin/admin_bt_tracker_cfg.tpl | 0 .../templates/admin/admin_cron.tpl | 0 .../templates/admin/admin_disallow.tpl | 0 .../templates/admin/admin_extensions.tpl | 0 .../templates/admin/admin_forum_prune.tpl | 0 .../templates/admin/admin_forumauth.tpl | 0 .../templates/admin/admin_forumauth_list.tpl | 0 .../templates/admin/admin_forums.tpl | 0 .../templates/admin/admin_groups.tpl | 0 .../styles => styles}/templates/admin/admin_log.tpl | 0 .../templates/admin/admin_mass_email.tpl | 0 .../templates/admin/admin_ranks.tpl | 0 .../templates/admin/admin_rebuild_search.tpl | 0 .../templates/admin/admin_sitemap.tpl | 0 .../templates/admin/admin_smilies.tpl | 0 .../templates/admin/admin_terms.tpl | 0 .../templates/admin/admin_ug_auth.tpl | 0 .../templates/admin/admin_user_ban.tpl | 0 .../templates/admin/admin_user_search.tpl | 0 .../templates/admin/admin_words.tpl | 0 {upload/styles => styles}/templates/admin/index.tpl | 0 .../styles => styles}/templates/default/common.tpl | 0 .../templates/default/css/admin.css | 0 .../templates/default/css/main.css | 0 .../styles => styles}/templates/default/group.tpl | 0 .../templates/default/group_edit.tpl | 0 .../templates/default/images/aerobg.png | Bin .../templates/default/images/arrow1.gif | Bin .../templates/default/images/button.gif | Bin .../templates/default/images/cellpic.gif | Bin .../templates/default/images/cellpic1.gif | Bin .../templates/default/images/def_button.png | Bin .../templates/default/images/def_button_light.png | Bin .../templates/default/images/feed.png | Bin .../templates/default/images/folder.gif | Bin .../templates/default/images/folder_announce.gif | Bin .../default/images/folder_announce_new.gif | Bin .../templates/default/images/folder_big.gif | Bin .../templates/default/images/folder_dl.gif | Bin .../templates/default/images/folder_dl_hot.gif | Bin .../templates/default/images/folder_dl_hot_new.gif | Bin .../templates/default/images/folder_dl_new.gif | Bin .../templates/default/images/folder_hot.gif | Bin .../templates/default/images/folder_lock.gif | Bin .../templates/default/images/folder_lock_new.gif | Bin .../templates/default/images/folder_locked_big.gif | Bin .../templates/default/images/folder_new.gif | Bin .../templates/default/images/folder_new_big.gif | Bin .../templates/default/images/folder_new_hot.gif | Bin .../templates/default/images/folder_sticky.gif | Bin .../templates/default/images/folder_sticky_new.gif | Bin .../templates/default/images/hr200_ltr_gradient.jpg | Bin .../templates/default/images/hr400_ltr_gradient.jpg | Bin .../templates/default/images/icon_birthday.gif | Bin .../templates/default/images/icon_delete.gif | Bin .../templates/default/images/icon_female.gif | Bin .../templates/default/images/icon_latest_reply.gif | Bin .../templates/default/images/icon_male.gif | Bin .../templates/default/images/icon_minipost.gif | Bin .../templates/default/images/icon_minipost_new.gif | Bin .../templates/default/images/icon_minus_1.gif | Bin .../templates/default/images/icon_minus_2.gif | Bin .../templates/default/images/icon_mod.gif | Bin .../templates/default/images/icon_newest_reply.gif | Bin .../templates/default/images/icon_nogender.gif | Bin .../templates/default/images/icon_plus_1.gif | Bin .../templates/default/images/icon_plus_2.gif | Bin .../templates/default/images/img_alert.gif | Bin .../templates/default/images/lang/en/icon_edit.gif | Bin .../templates/default/images/lang/en/icon_email.gif | Bin .../default/images/lang/en/icon_icq_add.gif | Bin .../templates/default/images/lang/en/icon_ip.gif | Bin .../templates/default/images/lang/en/icon_mc.gif | Bin .../templates/default/images/lang/en/icon_pm.gif | Bin .../templates/default/images/lang/en/icon_poll.gif | Bin .../default/images/lang/en/icon_profile.gif | Bin .../templates/default/images/lang/en/icon_quote.gif | Bin .../default/images/lang/en/icon_search.gif | Bin .../templates/default/images/lang/en/icon_www.gif | Bin .../default/images/lang/en/msg_newpost.gif | Bin .../templates/default/images/lang/en/post.gif | Bin .../templates/default/images/lang/en/release.gif | Bin .../default/images/lang/en/reply-locked.gif | Bin .../templates/default/images/lang/en/reply.gif | Bin .../templates/default/images/lang/ru/icon_edit.gif | Bin .../templates/default/images/lang/ru/icon_email.gif | Bin .../default/images/lang/ru/icon_icq_add.gif | Bin .../templates/default/images/lang/ru/icon_ip.gif | Bin .../templates/default/images/lang/ru/icon_mc.gif | Bin .../templates/default/images/lang/ru/icon_pm.gif | Bin .../templates/default/images/lang/ru/icon_poll.gif | Bin .../default/images/lang/ru/icon_profile.gif | Bin .../templates/default/images/lang/ru/icon_quote.gif | Bin .../default/images/lang/ru/icon_search.gif | Bin .../templates/default/images/lang/ru/icon_www.gif | Bin .../default/images/lang/ru/msg_newpost.gif | Bin .../templates/default/images/lang/ru/post.gif | Bin .../templates/default/images/lang/ru/release.gif | Bin .../default/images/lang/ru/reply-locked.gif | Bin .../templates/default/images/lang/ru/reply.gif | Bin .../templates/default/images/lang/uk/icon_edit.gif | Bin .../templates/default/images/lang/uk/icon_email.gif | Bin .../default/images/lang/uk/icon_icq_add.gif | Bin .../templates/default/images/lang/uk/icon_ip.gif | Bin .../templates/default/images/lang/uk/icon_mc.gif | Bin .../templates/default/images/lang/uk/icon_pm.gif | Bin .../templates/default/images/lang/uk/icon_poll.gif | Bin .../default/images/lang/uk/icon_profile.gif | Bin .../templates/default/images/lang/uk/icon_quote.gif | Bin .../default/images/lang/uk/icon_search.gif | Bin .../templates/default/images/lang/uk/icon_www.gif | Bin .../default/images/lang/uk/msg_newpost.gif | Bin .../templates/default/images/lang/uk/post.gif | Bin .../templates/default/images/lang/uk/release.gif | Bin .../default/images/lang/uk/reply-locked.gif | Bin .../templates/default/images/lang/uk/reply.gif | Bin .../templates/default/images/link_help.cur | Bin .../templates/default/images/loading.gif | Bin .../templates/default/images/loading_1.gif | Bin .../templates/default/images/menu_open.gif | Bin .../templates/default/images/menu_open_1.gif | Bin .../templates/default/images/msg_inbox.gif | Bin .../templates/default/images/msg_outbox.gif | Bin .../templates/default/images/msg_savebox.gif | Bin .../templates/default/images/msg_sentbox.gif | Bin .../templates/default/images/progress_bar.gif | Bin .../templates/default/images/progress_bar_full.gif | Bin .../templates/default/images/spacer.gif | Bin .../templates/default/images/tbl_sort_asc.gif | Bin .../templates/default/images/tbl_sort_bg.gif | Bin .../templates/default/images/tbl_sort_desc.gif | Bin .../templates/default/images/topic_delete.gif | Bin .../templates/default/images/topic_dl.gif | Bin .../templates/default/images/topic_lock.gif | Bin .../templates/default/images/topic_move.gif | Bin .../templates/default/images/topic_normal.gif | Bin .../templates/default/images/topic_split.gif | Bin .../templates/default/images/topic_unlock.gif | Bin .../images/treeview/treeview-default-line.gif | Bin .../default/images/treeview/treeview-default.gif | Bin .../templates/default/images/vote_lcap.gif | Bin .../templates/default/images/vote_rcap.gif | Bin .../templates/default/images/voting_bar.gif | Bin .../templates/default/images/whosonline.gif | Bin .../styles => styles}/templates/default/index.tpl | 0 .../templates/default/index_map.tpl | 0 .../styles => styles}/templates/default/login.tpl | 0 .../templates/default/memberlist.tpl | 0 .../styles => styles}/templates/default/modcp.tpl | 0 .../templates/default/modcp_split.tpl | 0 .../templates/default/page_footer.tpl | 0 .../templates/default/page_header.tpl | 0 .../styles => styles}/templates/default/posting.tpl | 0 .../templates/default/posting_attach.tpl | 0 .../templates/default/posting_editor.tpl | 0 .../templates/default/posting_smilies.tpl | 0 .../templates/default/privmsgs.tpl | 0 .../templates/default/privmsgs_read.tpl | 0 .../styles => styles}/templates/default/search.tpl | 0 .../templates/default/search_results.tpl | 0 .../styles => styles}/templates/default/terms.tpl | 0 .../styles => styles}/templates/default/torhelp.tpl | 0 .../templates/default/tpl_config.php | 0 .../styles => styles}/templates/default/tracker.tpl | 0 .../templates/default/usercp_bonus.tpl | 0 .../templates/default/usercp_email.tpl | 0 .../templates/default/usercp_register.tpl | 0 .../templates/default/usercp_sendpasswd.tpl | 0 .../templates/default/usercp_topic_watch.tpl | 0 .../templates/default/usercp_viewprofile.tpl | 0 .../templates/default/viewforum.tpl | 0 .../templates/default/viewtopic.tpl | 0 .../templates/default/viewtopic_attach.tpl | 0 .../templates/default/viewtopic_attach_guest.tpl | 0 .../templates/default/viewtopic_poll.tpl | 0 .../templates/default/viewtopic_torrent.tpl | 0 {upload/styles => styles}/templates/posting_tpl.tpl | 0 upload/terms.php => terms.php | 0 upload/tracker.php => tracker.php | 0 upload/viewforum.php => viewforum.php | 0 upload/viewtopic.php => viewtopic.php | 0 585 files changed, 14 insertions(+), 14 deletions(-) rename upload/.htaccess => .htaccess (100%) rename {upload/admin => admin}/admin_attach_cp.php (100%) rename {upload/admin => admin}/admin_attachments.php (100%) rename {upload/admin => admin}/admin_board.php (100%) rename {upload/admin => admin}/admin_bt_forum_cfg.php (100%) rename {upload/admin => admin}/admin_bt_tracker_cfg.php (100%) rename {upload/admin => admin}/admin_cron.php (100%) rename {upload/admin => admin}/admin_disallow.php (100%) rename {upload/admin => admin}/admin_extensions.php (100%) rename {upload/admin => admin}/admin_forum_prune.php (100%) rename {upload/admin => admin}/admin_forumauth.php (100%) rename {upload/admin => admin}/admin_forumauth_list.php (100%) rename {upload/admin => admin}/admin_forums.php (100%) rename {upload/admin => admin}/admin_groups.php (100%) rename {upload/admin => admin}/admin_log.php (100%) rename {upload/admin => admin}/admin_mass_email.php (100%) rename {upload/admin => admin}/admin_phpinfo.php (100%) rename {upload/admin => admin}/admin_ranks.php (100%) rename {upload/admin => admin}/admin_rebuild_search.php (100%) rename {upload/admin => admin}/admin_sitemap.php (100%) rename {upload/admin => admin}/admin_smilies.php (100%) rename {upload/admin => admin}/admin_terms.php (100%) rename {upload/admin => admin}/admin_ug_auth.php (100%) rename {upload/admin => admin}/admin_user_ban.php (100%) rename {upload/admin => admin}/admin_user_search.php (100%) rename {upload/admin => admin}/admin_words.php (100%) rename {upload/admin => admin}/index.php (100%) rename {upload/admin => admin}/pagestart.php (100%) rename {upload/admin => admin}/stats/tr_stats.php (100%) rename {upload/admin => admin}/stats/tracker.php (100%) rename upload/ajax.php => ajax.php (100%) rename {upload/bt => bt}/announce.php (99%) rename {upload/bt => bt}/includes/.htaccess (100%) rename {upload/bt => bt}/includes/init_tr.php (100%) rename {upload/bt => bt}/index.php (100%) rename {upload/bt => bt}/robots.txt (100%) rename {upload/bt => bt}/scrape.php (96%) rename upload/callseed.php => callseed.php (100%) rename upload/common.php => common.php (99%) rename upload/cron.php => cron.php (100%) rename upload/crossdomain.xml => crossdomain.xml (100%) rename {upload/data => data}/avatars/gallery/bot.gif (100%) rename {upload/data => data}/avatars/gallery/noavatar.png (100%) rename {upload/data => data}/old_files/.htaccess (100%) rename {upload/data => data}/torrent_files/.htaccess (100%) rename upload/dl.php => dl.php (100%) rename upload/dl_list.php => dl_list.php (100%) rename upload/favicon.ico => favicon.ico (100%) rename upload/feed.php => feed.php (100%) rename upload/group.php => group.php (100%) rename upload/group_edit.php => group_edit.php (100%) rename upload/index.php => index.php (100%) rename upload/info.php => info.php (95%) rename {other => install/other}/converter/TBDevYSE_pre6/ReadMe.txt (100%) rename {other => install/other}/converter/TBDevYSE_pre6/for_tbdev/announce.php (98%) rename {other => install/other}/converter/TBDevYSE_pre6/for_tbdev/pass.php (100%) rename {other => install/other}/converter/TBDevYSE_pre6/root/convert.php (97%) rename {other => install/other}/converter/TBDevYSE_pre6/root/converter/constants.php (100%) rename {other => install/other}/converter/TBDevYSE_pre6/root/converter/functions.php (100%) rename {other => install/other}/converter/TBDevYSE_pre6/root/converter/passwords.php (100%) rename {other => install/other}/converter/TBDevYSE_pre6/root/converter/settings.php (100%) rename {other => install/other}/converter/TBDevYSE_pre6/root/recover.php (95%) rename {other => install/other}/recover/converter/constants.php (100%) rename {other => install/other}/recover/converter/functions.php (100%) rename {other => install/other}/recover/converter/passwords.php (100%) rename {other => install/other}/recover/converter/settings.php (100%) rename {other => install/other}/recover/recover.php (95%) rename {upgrade => install/upgrade}/changes.txt (100%) rename {upgrade => install/upgrade}/r496-user_birthday.php (100%) rename {upgrade => install/upgrade}/r571-dl_upgrade.php (100%) rename {upgrade => install/upgrade}/r575-poll_upgrade.php (100%) rename {upgrade => install/upgrade}/r583-convert_avatars.php (100%) rename {upgrade => install/upgrade}/r588-short_lang.php (100%) rename {upgrade => install/upgrade}/r600-stable.php (100%) rename {upload/internal_data => internal_data}/ajax_html/jumpbox_guest.html (100%) rename {upload/internal_data => internal_data}/ajax_html/jumpbox_user.html (100%) rename {upload/internal_data => internal_data}/atom/.keep (100%) rename {upload/internal_data => internal_data}/cache/.htaccess (100%) rename {upload/internal_data => internal_data}/captcha/.keep (100%) rename {upload/internal_data => internal_data}/log/.htaccess (100%) rename {upload/internal_data => internal_data}/log/cron/.htaccess (100%) rename {upload/internal_data => internal_data}/sitemap/.keep (100%) rename {upload/internal_data => internal_data}/triggers/$on (100%) rename {upload/internal_data => internal_data}/triggers/.htaccess (100%) rename {upload/internal_data => internal_data}/triggers/cron_allowed (100%) rename {upload/library => library}/ajax/avatar.php (100%) rename {upload/library => library}/ajax/change_tor_status.php (100%) rename {upload/library => library}/ajax/change_torrent.php (100%) rename {upload/library => library}/ajax/change_user_opt.php (100%) rename {upload/library => library}/ajax/change_user_rank.php (100%) rename {upload/library => library}/ajax/edit_group_profile.php (100%) rename {upload/library => library}/ajax/edit_user_profile.php (100%) rename {upload/library => library}/ajax/gen_passkey.php (100%) rename {upload/library => library}/ajax/group_membership.php (100%) rename {upload/library => library}/ajax/index_data.php (100%) rename {upload/library => library}/ajax/manage_admin.php (100%) rename {upload/library => library}/ajax/manage_user.php (100%) rename {upload/library => library}/ajax/mod_action.php (100%) rename {upload/library => library}/ajax/post_mod_comment.php (100%) rename {upload/library => library}/ajax/posts.php (100%) rename {upload/library => library}/ajax/sitemap.php (100%) rename {upload/library => library}/ajax/topic_tpl.php (100%) rename {upload/library => library}/ajax/user_register.php (100%) rename {upload/library => library}/ajax/view_post.php (100%) rename {upload/library => library}/ajax/view_torrent.php (100%) rename {upload/library => library}/attach_mod/.htaccess (100%) rename {upload/library => library}/attach_mod/attachment_mod.php (100%) rename {upload/library => library}/attach_mod/displaying.php (100%) rename {upload/library => library}/attach_mod/displaying_torrent.php (100%) rename {upload/library => library}/attach_mod/includes/.htaccess (100%) rename {upload/library => library}/attach_mod/includes/functions_admin.php (100%) rename {upload/library => library}/attach_mod/includes/functions_attach.php (100%) rename {upload/library => library}/attach_mod/includes/functions_delete.php (100%) rename {upload/library => library}/attach_mod/includes/functions_filetypes.php (100%) rename {upload/library => library}/attach_mod/includes/functions_includes.php (100%) rename {upload/library => library}/attach_mod/includes/functions_selects.php (100%) rename {upload/library => library}/attach_mod/includes/functions_thumbs.php (100%) rename {upload/library => library}/attach_mod/posting_attachments.php (100%) rename {upload/library => library}/config.php (100%) rename {upload/library => library}/includes/.htaccess (100%) rename {upload/library => library}/includes/api/sphinx.php (100%) rename {upload/library => library}/includes/bbcode.php (100%) rename {upload/library => library}/includes/captcha/.htaccess (100%) rename {upload/library => library}/includes/captcha/captcha.php (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/antiqua.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/baskerville.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/batang.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/bookman.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/calisto.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/cambria.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/centaur.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/century.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/chaparral.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/constantia.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/footlight.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/garamond.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/georgia.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/goudy_old.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/kozuka.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/lucida.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/minion.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/palatino.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/perpetua.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/rockwell.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/times.png (100%) rename {upload/library => library}/includes/captcha/kcaptcha/fonts/warnock.png (100%) rename {upload/library => library}/includes/classes/.htaccess (100%) rename {upload/library => library}/includes/classes/correct.php (100%) rename {upload/library => library}/includes/classes/emailer.php (100%) rename {upload/library => library}/includes/classes/reflection.php (100%) rename {upload/library => library}/includes/classes/sitemap.php (100%) rename {upload/library => library}/includes/classes/utf8.php (100%) rename {upload/library => library}/includes/core/mysql.php (100%) rename {upload/library => library}/includes/cron/.htaccess (100%) rename {upload/library => library}/includes/cron/cron_check.php (100%) rename {upload/library => library}/includes/cron/cron_init.php (100%) rename {upload/library => library}/includes/cron/cron_run.php (100%) rename {upload/library => library}/includes/cron/jobs/.htaccess (100%) rename {upload/library => library}/includes/cron/jobs/attach_maintenance.php (100%) rename {upload/library => library}/includes/cron/jobs/board_maintenance.php (100%) rename {upload/library => library}/includes/cron/jobs/cache_gc.php (100%) rename {upload/library => library}/includes/cron/jobs/captcha_gen_gc.php (100%) rename {upload/library => library}/includes/cron/jobs/clean_dlstat.php (100%) rename {upload/library => library}/includes/cron/jobs/clean_log.php (100%) rename {upload/library => library}/includes/cron/jobs/clean_search_results.php (100%) rename {upload/library => library}/includes/cron/jobs/ds_update_cat_forums.php (100%) rename {upload/library => library}/includes/cron/jobs/ds_update_stats.php (100%) rename {upload/library => library}/includes/cron/jobs/flash_topic_view.php (100%) rename {upload/library => library}/includes/cron/jobs/prune_forums.php (100%) rename {upload/library => library}/includes/cron/jobs/prune_inactive_users.php (100%) rename {upload/library => library}/includes/cron/jobs/prune_topic_moved.php (100%) rename {upload/library => library}/includes/cron/jobs/sessions_cleanup.php (100%) rename {upload/library => library}/includes/cron/jobs/sitemap.php (100%) rename {upload/library => library}/includes/cron/jobs/tr_cleanup_and_dlstat.php (100%) rename {upload/library => library}/includes/cron/jobs/tr_complete_count.php (100%) rename {upload/library => library}/includes/cron/jobs/tr_maintenance.php (100%) rename {upload/library => library}/includes/cron/jobs/tr_make_snapshot.php (100%) rename {upload/library => library}/includes/cron/jobs/tr_update_seeder_last_seen.php (100%) rename {upload/library => library}/includes/cron/jobs/update_forums_atom.php (100%) rename {upload/library => library}/includes/datastore/.htaccess (100%) rename {upload/library => library}/includes/datastore/build_attach_extensions.php (100%) rename {upload/library => library}/includes/datastore/build_cat_forums.php (100%) rename {upload/library => library}/includes/datastore/build_moderators.php (100%) rename {upload/library => library}/includes/datastore/build_ranks.php (100%) rename {upload/library => library}/includes/datastore/build_smilies.php (100%) rename {upload/library => library}/includes/datastore/build_stats.php (100%) rename {upload/library => library}/includes/functions.php (100%) rename {upload/library => library}/includes/functions_admin.php (100%) rename {upload/library => library}/includes/functions_admin_cron.php (100%) rename {upload/library => library}/includes/functions_admin_torrent.php (100%) rename {upload/library => library}/includes/functions_atom.php (100%) rename {upload/library => library}/includes/functions_dev.php (100%) rename {upload/library => library}/includes/functions_group.php (100%) rename {upload/library => library}/includes/functions_post.php (100%) rename {upload/library => library}/includes/functions_selects.php (100%) rename {upload/library => library}/includes/functions_torrent.php (100%) rename {upload/library => library}/includes/functions_upload.php (100%) rename {upload/library => library}/includes/functions_validate.php (100%) rename {upload/library => library}/includes/init_bb.php (100%) rename {upload/library => library}/includes/online_userlist.php (100%) rename {upload/library => library}/includes/page_footer.php (100%) rename {upload/library => library}/includes/page_footer_dev.php (100%) rename {upload/library => library}/includes/page_header.php (100%) rename {upload/library => library}/includes/posting_tpl.php (100%) rename {upload/library => library}/includes/sessions.php (100%) rename {upload/library => library}/includes/smtp.php (100%) rename {upload/library => library}/includes/sql_parse.php (100%) rename {upload/library => library}/includes/template.php (100%) rename {upload/library => library}/includes/torrent_announce_urls.php (100%) rename {upload/library => library}/includes/torrent_show_dl_list.php (100%) rename {upload/library => library}/includes/ucp/.htaccess (100%) rename {upload/library => library}/includes/ucp/activate.php (100%) rename {upload/library => library}/includes/ucp/bonus.php (100%) rename {upload/library => library}/includes/ucp/email.php (100%) rename {upload/library => library}/includes/ucp/register.php (100%) rename {upload/library => library}/includes/ucp/sendpasswd.php (100%) rename {upload/library => library}/includes/ucp/topic_watch.php (100%) rename {upload/library => library}/includes/ucp/viewprofile.php (100%) rename {upload/library => library}/includes/ucp/viewtorrent.php (100%) rename {upload/library => library}/language/.htaccess (100%) rename {upload/library => library}/language/en/.htaccess (100%) rename {upload/library => library}/language/en/email/.htaccess (100%) rename {upload/library => library}/language/en/email/admin_send_email.tpl (100%) rename {upload/library => library}/language/en/email/blank.tpl (100%) rename {upload/library => library}/language/en/email/group_added.tpl (100%) rename {upload/library => library}/language/en/email/group_approved.tpl (100%) rename {upload/library => library}/language/en/email/group_request.tpl (100%) rename {upload/library => library}/language/en/email/privmsg_notify.tpl (100%) rename {upload/library => library}/language/en/email/profile_send_email.tpl (100%) rename {upload/library => library}/language/en/email/topic_notify.tpl (100%) rename {upload/library => library}/language/en/email/user_activate.tpl (100%) rename {upload/library => library}/language/en/email/user_activate_passwd.tpl (100%) rename {upload/library => library}/language/en/email/user_welcome.tpl (100%) rename {upload/library => library}/language/en/email/user_welcome_inactive.tpl (100%) rename {upload/library => library}/language/en/html/.htaccess (100%) rename {upload/library => library}/language/en/html/advert.html (100%) rename {upload/library => library}/language/en/html/copyright_holders.html (100%) rename {upload/library => library}/language/en/html/not_found.html (100%) rename {upload/library => library}/language/en/html/sidebar1.html (100%) rename {upload/library => library}/language/en/html/sidebar2.html (100%) rename {upload/library => library}/language/en/html/user_agreement.html (100%) rename {upload/library => library}/language/en/main.php (100%) rename {upload/library => library}/language/en/search_stopwords.txt (100%) rename {upload/library => library}/language/en/search_synonyms.txt (100%) rename {upload/library => library}/language/ru/.htaccess (100%) rename {upload/library => library}/language/ru/email/.htaccess (100%) rename {upload/library => library}/language/ru/email/admin_send_email.tpl (100%) rename {upload/library => library}/language/ru/email/blank.tpl (100%) rename {upload/library => library}/language/ru/email/group_added.tpl (100%) rename {upload/library => library}/language/ru/email/group_approved.tpl (100%) rename {upload/library => library}/language/ru/email/group_request.tpl (100%) rename {upload/library => library}/language/ru/email/privmsg_notify.tpl (100%) rename {upload/library => library}/language/ru/email/profile_send_email.tpl (100%) rename {upload/library => library}/language/ru/email/topic_notify.tpl (100%) rename {upload/library => library}/language/ru/email/user_activate.tpl (100%) rename {upload/library => library}/language/ru/email/user_activate_passwd.tpl (100%) rename {upload/library => library}/language/ru/email/user_welcome.tpl (100%) rename {upload/library => library}/language/ru/email/user_welcome_inactive.tpl (100%) rename {upload/library => library}/language/ru/html/.htaccess (100%) rename {upload/library => library}/language/ru/html/advert.html (100%) rename {upload/library => library}/language/ru/html/copyright_holders.html (100%) rename {upload/library => library}/language/ru/html/not_found.html (100%) rename {upload/library => library}/language/ru/html/sidebar1.html (100%) rename {upload/library => library}/language/ru/html/sidebar2.html (100%) rename {upload/library => library}/language/ru/html/user_agreement.html (100%) rename {upload/library => library}/language/ru/main.php (100%) rename {upload/library => library}/language/ru/search_stopwords.txt (100%) rename {upload/library => library}/language/ru/search_synonyms.txt (100%) rename {upload/library => library}/language/uk/.htaccess (100%) rename {upload/library => library}/language/uk/email/.htaccess (100%) rename {upload/library => library}/language/uk/email/admin_send_email.tpl (100%) rename {upload/library => library}/language/uk/email/blank.tpl (100%) rename {upload/library => library}/language/uk/email/group_added.tpl (100%) rename {upload/library => library}/language/uk/email/group_approved.tpl (100%) rename {upload/library => library}/language/uk/email/group_request.tpl (100%) rename {upload/library => library}/language/uk/email/privmsg_notify.tpl (100%) rename {upload/library => library}/language/uk/email/profile_send_email.tpl (100%) rename {upload/library => library}/language/uk/email/topic_notify.tpl (100%) rename {upload/library => library}/language/uk/email/user_activate.tpl (100%) rename {upload/library => library}/language/uk/email/user_activate_passwd.tpl (100%) rename {upload/library => library}/language/uk/email/user_welcome.tpl (100%) rename {upload/library => library}/language/uk/email/user_welcome_inactive.tpl (100%) rename {upload/library => library}/language/uk/html/.htaccess (100%) rename {upload/library => library}/language/uk/html/advert.html (100%) rename {upload/library => library}/language/uk/html/copyright_holders.html (100%) rename {upload/library => library}/language/uk/html/not_found.html (100%) rename {upload/library => library}/language/uk/html/sidebar1.html (100%) rename {upload/library => library}/language/uk/html/sidebar2.html (100%) rename {upload/library => library}/language/uk/html/user_agreement.html (100%) rename {upload/library => library}/language/uk/main.php (100%) rename {upload/library => library}/language/uk/search_stopwords.txt (100%) rename {upload/library => library}/language/uk/search_synonyms.txt (100%) rename upload/login.php => login.php (100%) rename upload/memberlist.php => memberlist.php (100%) rename upload/modcp.php => modcp.php (100%) rename upload/opensearch_desc.xml => opensearch_desc.xml (100%) rename upload/opensearch_desc_bt.xml => opensearch_desc_bt.xml (100%) rename upload/poll.php => poll.php (100%) rename upload/posting.php => posting.php (100%) rename upload/privmsg.php => privmsg.php (100%) rename upload/profile.php => profile.php (100%) rename upload/robots.txt => robots.txt (100%) rename upload/search.php => search.php (100%) rename {upload/styles => styles}/bootstrap/css/bootstrap-theme.css (100%) rename {upload/styles => styles}/bootstrap/css/bootstrap-theme.css.map (100%) rename {upload/styles => styles}/bootstrap/css/bootstrap-theme.min.css (100%) rename {upload/styles => styles}/bootstrap/css/bootstrap.css (100%) rename {upload/styles => styles}/bootstrap/css/bootstrap.css.map (100%) rename {upload/styles => styles}/bootstrap/css/bootstrap.min.css (100%) rename {upload/styles => styles}/bootstrap/fonts/glyphicons-halflings-regular.eot (100%) rename {upload/styles => styles}/bootstrap/fonts/glyphicons-halflings-regular.svg (100%) rename {upload/styles => styles}/bootstrap/fonts/glyphicons-halflings-regular.ttf (100%) rename {upload/styles => styles}/bootstrap/fonts/glyphicons-halflings-regular.woff (100%) rename {upload/styles => styles}/bootstrap/js/bootstrap.js (100%) rename {upload/styles => styles}/bootstrap/js/bootstrap.min.js (100%) rename {upload/styles => styles}/images/bad.gif (100%) rename {upload/styles => styles}/images/dc_magnet.png (100%) rename {upload/styles => styles}/images/dc_magnet_ext.png (100%) rename {upload/styles => styles}/images/folder.gif (100%) rename {upload/styles => styles}/images/good.gif (100%) rename {upload/styles => styles}/images/icon_clip.gif (100%) rename {upload/styles => styles}/images/icon_delete.gif (100%) rename {upload/styles => styles}/images/icon_dn.gif (100%) rename {upload/styles => styles}/images/icon_edit.gif (100%) rename {upload/styles => styles}/images/icon_external.png (100%) rename {upload/styles => styles}/images/icon_run.gif (100%) rename {upload/styles => styles}/images/icon_sync.gif (100%) rename {upload/styles => styles}/images/logo/logo.png (100%) rename {upload/styles => styles}/images/logo/logo_summer.png (100%) rename {upload/styles => styles}/images/magnet.png (100%) rename {upload/styles => styles}/images/page.gif (100%) rename {upload/styles => styles}/images/pic_loading.gif (100%) rename {upload/styles => styles}/images/ranks/admin.png (100%) rename {upload/styles => styles}/images/ranks/user.png (100%) rename {upload/styles => styles}/images/smiles/aa.gif (100%) rename {upload/styles => styles}/images/smiles/ab.gif (100%) rename {upload/styles => styles}/images/smiles/ac.gif (100%) rename {upload/styles => styles}/images/smiles/ad.gif (100%) rename {upload/styles => styles}/images/smiles/ae.gif (100%) rename {upload/styles => styles}/images/smiles/af.gif (100%) rename {upload/styles => styles}/images/smiles/ag.gif (100%) rename {upload/styles => styles}/images/smiles/ah.gif (100%) rename {upload/styles => styles}/images/smiles/ai.gif (100%) rename {upload/styles => styles}/images/smiles/aj.gif (100%) rename {upload/styles => styles}/images/smiles/ak.gif (100%) rename {upload/styles => styles}/images/smiles/al.gif (100%) rename {upload/styles => styles}/images/smiles/am.gif (100%) rename {upload/styles => styles}/images/smiles/an.gif (100%) rename {upload/styles => styles}/images/smiles/ao.gif (100%) rename {upload/styles => styles}/images/smiles/ap.gif (100%) rename {upload/styles => styles}/images/smiles/aq.gif (100%) rename {upload/styles => styles}/images/smiles/ar.gif (100%) rename {upload/styles => styles}/images/smiles/as.gif (100%) rename {upload/styles => styles}/images/smiles/at.gif (100%) rename {upload/styles => styles}/images/smiles/au.gif (100%) rename {upload/styles => styles}/images/smiles/av.gif (100%) rename {upload/styles => styles}/images/smiles/aw.gif (100%) rename {upload/styles => styles}/images/smiles/ax.gif (100%) rename {upload/styles => styles}/images/smiles/ay.gif (100%) rename {upload/styles => styles}/images/smiles/az.gif (100%) rename {upload/styles => styles}/images/smiles/ba.gif (100%) rename {upload/styles => styles}/images/smiles/bb.gif (100%) rename {upload/styles => styles}/images/smiles/bc.gif (100%) rename {upload/styles => styles}/images/smiles/bd.gif (100%) rename {upload/styles => styles}/images/smiles/be.gif (100%) rename {upload/styles => styles}/images/smiles/bf.gif (100%) rename {upload/styles => styles}/images/smiles/bg.gif (100%) rename {upload/styles => styles}/images/smiles/bh.gif (100%) rename {upload/styles => styles}/images/smiles/bi.gif (100%) rename {upload/styles => styles}/images/smiles/bj.gif (100%) rename {upload/styles => styles}/images/smiles/bk.gif (100%) rename {upload/styles => styles}/images/smiles/bl.gif (100%) rename {upload/styles => styles}/images/smiles/bm.gif (100%) rename {upload/styles => styles}/images/smiles/bn.gif (100%) rename {upload/styles => styles}/images/smiles/bo.gif (100%) rename {upload/styles => styles}/images/smiles/bp.gif (100%) rename {upload/styles => styles}/images/smiles/bq.gif (100%) rename {upload/styles => styles}/images/smiles/br.gif (100%) rename {upload/styles => styles}/images/smiles/bs.gif (100%) rename {upload/styles => styles}/images/smiles/bt.gif (100%) rename {upload/styles => styles}/images/smiles/bu.gif (100%) rename {upload/styles => styles}/images/smiles/bv.gif (100%) rename {upload/styles => styles}/images/smiles/bw.gif (100%) rename {upload/styles => styles}/images/smiles/bx.gif (100%) rename {upload/styles => styles}/images/smiles/by.gif (100%) rename {upload/styles => styles}/images/smiles/bz.gif (100%) rename {upload/styles => styles}/images/smiles/ca.gif (100%) rename {upload/styles => styles}/images/smiles/cb.gif (100%) rename {upload/styles => styles}/images/smiles/cc.gif (100%) rename {upload/styles => styles}/images/smiles/tr_oops.gif (100%) rename {upload/styles => styles}/images/spacer.gif (100%) rename {upload/styles => styles}/images/tor_gold.gif (100%) rename {upload/styles => styles}/images/tor_silver.gif (100%) rename {upload/styles => styles}/images/user_offline.gif (100%) rename {upload/styles => styles}/images/user_online.gif (100%) rename {upload/styles => styles}/js/bbcode.js (100%) rename {upload/styles => styles}/js/jquery.pack.js (100%) rename {upload/styles => styles}/js/main.js (100%) rename {upload/styles => styles}/templates/admin/admin_attach_cp.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_attachments.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_board.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_bt_forum_cfg.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_bt_tracker_cfg.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_cron.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_disallow.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_extensions.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_forum_prune.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_forumauth.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_forumauth_list.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_forums.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_groups.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_log.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_mass_email.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_ranks.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_rebuild_search.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_sitemap.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_smilies.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_terms.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_ug_auth.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_user_ban.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_user_search.tpl (100%) rename {upload/styles => styles}/templates/admin/admin_words.tpl (100%) rename {upload/styles => styles}/templates/admin/index.tpl (100%) rename {upload/styles => styles}/templates/default/common.tpl (100%) rename {upload/styles => styles}/templates/default/css/admin.css (100%) rename {upload/styles => styles}/templates/default/css/main.css (100%) rename {upload/styles => styles}/templates/default/group.tpl (100%) rename {upload/styles => styles}/templates/default/group_edit.tpl (100%) rename {upload/styles => styles}/templates/default/images/aerobg.png (100%) rename {upload/styles => styles}/templates/default/images/arrow1.gif (100%) rename {upload/styles => styles}/templates/default/images/button.gif (100%) rename {upload/styles => styles}/templates/default/images/cellpic.gif (100%) rename {upload/styles => styles}/templates/default/images/cellpic1.gif (100%) rename {upload/styles => styles}/templates/default/images/def_button.png (100%) rename {upload/styles => styles}/templates/default/images/def_button_light.png (100%) rename {upload/styles => styles}/templates/default/images/feed.png (100%) rename {upload/styles => styles}/templates/default/images/folder.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_announce.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_announce_new.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_big.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_dl.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_dl_hot.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_dl_hot_new.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_dl_new.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_hot.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_lock.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_lock_new.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_locked_big.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_new.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_new_big.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_new_hot.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_sticky.gif (100%) rename {upload/styles => styles}/templates/default/images/folder_sticky_new.gif (100%) rename {upload/styles => styles}/templates/default/images/hr200_ltr_gradient.jpg (100%) rename {upload/styles => styles}/templates/default/images/hr400_ltr_gradient.jpg (100%) rename {upload/styles => styles}/templates/default/images/icon_birthday.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_delete.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_female.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_latest_reply.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_male.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_minipost.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_minipost_new.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_minus_1.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_minus_2.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_mod.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_newest_reply.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_nogender.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_plus_1.gif (100%) rename {upload/styles => styles}/templates/default/images/icon_plus_2.gif (100%) rename {upload/styles => styles}/templates/default/images/img_alert.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/icon_edit.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/icon_email.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/icon_icq_add.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/icon_ip.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/icon_mc.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/icon_pm.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/icon_poll.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/icon_profile.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/icon_quote.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/icon_search.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/icon_www.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/msg_newpost.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/post.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/release.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/reply-locked.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/en/reply.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/icon_edit.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/icon_email.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/icon_icq_add.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/icon_ip.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/icon_mc.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/icon_pm.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/icon_poll.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/icon_profile.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/icon_quote.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/icon_search.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/icon_www.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/msg_newpost.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/post.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/release.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/reply-locked.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/ru/reply.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/icon_edit.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/icon_email.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/icon_icq_add.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/icon_ip.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/icon_mc.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/icon_pm.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/icon_poll.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/icon_profile.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/icon_quote.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/icon_search.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/icon_www.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/msg_newpost.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/post.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/release.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/reply-locked.gif (100%) rename {upload/styles => styles}/templates/default/images/lang/uk/reply.gif (100%) rename {upload/styles => styles}/templates/default/images/link_help.cur (100%) rename {upload/styles => styles}/templates/default/images/loading.gif (100%) rename {upload/styles => styles}/templates/default/images/loading_1.gif (100%) rename {upload/styles => styles}/templates/default/images/menu_open.gif (100%) rename {upload/styles => styles}/templates/default/images/menu_open_1.gif (100%) rename {upload/styles => styles}/templates/default/images/msg_inbox.gif (100%) rename {upload/styles => styles}/templates/default/images/msg_outbox.gif (100%) rename {upload/styles => styles}/templates/default/images/msg_savebox.gif (100%) rename {upload/styles => styles}/templates/default/images/msg_sentbox.gif (100%) rename {upload/styles => styles}/templates/default/images/progress_bar.gif (100%) rename {upload/styles => styles}/templates/default/images/progress_bar_full.gif (100%) rename {upload/styles => styles}/templates/default/images/spacer.gif (100%) rename {upload/styles => styles}/templates/default/images/tbl_sort_asc.gif (100%) rename {upload/styles => styles}/templates/default/images/tbl_sort_bg.gif (100%) rename {upload/styles => styles}/templates/default/images/tbl_sort_desc.gif (100%) rename {upload/styles => styles}/templates/default/images/topic_delete.gif (100%) rename {upload/styles => styles}/templates/default/images/topic_dl.gif (100%) rename {upload/styles => styles}/templates/default/images/topic_lock.gif (100%) rename {upload/styles => styles}/templates/default/images/topic_move.gif (100%) rename {upload/styles => styles}/templates/default/images/topic_normal.gif (100%) rename {upload/styles => styles}/templates/default/images/topic_split.gif (100%) rename {upload/styles => styles}/templates/default/images/topic_unlock.gif (100%) rename {upload/styles => styles}/templates/default/images/treeview/treeview-default-line.gif (100%) rename {upload/styles => styles}/templates/default/images/treeview/treeview-default.gif (100%) rename {upload/styles => styles}/templates/default/images/vote_lcap.gif (100%) rename {upload/styles => styles}/templates/default/images/vote_rcap.gif (100%) rename {upload/styles => styles}/templates/default/images/voting_bar.gif (100%) rename {upload/styles => styles}/templates/default/images/whosonline.gif (100%) rename {upload/styles => styles}/templates/default/index.tpl (100%) rename {upload/styles => styles}/templates/default/index_map.tpl (100%) rename {upload/styles => styles}/templates/default/login.tpl (100%) rename {upload/styles => styles}/templates/default/memberlist.tpl (100%) rename {upload/styles => styles}/templates/default/modcp.tpl (100%) rename {upload/styles => styles}/templates/default/modcp_split.tpl (100%) rename {upload/styles => styles}/templates/default/page_footer.tpl (100%) rename {upload/styles => styles}/templates/default/page_header.tpl (100%) rename {upload/styles => styles}/templates/default/posting.tpl (100%) rename {upload/styles => styles}/templates/default/posting_attach.tpl (100%) rename {upload/styles => styles}/templates/default/posting_editor.tpl (100%) rename {upload/styles => styles}/templates/default/posting_smilies.tpl (100%) rename {upload/styles => styles}/templates/default/privmsgs.tpl (100%) rename {upload/styles => styles}/templates/default/privmsgs_read.tpl (100%) rename {upload/styles => styles}/templates/default/search.tpl (100%) rename {upload/styles => styles}/templates/default/search_results.tpl (100%) rename {upload/styles => styles}/templates/default/terms.tpl (100%) rename {upload/styles => styles}/templates/default/torhelp.tpl (100%) rename {upload/styles => styles}/templates/default/tpl_config.php (100%) rename {upload/styles => styles}/templates/default/tracker.tpl (100%) rename {upload/styles => styles}/templates/default/usercp_bonus.tpl (100%) rename {upload/styles => styles}/templates/default/usercp_email.tpl (100%) rename {upload/styles => styles}/templates/default/usercp_register.tpl (100%) rename {upload/styles => styles}/templates/default/usercp_sendpasswd.tpl (100%) rename {upload/styles => styles}/templates/default/usercp_topic_watch.tpl (100%) rename {upload/styles => styles}/templates/default/usercp_viewprofile.tpl (100%) rename {upload/styles => styles}/templates/default/viewforum.tpl (100%) rename {upload/styles => styles}/templates/default/viewtopic.tpl (100%) rename {upload/styles => styles}/templates/default/viewtopic_attach.tpl (100%) rename {upload/styles => styles}/templates/default/viewtopic_attach_guest.tpl (100%) rename {upload/styles => styles}/templates/default/viewtopic_poll.tpl (100%) rename {upload/styles => styles}/templates/default/viewtopic_torrent.tpl (100%) rename {upload/styles => styles}/templates/posting_tpl.tpl (100%) rename upload/terms.php => terms.php (100%) rename upload/tracker.php => tracker.php (100%) rename upload/viewforum.php => viewforum.php (100%) rename upload/viewtopic.php => viewtopic.php (100%) diff --git a/upload/.htaccess b/.htaccess similarity index 100% rename from upload/.htaccess rename to .htaccess diff --git a/README.md b/README.md index 03597f610..c8157c951 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ TorrentPier II - движок торрент-трекера, написанны Для установки вам необходимо выполнить несколько простых шагов: -1. Распаковываем на сервер содержимое папки **upload** +1. Распаковываем на сервер содержимое скачанной вами папки 2. Создаем базу данных, в которую при помощи phpmyadmin (или любого другого удобного инструмента) импортируем дамп, расположенный в папке **install/sql/mysql.sql** 3. Правим файл конфигурации **library/config.php**, загруженный на сервер: diff --git a/upload/admin/admin_attach_cp.php b/admin/admin_attach_cp.php similarity index 100% rename from upload/admin/admin_attach_cp.php rename to admin/admin_attach_cp.php diff --git a/upload/admin/admin_attachments.php b/admin/admin_attachments.php similarity index 100% rename from upload/admin/admin_attachments.php rename to admin/admin_attachments.php diff --git a/upload/admin/admin_board.php b/admin/admin_board.php similarity index 100% rename from upload/admin/admin_board.php rename to admin/admin_board.php diff --git a/upload/admin/admin_bt_forum_cfg.php b/admin/admin_bt_forum_cfg.php similarity index 100% rename from upload/admin/admin_bt_forum_cfg.php rename to admin/admin_bt_forum_cfg.php diff --git a/upload/admin/admin_bt_tracker_cfg.php b/admin/admin_bt_tracker_cfg.php similarity index 100% rename from upload/admin/admin_bt_tracker_cfg.php rename to admin/admin_bt_tracker_cfg.php diff --git a/upload/admin/admin_cron.php b/admin/admin_cron.php similarity index 100% rename from upload/admin/admin_cron.php rename to admin/admin_cron.php diff --git a/upload/admin/admin_disallow.php b/admin/admin_disallow.php similarity index 100% rename from upload/admin/admin_disallow.php rename to admin/admin_disallow.php diff --git a/upload/admin/admin_extensions.php b/admin/admin_extensions.php similarity index 100% rename from upload/admin/admin_extensions.php rename to admin/admin_extensions.php diff --git a/upload/admin/admin_forum_prune.php b/admin/admin_forum_prune.php similarity index 100% rename from upload/admin/admin_forum_prune.php rename to admin/admin_forum_prune.php diff --git a/upload/admin/admin_forumauth.php b/admin/admin_forumauth.php similarity index 100% rename from upload/admin/admin_forumauth.php rename to admin/admin_forumauth.php diff --git a/upload/admin/admin_forumauth_list.php b/admin/admin_forumauth_list.php similarity index 100% rename from upload/admin/admin_forumauth_list.php rename to admin/admin_forumauth_list.php diff --git a/upload/admin/admin_forums.php b/admin/admin_forums.php similarity index 100% rename from upload/admin/admin_forums.php rename to admin/admin_forums.php diff --git a/upload/admin/admin_groups.php b/admin/admin_groups.php similarity index 100% rename from upload/admin/admin_groups.php rename to admin/admin_groups.php diff --git a/upload/admin/admin_log.php b/admin/admin_log.php similarity index 100% rename from upload/admin/admin_log.php rename to admin/admin_log.php diff --git a/upload/admin/admin_mass_email.php b/admin/admin_mass_email.php similarity index 100% rename from upload/admin/admin_mass_email.php rename to admin/admin_mass_email.php diff --git a/upload/admin/admin_phpinfo.php b/admin/admin_phpinfo.php similarity index 100% rename from upload/admin/admin_phpinfo.php rename to admin/admin_phpinfo.php diff --git a/upload/admin/admin_ranks.php b/admin/admin_ranks.php similarity index 100% rename from upload/admin/admin_ranks.php rename to admin/admin_ranks.php diff --git a/upload/admin/admin_rebuild_search.php b/admin/admin_rebuild_search.php similarity index 100% rename from upload/admin/admin_rebuild_search.php rename to admin/admin_rebuild_search.php diff --git a/upload/admin/admin_sitemap.php b/admin/admin_sitemap.php similarity index 100% rename from upload/admin/admin_sitemap.php rename to admin/admin_sitemap.php diff --git a/upload/admin/admin_smilies.php b/admin/admin_smilies.php similarity index 100% rename from upload/admin/admin_smilies.php rename to admin/admin_smilies.php diff --git a/upload/admin/admin_terms.php b/admin/admin_terms.php similarity index 100% rename from upload/admin/admin_terms.php rename to admin/admin_terms.php diff --git a/upload/admin/admin_ug_auth.php b/admin/admin_ug_auth.php similarity index 100% rename from upload/admin/admin_ug_auth.php rename to admin/admin_ug_auth.php diff --git a/upload/admin/admin_user_ban.php b/admin/admin_user_ban.php similarity index 100% rename from upload/admin/admin_user_ban.php rename to admin/admin_user_ban.php diff --git a/upload/admin/admin_user_search.php b/admin/admin_user_search.php similarity index 100% rename from upload/admin/admin_user_search.php rename to admin/admin_user_search.php diff --git a/upload/admin/admin_words.php b/admin/admin_words.php similarity index 100% rename from upload/admin/admin_words.php rename to admin/admin_words.php diff --git a/upload/admin/index.php b/admin/index.php similarity index 100% rename from upload/admin/index.php rename to admin/index.php diff --git a/upload/admin/pagestart.php b/admin/pagestart.php similarity index 100% rename from upload/admin/pagestart.php rename to admin/pagestart.php diff --git a/upload/admin/stats/tr_stats.php b/admin/stats/tr_stats.php similarity index 100% rename from upload/admin/stats/tr_stats.php rename to admin/stats/tr_stats.php diff --git a/upload/admin/stats/tracker.php b/admin/stats/tracker.php similarity index 100% rename from upload/admin/stats/tracker.php rename to admin/stats/tracker.php diff --git a/upload/ajax.php b/ajax.php similarity index 100% rename from upload/ajax.php rename to ajax.php diff --git a/upload/bt/announce.php b/bt/announce.php similarity index 99% rename from upload/bt/announce.php rename to bt/announce.php index 15bc122a4..70fc72331 100644 --- a/upload/bt/announce.php +++ b/bt/announce.php @@ -187,7 +187,7 @@ function msg_die ($msg) // Start announcer define('TR_ROOT', './'); -require(TR_ROOT .'includes/init_tr.php'); +require(TR_ROOT . 'includes/init_tr.php'); $seeder = ($left == 0) ? 1 : 0; $stopped = ($event === 'stopped'); diff --git a/upload/bt/includes/.htaccess b/bt/includes/.htaccess similarity index 100% rename from upload/bt/includes/.htaccess rename to bt/includes/.htaccess diff --git a/upload/bt/includes/init_tr.php b/bt/includes/init_tr.php similarity index 100% rename from upload/bt/includes/init_tr.php rename to bt/includes/init_tr.php diff --git a/upload/bt/index.php b/bt/index.php similarity index 100% rename from upload/bt/index.php rename to bt/index.php diff --git a/upload/bt/robots.txt b/bt/robots.txt similarity index 100% rename from upload/bt/robots.txt rename to bt/robots.txt diff --git a/upload/bt/scrape.php b/bt/scrape.php similarity index 96% rename from upload/bt/scrape.php rename to bt/scrape.php index 1821161ef..e09ebbb9b 100644 --- a/upload/bt/scrape.php +++ b/bt/scrape.php @@ -33,7 +33,7 @@ function msg_die ($msg) } define('TR_ROOT', './'); -require(TR_ROOT .'includes/init_tr.php'); +require(TR_ROOT . 'includes/init_tr.php'); $info_hash_sql = rtrim(DB()->escape($info_hash), ' '); diff --git a/upload/callseed.php b/callseed.php similarity index 100% rename from upload/callseed.php rename to callseed.php diff --git a/upload/common.php b/common.php similarity index 99% rename from upload/common.php rename to common.php index 68ae49dc5..1a2e40ec6 100644 --- a/upload/common.php +++ b/common.php @@ -17,7 +17,7 @@ if (!defined('IN_FORUM') && !defined('IN_TRACKER')) define('IN_FORUM', true); header('X-Frame-Options: SAMEORIGIN'); // Get initial config -require(BB_ROOT .'library/config.php'); +require(BB_ROOT . 'library/config.php'); $server_protocol = ($bb_cfg['cookie_secure']) ? 'https://' : 'http://'; $server_port = ($bb_cfg['server_port'] != 80) ? ':'. $bb_cfg['server_port'] : ''; diff --git a/upload/cron.php b/cron.php similarity index 100% rename from upload/cron.php rename to cron.php diff --git a/upload/crossdomain.xml b/crossdomain.xml similarity index 100% rename from upload/crossdomain.xml rename to crossdomain.xml diff --git a/upload/data/avatars/gallery/bot.gif b/data/avatars/gallery/bot.gif similarity index 100% rename from upload/data/avatars/gallery/bot.gif rename to data/avatars/gallery/bot.gif diff --git a/upload/data/avatars/gallery/noavatar.png b/data/avatars/gallery/noavatar.png similarity index 100% rename from upload/data/avatars/gallery/noavatar.png rename to data/avatars/gallery/noavatar.png diff --git a/upload/data/old_files/.htaccess b/data/old_files/.htaccess similarity index 100% rename from upload/data/old_files/.htaccess rename to data/old_files/.htaccess diff --git a/upload/data/torrent_files/.htaccess b/data/torrent_files/.htaccess similarity index 100% rename from upload/data/torrent_files/.htaccess rename to data/torrent_files/.htaccess diff --git a/upload/dl.php b/dl.php similarity index 100% rename from upload/dl.php rename to dl.php diff --git a/upload/dl_list.php b/dl_list.php similarity index 100% rename from upload/dl_list.php rename to dl_list.php diff --git a/upload/favicon.ico b/favicon.ico similarity index 100% rename from upload/favicon.ico rename to favicon.ico diff --git a/upload/feed.php b/feed.php similarity index 100% rename from upload/feed.php rename to feed.php diff --git a/upload/group.php b/group.php similarity index 100% rename from upload/group.php rename to group.php diff --git a/upload/group_edit.php b/group_edit.php similarity index 100% rename from upload/group_edit.php rename to group_edit.php diff --git a/upload/index.php b/index.php similarity index 100% rename from upload/index.php rename to index.php diff --git a/upload/info.php b/info.php similarity index 95% rename from upload/info.php rename to info.php index 5a596c053..500596c8d 100644 --- a/upload/info.php +++ b/info.php @@ -46,7 +46,7 @@ $require = file_exists($html_dir . $info['src']) ? $html_dir . $info['src'] : $h - + '; + + if (null == $escapeStart && null == $escapeEnd) { + // inner wrap with comment end and start if !IE + if (str_replace(' ', '', $item->attributes['conditional']) === '!IE') { + $html = '' . $html . ''; + } + + return $html; + } + + /** + * Override append to enforce style creation + * + * @param mixed $value + * @throws Exception\InvalidArgumentException + * @return void + */ + public function append($value) + { + if (!$this->isValid($value)) { + throw new Exception\InvalidArgumentException( + 'Invalid value passed to append; please use appendStyle()' + ); + } + + return $this->getContainer()->append($value); + } + + /** + * Override offsetSet to enforce style creation + * + * @param string|int $index + * @param mixed $value + * @throws Exception\InvalidArgumentException + * @return void + */ + public function offsetSet($index, $value) + { + if (!$this->isValid($value)) { + throw new Exception\InvalidArgumentException( + 'Invalid value passed to offsetSet; please use offsetSetStyle()' + ); + } + + return $this->getContainer()->offsetSet($index, $value); + } + + /** + * Override prepend to enforce style creation + * + * @param mixed $value + * @throws Exception\InvalidArgumentException + * @return void + */ + public function prepend($value) + { + if (!$this->isValid($value)) { + throw new Exception\InvalidArgumentException( + 'Invalid value passed to prepend; please use prependStyle()' + ); + } + + return $this->getContainer()->prepend($value); + } + + /** + * Override set to enforce style creation + * + * @param mixed $value + * @throws Exception\InvalidArgumentException + * @return void + */ + public function set($value) + { + if (!$this->isValid($value)) { + throw new Exception\InvalidArgumentException('Invalid value passed to set; please use setStyle()'); + } + + return $this->getContainer()->set($value); + } +} diff --git a/library/Zend/View/Helper/HeadTitle.php b/library/Zend/View/Helper/HeadTitle.php new file mode 100755 index 000000000..2ea8d78dd --- /dev/null +++ b/library/Zend/View/Helper/HeadTitle.php @@ -0,0 +1,263 @@ +getDefaultAttachOrder()) + ? Placeholder\Container\AbstractContainer::APPEND + : $this->getDefaultAttachOrder(); + } + + $title = (string) $title; + if ($title !== '') { + if ($setType == Placeholder\Container\AbstractContainer::SET) { + $this->set($title); + } elseif ($setType == Placeholder\Container\AbstractContainer::PREPEND) { + $this->prepend($title); + } else { + $this->append($title); + } + } + + return $this; + } + + /** + * Render title (wrapped by title tag) + * + * @param string|null $indent + * @return string + */ + public function toString($indent = null) + { + $indent = (null !== $indent) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + $output = $this->renderTitle(); + + return $indent . '' . $output . ''; + } + + /** + * Render title string + * + * @return string + */ + public function renderTitle() + { + $items = array(); + + if (null !== ($translator = $this->getTranslator())) { + foreach ($this as $item) { + $items[] = $translator->translate($item, $this->getTranslatorTextDomain()); + } + } else { + foreach ($this as $item) { + $items[] = $item; + } + } + + $separator = $this->getSeparator(); + $output = ''; + + $prefix = $this->getPrefix(); + if ($prefix) { + $output .= $prefix; + } + + $output .= implode($separator, $items); + + $postfix = $this->getPostfix(); + if ($postfix) { + $output .= $postfix; + } + + $output = ($this->autoEscape) ? $this->escape($output) : $output; + + return $output; + } + + /** + * Set a default order to add titles + * + * @param string $setType + * @throws Exception\DomainException + * @return HeadTitle + */ + public function setDefaultAttachOrder($setType) + { + if (!in_array($setType, array( + Placeholder\Container\AbstractContainer::APPEND, + Placeholder\Container\AbstractContainer::SET, + Placeholder\Container\AbstractContainer::PREPEND + ))) { + throw new Exception\DomainException( + "You must use a valid attach order: 'PREPEND', 'APPEND' or 'SET'" + ); + } + $this->defaultAttachOrder = $setType; + + return $this; + } + + /** + * Get the default attach order, if any. + * + * @return mixed + */ + public function getDefaultAttachOrder() + { + return $this->defaultAttachOrder; + } + + // Translator methods - Good candidate to refactor as a trait with PHP 5.4 + + /** + * Sets translator to use in helper + * + * @param Translator $translator [optional] translator. + * Default is null, which sets no translator. + * @param string $textDomain [optional] text domain + * Default is null, which skips setTranslatorTextDomain + * @return HeadTitle + */ + public function setTranslator(Translator $translator = null, $textDomain = null) + { + $this->translator = $translator; + if (null !== $textDomain) { + $this->setTranslatorTextDomain($textDomain); + } + return $this; + } + + /** + * Returns translator used in helper + * + * @return Translator|null + */ + public function getTranslator() + { + if (! $this->isTranslatorEnabled()) { + return null; + } + + return $this->translator; + } + + /** + * Checks if the helper has a translator + * + * @return bool + */ + public function hasTranslator() + { + return (bool) $this->getTranslator(); + } + + /** + * Sets whether translator is enabled and should be used + * + * @param bool $enabled [optional] whether translator should be used. + * Default is true. + * @return HeadTitle + */ + public function setTranslatorEnabled($enabled = true) + { + $this->translatorEnabled = (bool) $enabled; + return $this; + } + + /** + * Returns whether translator is enabled and should be used + * + * @return bool + */ + public function isTranslatorEnabled() + { + return $this->translatorEnabled; + } + + /** + * Set translation text domain + * + * @param string $textDomain + * @return HeadTitle + */ + public function setTranslatorTextDomain($textDomain = 'default') + { + $this->translatorTextDomain = $textDomain; + return $this; + } + + /** + * Return the translation text domain + * + * @return string + */ + public function getTranslatorTextDomain() + { + return $this->translatorTextDomain; + } +} diff --git a/library/Zend/View/Helper/HelperInterface.php b/library/Zend/View/Helper/HelperInterface.php new file mode 100755 index 000000000..2d58c01f9 --- /dev/null +++ b/library/Zend/View/Helper/HelperInterface.php @@ -0,0 +1,30 @@ + $data, 'quality' => 'high'), $params); + + $htmlObject = $this->getView()->plugin('htmlObject'); + return $htmlObject($data, self::TYPE, $attribs, $params, $content); + } +} diff --git a/library/Zend/View/Helper/HtmlList.php b/library/Zend/View/Helper/HtmlList.php new file mode 100755 index 000000000..29c79c73c --- /dev/null +++ b/library/Zend/View/Helper/HtmlList.php @@ -0,0 +1,58 @@ +getView()->plugin('escapeHtml'); + $item = $escaper($item); + } + $list .= '
  • ' . $item . '
  • ' . self::EOL; + } else { + $itemLength = 5 + strlen(self::EOL); + if ($itemLength < strlen($list)) { + $list = substr($list, 0, strlen($list) - $itemLength) + . $this($item, $ordered, $attribs, $escape) . '' . self::EOL; + } else { + $list .= '
  • ' . $this($item, $ordered, $attribs, $escape) . '
  • ' . self::EOL; + } + } + } + + if ($attribs) { + $attribs = $this->htmlAttribs($attribs); + } else { + $attribs = ''; + } + + $tag = ($ordered) ? 'ol' : 'ul'; + + return '<' . $tag . $attribs . '>' . self::EOL . $list . '' . self::EOL; + } +} diff --git a/library/Zend/View/Helper/HtmlObject.php b/library/Zend/View/Helper/HtmlObject.php new file mode 100755 index 000000000..17c2822f3 --- /dev/null +++ b/library/Zend/View/Helper/HtmlObject.php @@ -0,0 +1,63 @@ + $data, 'type' => $type), $attribs); + + // Params + $paramHtml = array(); + $closingBracket = $this->getClosingBracket(); + + foreach ($params as $param => $options) { + if (is_string($options)) { + $options = array('value' => $options); + } + + $options = array_merge(array('name' => $param), $options); + + $paramHtml[] = 'htmlAttribs($options) . $closingBracket; + } + + // Content + if (is_array($content)) { + $content = implode(self::EOL, $content); + } + + // Object header + $xhtml = 'htmlAttribs($attribs) . '>' . self::EOL + . implode(self::EOL, $paramHtml) . self::EOL + . ($content ? $content . self::EOL : '') + . ''; + + return $xhtml; + } +} diff --git a/library/Zend/View/Helper/HtmlPage.php b/library/Zend/View/Helper/HtmlPage.php new file mode 100755 index 000000000..ee170c1b0 --- /dev/null +++ b/library/Zend/View/Helper/HtmlPage.php @@ -0,0 +1,51 @@ + self::ATTRIB_CLASSID); + + /** + * Output a html object tag + * + * @param string $data The html url + * @param array $attribs Attribs for the object tag + * @param array $params Params for in the object tag + * @param string $content Alternative content + * @return string + */ + public function __invoke($data, array $attribs = array(), array $params = array(), $content = null) + { + // Attribs + $attribs = array_merge($this->attribs, $attribs); + + // Params + $params = array_merge(array('data' => $data), $params); + + $htmlObject = $this->getView()->plugin('htmlObject'); + return $htmlObject($data, self::TYPE, $attribs, $params, $content); + } +} diff --git a/library/Zend/View/Helper/HtmlQuicktime.php b/library/Zend/View/Helper/HtmlQuicktime.php new file mode 100755 index 000000000..629d6efa3 --- /dev/null +++ b/library/Zend/View/Helper/HtmlQuicktime.php @@ -0,0 +1,56 @@ + self::ATTRIB_CLASSID, 'codebase' => self::ATTRIB_CODEBASE); + + /** + * Output a quicktime movie object tag + * + * @param string $data The quicktime file + * @param array $attribs Attribs for the object tag + * @param array $params Params for in the object tag + * @param string $content Alternative content + * @return string + */ + public function __invoke($data, array $attribs = array(), array $params = array(), $content = null) + { + // Attrs + $attribs = array_merge($this->attribs, $attribs); + + // Params + $params = array_merge(array('src' => $data), $params); + + $htmlObject = $this->getView()->plugin('htmlObject'); + return $htmlObject($data, self::TYPE, $attribs, $params, $content); + } +} diff --git a/library/Zend/View/Helper/Identity.php b/library/Zend/View/Helper/Identity.php new file mode 100755 index 000000000..4fe145373 --- /dev/null +++ b/library/Zend/View/Helper/Identity.php @@ -0,0 +1,69 @@ +authenticationService instanceof AuthenticationService) { + throw new Exception\RuntimeException('No AuthenticationService instance provided'); + } + + if (!$this->authenticationService->hasIdentity()) { + return null; + } + + return $this->authenticationService->getIdentity(); + } + + /** + * Set AuthenticationService instance + * + * @param AuthenticationService $authenticationService + * @return Identity + */ + public function setAuthenticationService(AuthenticationService $authenticationService) + { + $this->authenticationService = $authenticationService; + return $this; + } + + /** + * Get AuthenticationService instance + * + * @return AuthenticationService + */ + public function getAuthenticationService() + { + return $this->authenticationService; + } +} diff --git a/library/Zend/View/Helper/InlineScript.php b/library/Zend/View/Helper/InlineScript.php new file mode 100755 index 000000000..57dace7d6 --- /dev/null +++ b/library/Zend/View/Helper/InlineScript.php @@ -0,0 +1,42 @@ +response instanceof Response) { + $headers = $this->response->getHeaders(); + $headers->addHeaderLine('Content-Type', 'application/json'); + } + + return $data; + } + + /** + * Set the response object + * + * @param Response $response + * @return Json + */ + public function setResponse(Response $response) + { + $this->response = $response; + return $this; + } +} diff --git a/library/Zend/View/Helper/Layout.php b/library/Zend/View/Helper/Layout.php new file mode 100755 index 000000000..65b630fb2 --- /dev/null +++ b/library/Zend/View/Helper/Layout.php @@ -0,0 +1,98 @@ +getRoot(); + } + + return $this->setTemplate($template); + } + + /** + * Get layout template + * + * @return string + */ + public function getLayout() + { + return $this->getRoot()->getTemplate(); + } + + /** + * Get the root view model + * + * @throws Exception\RuntimeException + * @return null|Model + */ + protected function getRoot() + { + $helper = $this->getViewModelHelper(); + + if (!$helper->hasRoot()) { + throw new Exception\RuntimeException(sprintf( + '%s: no view model currently registered as root in renderer', + __METHOD__ + )); + } + + return $helper->getRoot(); + } + + /** + * Set layout template + * + * @param string $template + * @return Layout + */ + public function setTemplate($template) + { + $this->getRoot()->setTemplate((string) $template); + return $this; + } + + /** + * Retrieve the view model helper + * + * @return ViewModel + */ + protected function getViewModelHelper() + { + if (null === $this->viewModelHelper) { + $this->viewModelHelper = $this->getView()->plugin('view_model'); + } + + return $this->viewModelHelper; + } +} diff --git a/library/Zend/View/Helper/Navigation.php b/library/Zend/View/Helper/Navigation.php new file mode 100755 index 000000000..015a5ec02 --- /dev/null +++ b/library/Zend/View/Helper/Navigation.php @@ -0,0 +1,346 @@ +setContainer($container); + } + + return $this; + } + + /** + * Magic overload: Proxy to other navigation helpers or the container + * + * Examples of usage from a view script or layout: + * + * // proxy to Menu helper and render container: + * echo $this->navigation()->menu(); + * + * // proxy to Breadcrumbs helper and set indentation: + * $this->navigation()->breadcrumbs()->setIndent(8); + * + * // proxy to container and find all pages with 'blog' route: + * $blogPages = $this->navigation()->findAllByRoute('blog'); + * + * + * @param string $method helper name or method name in container + * @param array $arguments [optional] arguments to pass + * @throws \Zend\View\Exception\ExceptionInterface if proxying to a helper, and the + * helper is not an instance of the + * interface specified in + * {@link findHelper()} + * @throws \Zend\Navigation\Exception\ExceptionInterface if method does not exist in container + * @return mixed returns what the proxied call returns + */ + public function __call($method, array $arguments = array()) + { + // check if call should proxy to another helper + $helper = $this->findHelper($method, false); + if ($helper) { + if ($helper instanceof ServiceLocatorAwareInterface && $this->getServiceLocator()) { + $helper->setServiceLocator($this->getServiceLocator()); + } + return call_user_func_array($helper, $arguments); + } + + // default behaviour: proxy call to container + return parent::__call($method, $arguments); + } + + /** + * Renders helper + * + * @param AbstractContainer $container + * @return string + * @throws Exception\RuntimeException + */ + public function render($container = null) + { + return $this->findHelper($this->getDefaultProxy())->render($container); + } + + /** + * Returns the helper matching $proxy + * + * The helper must implement the interface + * {@link Zend\View\Helper\Navigation\Helper}. + * + * @param string $proxy helper name + * @param bool $strict [optional] whether exceptions should be + * thrown if something goes + * wrong. Default is true. + * @throws Exception\RuntimeException if $strict is true and helper cannot be found + * @return \Zend\View\Helper\Navigation\HelperInterface helper instance + */ + public function findHelper($proxy, $strict = true) + { + $plugins = $this->getPluginManager(); + if (!$plugins->has($proxy)) { + if ($strict) { + throw new Exception\RuntimeException(sprintf( + 'Failed to find plugin for %s', + $proxy + )); + } + return false; + } + + $helper = $plugins->get($proxy); + $container = $this->getContainer(); + $hash = spl_object_hash($container) . spl_object_hash($helper); + + if (!isset($this->injected[$hash])) { + $helper->setContainer(); + $this->inject($helper); + $this->injected[$hash] = true; + } else { + if ($this->getInjectContainer()) { + $helper->setContainer($container); + } + } + + return $helper; + } + + /** + * Injects container, ACL, and translator to the given $helper if this + * helper is configured to do so + * + * @param NavigationHelper $helper helper instance + * @return void + */ + protected function inject(NavigationHelper $helper) + { + if ($this->getInjectContainer() && !$helper->hasContainer()) { + $helper->setContainer($this->getContainer()); + } + + if ($this->getInjectAcl()) { + if (!$helper->hasAcl()) { + $helper->setAcl($this->getAcl()); + } + if (!$helper->hasRole()) { + $helper->setRole($this->getRole()); + } + } + + if ($this->getInjectTranslator() && !$helper->hasTranslator()) { + $helper->setTranslator( + $this->getTranslator(), + $this->getTranslatorTextDomain() + ); + } + } + + /** + * Sets the default proxy to use in {@link render()} + * + * @param string $proxy default proxy + * @return Navigation + */ + public function setDefaultProxy($proxy) + { + $this->defaultProxy = (string) $proxy; + return $this; + } + + /** + * Returns the default proxy to use in {@link render()} + * + * @return string + */ + public function getDefaultProxy() + { + return $this->defaultProxy; + } + + /** + * Sets whether container should be injected when proxying + * + * @param bool $injectContainer + * @return Navigation + */ + public function setInjectContainer($injectContainer = true) + { + $this->injectContainer = (bool) $injectContainer; + return $this; + } + + /** + * Returns whether container should be injected when proxying + * + * @return bool + */ + public function getInjectContainer() + { + return $this->injectContainer; + } + + /** + * Sets whether ACL should be injected when proxying + * + * @param bool $injectAcl + * @return Navigation + */ + public function setInjectAcl($injectAcl = true) + { + $this->injectAcl = (bool) $injectAcl; + return $this; + } + + /** + * Returns whether ACL should be injected when proxying + * + * @return bool + */ + public function getInjectAcl() + { + return $this->injectAcl; + } + + /** + * Sets whether translator should be injected when proxying + * + * @param bool $injectTranslator + * @return Navigation + */ + public function setInjectTranslator($injectTranslator = true) + { + $this->injectTranslator = (bool) $injectTranslator; + return $this; + } + + /** + * Returns whether translator should be injected when proxying + * + * @return bool + */ + public function getInjectTranslator() + { + return $this->injectTranslator; + } + + /** + * Set manager for retrieving navigation helpers + * + * @param Navigation\PluginManager $plugins + * @return Navigation + */ + public function setPluginManager(Navigation\PluginManager $plugins) + { + $renderer = $this->getView(); + if ($renderer) { + $plugins->setRenderer($renderer); + } + $this->plugins = $plugins; + + return $this; + } + + /** + * Retrieve plugin loader for navigation helpers + * + * Lazy-loads an instance of Navigation\HelperLoader if none currently + * registered. + * + * @return Navigation\PluginManager + */ + public function getPluginManager() + { + if (null === $this->plugins) { + $this->setPluginManager(new Navigation\PluginManager()); + } + + return $this->plugins; + } + + /** + * Set the View object + * + * @param Renderer $view + * @return self + */ + public function setView(Renderer $view) + { + parent::setView($view); + if ($view && $this->plugins) { + $this->plugins->setRenderer($view); + } + return $this; + } +} diff --git a/library/Zend/View/Helper/Navigation/AbstractHelper.php b/library/Zend/View/Helper/Navigation/AbstractHelper.php new file mode 100755 index 000000000..1b997683f --- /dev/null +++ b/library/Zend/View/Helper/Navigation/AbstractHelper.php @@ -0,0 +1,945 @@ +getContainer(), $method), + $arguments); + } + + /** + * Magic overload: Proxy to {@link render()}. + * + * This method will trigger an E_USER_ERROR if rendering the helper causes + * an exception to be thrown. + * + * Implements {@link HelperInterface::__toString()}. + * + * @return string + */ + public function __toString() + { + try { + return $this->render(); + } catch (\Exception $e) { + $msg = get_class($e) . ': ' . $e->getMessage(); + trigger_error($msg, E_USER_ERROR); + return ''; + } + } + + /** + * Finds the deepest active page in the given container + * + * @param Navigation\AbstractContainer $container container to search + * @param int|null $minDepth [optional] minimum depth + * required for page to be + * valid. Default is to use + * {@link getMinDepth()}. A + * null value means no minimum + * depth required. + * @param int|null $maxDepth [optional] maximum depth + * a page can have to be + * valid. Default is to use + * {@link getMaxDepth()}. A + * null value means no maximum + * depth required. + * @return array an associative array with + * the values 'depth' and + * 'page', or an empty array + * if not found + */ + public function findActive($container, $minDepth = null, $maxDepth = -1) + { + $this->parseContainer($container); + if (!is_int($minDepth)) { + $minDepth = $this->getMinDepth(); + } + if ((!is_int($maxDepth) || $maxDepth < 0) && null !== $maxDepth) { + $maxDepth = $this->getMaxDepth(); + } + + $found = null; + $foundDepth = -1; + $iterator = new RecursiveIteratorIterator( + $container, + RecursiveIteratorIterator::CHILD_FIRST + ); + + /** @var \Zend\Navigation\Page\AbstractPage $page */ + foreach ($iterator as $page) { + $currDepth = $iterator->getDepth(); + if ($currDepth < $minDepth || !$this->accept($page)) { + // page is not accepted + continue; + } + + if ($page->isActive(false) && $currDepth > $foundDepth) { + // found an active page at a deeper level than before + $found = $page; + $foundDepth = $currDepth; + } + } + + if (is_int($maxDepth) && $foundDepth > $maxDepth) { + while ($foundDepth > $maxDepth) { + if (--$foundDepth < $minDepth) { + $found = null; + break; + } + + $found = $found->getParent(); + if (!$found instanceof AbstractPage) { + $found = null; + break; + } + } + } + + if ($found) { + return array('page' => $found, 'depth' => $foundDepth); + } + + return array(); + } + + /** + * Verifies container and eventually fetches it from service locator if it is a string + * + * @param Navigation\AbstractContainer|string|null $container + * @throws Exception\InvalidArgumentException + */ + protected function parseContainer(&$container = null) + { + if (null === $container) { + return; + } + + if (is_string($container)) { + if (!$this->getServiceLocator()) { + throw new Exception\InvalidArgumentException(sprintf( + 'Attempted to set container with alias "%s" but no ServiceLocator was set', + $container + )); + } + + /** + * Load the navigation container from the root service locator + * + * The navigation container is probably located in Zend\ServiceManager\ServiceManager + * and not in the View\HelperPluginManager. If the set service locator is a + * HelperPluginManager, access the navigation container via the main service locator. + */ + $sl = $this->getServiceLocator(); + if ($sl instanceof View\HelperPluginManager) { + $sl = $sl->getServiceLocator(); + } + $container = $sl->get($container); + return; + } + + if (!$container instanceof Navigation\AbstractContainer) { + throw new Exception\InvalidArgumentException( + 'Container must be a string alias or an instance of ' . + 'Zend\Navigation\AbstractContainer' + ); + } + } + + // Iterator filter methods: + + /** + * Determines whether a page should be accepted when iterating + * + * Default listener may be 'overridden' by attaching listener to 'isAllowed' + * method. Listener must be 'short circuited' if overriding default ACL + * listener. + * + * Rules: + * - If a page is not visible it is not accepted, unless RenderInvisible has + * been set to true + * - If $useAcl is true (default is true): + * - Page is accepted if listener returns true, otherwise false + * - If page is accepted and $recursive is true, the page + * will not be accepted if it is the descendant of a non-accepted page + * + * @param AbstractPage $page page to check + * @param bool $recursive [optional] if true, page will not be + * accepted if it is the descendant of + * a page that is not accepted. Default + * is true + * + * @return bool Whether page should be accepted + */ + public function accept(AbstractPage $page, $recursive = true) + { + $accept = true; + + if (!$page->isVisible(false) && !$this->getRenderInvisible()) { + $accept = false; + } elseif ($this->getUseAcl()) { + $acl = $this->getAcl(); + $role = $this->getRole(); + $params = array('acl' => $acl, 'page' => $page, 'role' => $role); + $accept = $this->isAllowed($params); + } + + if ($accept && $recursive) { + $parent = $page->getParent(); + + if ($parent instanceof AbstractPage) { + $accept = $this->accept($parent, true); + } + } + + return $accept; + } + + /** + * Determines whether a page should be allowed given certain parameters + * + * @param array $params + * @return bool + */ + protected function isAllowed($params) + { + $results = $this->getEventManager()->trigger(__FUNCTION__, $this, $params); + return $results->last(); + } + + // Util methods: + + /** + * Retrieve whitespace representation of $indent + * + * @param int|string $indent + * @return string + */ + protected function getWhitespace($indent) + { + if (is_int($indent)) { + $indent = str_repeat(' ', $indent); + } + + return (string) $indent; + } + + /** + * Converts an associative array to a string of tag attributes. + * + * Overloads {@link View\Helper\AbstractHtmlElement::htmlAttribs()}. + * + * @param array $attribs an array where each key-value pair is converted + * to an attribute name and value + * @return string + */ + protected function htmlAttribs($attribs) + { + // filter out null values and empty string values + foreach ($attribs as $key => $value) { + if ($value === null || (is_string($value) && !strlen($value))) { + unset($attribs[$key]); + } + } + + return parent::htmlAttribs($attribs); + } + + /** + * Returns an HTML string containing an 'a' element for the given page + * + * @param AbstractPage $page page to generate HTML for + * @return string HTML string (Label) + */ + public function htmlify(AbstractPage $page) + { + $label = $this->translate($page->getLabel(), $page->getTextDomain()); + $title = $this->translate($page->getTitle(), $page->getTextDomain()); + + // get attribs for anchor element + $attribs = array( + 'id' => $page->getId(), + 'title' => $title, + 'class' => $page->getClass(), + 'href' => $page->getHref(), + 'target' => $page->getTarget() + ); + + /** @var \Zend\View\Helper\EscapeHtml $escaper */ + $escaper = $this->view->plugin('escapeHtml'); + $label = $escaper($label); + + return 'htmlAttribs($attribs) . '>' . $label . ''; + } + + /** + * Translate a message (for label, title, …) + * + * @param string $message ID of the message to translate + * @param string $textDomain Text domain (category name for the translations) + * @return string Translated message + */ + protected function translate($message, $textDomain = null) + { + if (is_string($message) && !empty($message)) { + if (null !== ($translator = $this->getTranslator())) { + if (null === $textDomain) { + $textDomain = $this->getTranslatorTextDomain(); + } + + return $translator->translate($message, $textDomain); + } + } + + return $message; + } + + /** + * Normalize an ID + * + * Overrides {@link View\Helper\AbstractHtmlElement::normalizeId()}. + * + * @param string $value + * @return string + */ + protected function normalizeId($value) + { + $prefix = get_class($this); + $prefix = strtolower(trim(substr($prefix, strrpos($prefix, '\\')), '\\')); + + return $prefix . '-' . $value; + } + + /** + * Sets ACL to use when iterating pages + * + * Implements {@link HelperInterface::setAcl()}. + * + * @param Acl\AclInterface $acl ACL object. + * @return AbstractHelper + */ + public function setAcl(Acl\AclInterface $acl = null) + { + $this->acl = $acl; + return $this; + } + + /** + * Returns ACL or null if it isn't set using {@link setAcl()} or + * {@link setDefaultAcl()} + * + * Implements {@link HelperInterface::getAcl()}. + * + * @return Acl\AclInterface|null ACL object or null + */ + public function getAcl() + { + if ($this->acl === null && static::$defaultAcl !== null) { + return static::$defaultAcl; + } + + return $this->acl; + } + + /** + * Checks if the helper has an ACL instance + * + * Implements {@link HelperInterface::hasAcl()}. + * + * @return bool + */ + public function hasAcl() + { + if ($this->acl instanceof Acl\Acl + || static::$defaultAcl instanceof Acl\Acl + ) { + return true; + } + + return false; + } + + /** + * Set the event manager. + * + * @param EventManagerInterface $events + * @return AbstractHelper + */ + public function setEventManager(EventManagerInterface $events) + { + $events->setIdentifiers(array( + __CLASS__, + get_called_class(), + )); + + $this->events = $events; + + $this->setDefaultListeners(); + + return $this; + } + + /** + * Get the event manager. + * + * @return EventManagerInterface + */ + public function getEventManager() + { + if (null === $this->events) { + $this->setEventManager(new EventManager()); + } + + return $this->events; + } + + /** + * Sets navigation container the helper operates on by default + * + * Implements {@link HelperInterface::setContainer()}. + * + * @param string|Navigation\AbstractContainer $container Default is null, meaning container will be reset. + * @return AbstractHelper + */ + public function setContainer($container = null) + { + $this->parseContainer($container); + $this->container = $container; + + return $this; + } + + /** + * Returns the navigation container helper operates on by default + * + * Implements {@link HelperInterface::getContainer()}. + * + * If no container is set, a new container will be instantiated and + * stored in the helper. + * + * @return Navigation\AbstractContainer navigation container + */ + public function getContainer() + { + if (null === $this->container) { + $this->container = new Navigation\Navigation(); + } + + return $this->container; + } + + /** + * Checks if the helper has a container + * + * Implements {@link HelperInterface::hasContainer()}. + * + * @return bool + */ + public function hasContainer() + { + return null !== $this->container; + } + + /** + * Set the indentation string for using in {@link render()}, optionally a + * number of spaces to indent with + * + * @param string|int $indent + * @return AbstractHelper + */ + public function setIndent($indent) + { + $this->indent = $this->getWhitespace($indent); + return $this; + } + + /** + * Returns indentation + * + * @return string + */ + public function getIndent() + { + return $this->indent; + } + + /** + * Sets the maximum depth a page can have to be included when rendering + * + * @param int $maxDepth Default is null, which sets no maximum depth. + * @return AbstractHelper + */ + public function setMaxDepth($maxDepth = null) + { + if (null === $maxDepth || is_int($maxDepth)) { + $this->maxDepth = $maxDepth; + } else { + $this->maxDepth = (int) $maxDepth; + } + + return $this; + } + + /** + * Returns maximum depth a page can have to be included when rendering + * + * @return int|null + */ + public function getMaxDepth() + { + return $this->maxDepth; + } + + /** + * Sets the minimum depth a page must have to be included when rendering + * + * @param int $minDepth Default is null, which sets no minimum depth. + * @return AbstractHelper + */ + public function setMinDepth($minDepth = null) + { + if (null === $minDepth || is_int($minDepth)) { + $this->minDepth = $minDepth; + } else { + $this->minDepth = (int) $minDepth; + } + + return $this; + } + + /** + * Returns minimum depth a page must have to be included when rendering + * + * @return int|null + */ + public function getMinDepth() + { + if (!is_int($this->minDepth) || $this->minDepth < 0) { + return 0; + } + + return $this->minDepth; + } + + /** + * Render invisible items? + * + * @param bool $renderInvisible + * @return AbstractHelper + */ + public function setRenderInvisible($renderInvisible = true) + { + $this->renderInvisible = (bool) $renderInvisible; + return $this; + } + + /** + * Return renderInvisible flag + * + * @return bool + */ + public function getRenderInvisible() + { + return $this->renderInvisible; + } + + /** + * Sets ACL role(s) to use when iterating pages + * + * Implements {@link HelperInterface::setRole()}. + * + * @param mixed $role [optional] role to set. Expects a string, an + * instance of type {@link Acl\Role\RoleInterface}, or null. Default + * is null, which will set no role. + * @return AbstractHelper + * @throws Exception\InvalidArgumentException + */ + public function setRole($role = null) + { + if (null === $role || is_string($role) || + $role instanceof Acl\Role\RoleInterface + ) { + $this->role = $role; + } else { + throw new Exception\InvalidArgumentException(sprintf( + '$role must be a string, null, or an instance of ' + . 'Zend\Permissions\Role\RoleInterface; %s given', + (is_object($role) ? get_class($role) : gettype($role)) + )); + } + + return $this; + } + + /** + * Returns ACL role to use when iterating pages, or null if it isn't set + * using {@link setRole()} or {@link setDefaultRole()} + * + * Implements {@link HelperInterface::getRole()}. + * + * @return string|Acl\Role\RoleInterface|null + */ + public function getRole() + { + if ($this->role === null && static::$defaultRole !== null) { + return static::$defaultRole; + } + + return $this->role; + } + + /** + * Checks if the helper has an ACL role + * + * Implements {@link HelperInterface::hasRole()}. + * + * @return bool + */ + public function hasRole() + { + if ($this->role instanceof Acl\Role\RoleInterface + || is_string($this->role) + || static::$defaultRole instanceof Acl\Role\RoleInterface + || is_string(static::$defaultRole) + ) { + return true; + } + + return false; + } + + /** + * Set the service locator. + * + * @param ServiceLocatorInterface $serviceLocator + * @return AbstractHelper + */ + public function setServiceLocator(ServiceLocatorInterface $serviceLocator) + { + $this->serviceLocator = $serviceLocator; + return $this; + } + + /** + * Get the service locator. + * + * @return ServiceLocatorInterface + */ + public function getServiceLocator() + { + return $this->serviceLocator; + } + + // Translator methods - Good candidate to refactor as a trait with PHP 5.4 + + /** + * Sets translator to use in helper + * + * @param Translator $translator [optional] translator. + * Default is null, which sets no translator. + * @param string $textDomain [optional] text domain + * Default is null, which skips setTranslatorTextDomain + * @return AbstractHelper + */ + public function setTranslator(Translator $translator = null, $textDomain = null) + { + $this->translator = $translator; + if (null !== $textDomain) { + $this->setTranslatorTextDomain($textDomain); + } + + return $this; + } + + /** + * Returns translator used in helper + * + * @return Translator|null + */ + public function getTranslator() + { + if (! $this->isTranslatorEnabled()) { + return null; + } + + return $this->translator; + } + + /** + * Checks if the helper has a translator + * + * @return bool + */ + public function hasTranslator() + { + return (bool) $this->getTranslator(); + } + + /** + * Sets whether translator is enabled and should be used + * + * @param bool $enabled + * @return AbstractHelper + */ + public function setTranslatorEnabled($enabled = true) + { + $this->translatorEnabled = (bool) $enabled; + return $this; + } + + /** + * Returns whether translator is enabled and should be used + * + * @return bool + */ + public function isTranslatorEnabled() + { + return $this->translatorEnabled; + } + + /** + * Set translation text domain + * + * @param string $textDomain + * @return AbstractHelper + */ + public function setTranslatorTextDomain($textDomain = 'default') + { + $this->translatorTextDomain = $textDomain; + return $this; + } + + /** + * Return the translation text domain + * + * @return string + */ + public function getTranslatorTextDomain() + { + return $this->translatorTextDomain; + } + + /** + * Sets whether ACL should be used + * + * Implements {@link HelperInterface::setUseAcl()}. + * + * @param bool $useAcl + * @return AbstractHelper + */ + public function setUseAcl($useAcl = true) + { + $this->useAcl = (bool) $useAcl; + return $this; + } + + /** + * Returns whether ACL should be used + * + * Implements {@link HelperInterface::getUseAcl()}. + * + * @return bool + */ + public function getUseAcl() + { + return $this->useAcl; + } + + // Static methods: + + /** + * Sets default ACL to use if another ACL is not explicitly set + * + * @param Acl\AclInterface $acl [optional] ACL object. Default is null, which + * sets no ACL object. + * @return void + */ + public static function setDefaultAcl(Acl\AclInterface $acl = null) + { + static::$defaultAcl = $acl; + } + + /** + * Sets default ACL role(s) to use when iterating pages if not explicitly + * set later with {@link setRole()} + * + * @param mixed $role [optional] role to set. Expects null, string, or an + * instance of {@link Acl\Role\RoleInterface}. Default is null, which + * sets no default role. + * @return void + * @throws Exception\InvalidArgumentException if role is invalid + */ + public static function setDefaultRole($role = null) + { + if (null === $role + || is_string($role) + || $role instanceof Acl\Role\RoleInterface + ) { + static::$defaultRole = $role; + } else { + throw new Exception\InvalidArgumentException(sprintf( + '$role must be null|string|Zend\Permissions\Role\RoleInterface; received "%s"', + (is_object($role) ? get_class($role) : gettype($role)) + )); + } + } + + /** + * Attaches default ACL listeners, if ACLs are in use + */ + protected function setDefaultListeners() + { + if (!$this->getUseAcl()) { + return; + } + + $this->getEventManager()->getSharedManager()->attach( + 'Zend\View\Helper\Navigation\AbstractHelper', + 'isAllowed', + array('Zend\View\Helper\Navigation\Listener\AclListener', 'accept') + ); + } +} diff --git a/library/Zend/View/Helper/Navigation/Breadcrumbs.php b/library/Zend/View/Helper/Navigation/Breadcrumbs.php new file mode 100755 index 000000000..5337ca8e0 --- /dev/null +++ b/library/Zend/View/Helper/Navigation/Breadcrumbs.php @@ -0,0 +1,292 @@ +setContainer($container); + } + + return $this; + } + + /** + * Renders helper + * + * Implements {@link HelperInterface::render()}. + * + * @param AbstractContainer $container [optional] container to render. Default is + * to render the container registered in the helper. + * @return string + */ + public function render($container = null) + { + $partial = $this->getPartial(); + if ($partial) { + return $this->renderPartial($container, $partial); + } + + return $this->renderStraight($container); + } + + /** + * Renders breadcrumbs by chaining 'a' elements with the separator + * registered in the helper + * + * @param AbstractContainer $container [optional] container to render. Default is + * to render the container registered in the helper. + * @return string + */ + public function renderStraight($container = null) + { + $this->parseContainer($container); + if (null === $container) { + $container = $this->getContainer(); + } + + // find deepest active + if (!$active = $this->findActive($container)) { + return ''; + } + + $active = $active['page']; + + // put the deepest active page last in breadcrumbs + if ($this->getLinkLast()) { + $html = $this->htmlify($active); + } else { + /** @var \Zend\View\Helper\EscapeHtml $escaper */ + $escaper = $this->view->plugin('escapeHtml'); + $html = $escaper( + $this->translate($active->getLabel(), $active->getTextDomain()) + ); + } + + // walk back to root + while ($parent = $active->getParent()) { + if ($parent instanceof AbstractPage) { + // prepend crumb to html + $html = $this->htmlify($parent) + . $this->getSeparator() + . $html; + } + + if ($parent === $container) { + // at the root of the given container + break; + } + + $active = $parent; + } + + return strlen($html) ? $this->getIndent() . $html : ''; + } + + /** + * Renders the given $container by invoking the partial view helper + * + * The container will simply be passed on as a model to the view script, + * so in the script it will be available in $this->container. + * + * @param AbstractContainer $container [optional] container to pass to view script. + * Default is to use the container registered + * in the helper. + * @param string|array $partial [optional] partial view script to use. + * Default is to use the partial registered + * in the helper. If an array is given, it + * is expected to contain two values; the + * partial view script to use, and the module + * where the script can be found. + * @throws Exception\RuntimeException if no partial provided + * @throws Exception\InvalidArgumentException if partial is invalid array + * @return string helper output + */ + public function renderPartial($container = null, $partial = null) + { + $this->parseContainer($container); + if (null === $container) { + $container = $this->getContainer(); + } + + if (null === $partial) { + $partial = $this->getPartial(); + } + + if (empty($partial)) { + throw new Exception\RuntimeException( + 'Unable to render menu: No partial view script provided' + ); + } + + // put breadcrumb pages in model + $model = array( + 'pages' => array(), + 'separator' => $this->getSeparator() + ); + $active = $this->findActive($container); + if ($active) { + $active = $active['page']; + $model['pages'][] = $active; + while ($parent = $active->getParent()) { + if ($parent instanceof AbstractPage) { + $model['pages'][] = $parent; + } else { + break; + } + + if ($parent === $container) { + // break if at the root of the given container + break; + } + + $active = $parent; + } + $model['pages'] = array_reverse($model['pages']); + } + + /** @var \Zend\View\Helper\Partial $partialHelper */ + $partialHelper = $this->view->plugin('partial'); + + if (is_array($partial)) { + if (count($partial) != 2) { + throw new Exception\InvalidArgumentException( + 'Unable to render menu: A view partial supplied as ' + . 'an array must contain two values: partial view ' + . 'script and module where script can be found' + ); + } + + return $partialHelper($partial[0], $model); + } + + return $partialHelper($partial, $model); + } + + /** + * Sets whether last page in breadcrumbs should be hyperlinked + * + * @param bool $linkLast whether last page should be hyperlinked + * @return Breadcrumbs + */ + public function setLinkLast($linkLast) + { + $this->linkLast = (bool) $linkLast; + return $this; + } + + /** + * Returns whether last page in breadcrumbs should be hyperlinked + * + * @return bool + */ + public function getLinkLast() + { + return $this->linkLast; + } + + /** + * Sets which partial view script to use for rendering menu + * + * @param string|array $partial partial view script or null. If an array is + * given, it is expected to contain two + * values; the partial view script to use, + * and the module where the script can be + * found. + * @return Breadcrumbs + */ + public function setPartial($partial) + { + if (null === $partial || is_string($partial) || is_array($partial)) { + $this->partial = $partial; + } + + return $this; + } + + /** + * Returns partial view script to use for rendering menu + * + * @return string|array|null + */ + public function getPartial() + { + return $this->partial; + } + + /** + * Sets breadcrumb separator + * + * @param string $separator separator string + * @return Breadcrumbs + */ + public function setSeparator($separator) + { + if (is_string($separator)) { + $this->separator = $separator; + } + + return $this; + } + + /** + * Returns breadcrumb separator + * + * @return string breadcrumb separator + */ + public function getSeparator() + { + return $this->separator; + } +} diff --git a/library/Zend/View/Helper/Navigation/HelperInterface.php b/library/Zend/View/Helper/Navigation/HelperInterface.php new file mode 100755 index 000000000..8b52c8c1d --- /dev/null +++ b/library/Zend/View/Helper/Navigation/HelperInterface.php @@ -0,0 +1,143 @@ + elements + */ +class Links extends AbstractHelper +{ + /** + * Constants used for specifying which link types to find and render + * + * @var int + */ + const RENDER_ALTERNATE = 0x0001; + const RENDER_STYLESHEET = 0x0002; + const RENDER_START = 0x0004; + const RENDER_NEXT = 0x0008; + const RENDER_PREV = 0x0010; + const RENDER_CONTENTS = 0x0020; + const RENDER_INDEX = 0x0040; + const RENDER_GLOSSARY = 0x0080; + const RENDER_COPYRIGHT = 0x0100; + const RENDER_CHAPTER = 0x0200; + const RENDER_SECTION = 0x0400; + const RENDER_SUBSECTION = 0x0800; + const RENDER_APPENDIX = 0x1000; + const RENDER_HELP = 0x2000; + const RENDER_BOOKMARK = 0x4000; + const RENDER_CUSTOM = 0x8000; + const RENDER_ALL = 0xffff; + + /** + * Maps render constants to W3C link types + * + * @var array + */ + protected static $RELATIONS = array( + self::RENDER_ALTERNATE => 'alternate', + self::RENDER_STYLESHEET => 'stylesheet', + self::RENDER_START => 'start', + self::RENDER_NEXT => 'next', + self::RENDER_PREV => 'prev', + self::RENDER_CONTENTS => 'contents', + self::RENDER_INDEX => 'index', + self::RENDER_GLOSSARY => 'glossary', + self::RENDER_COPYRIGHT => 'copyright', + self::RENDER_CHAPTER => 'chapter', + self::RENDER_SECTION => 'section', + self::RENDER_SUBSECTION => 'subsection', + self::RENDER_APPENDIX => 'appendix', + self::RENDER_HELP => 'help', + self::RENDER_BOOKMARK => 'bookmark', + ); + + /** + * The helper's render flag + * + * @see render() + * @see setRenderFlag() + * @var int + */ + protected $renderFlag = self::RENDER_ALL; + + /** + * Root container + * + * Used for preventing methods to traverse above the container given to + * the {@link render()} method. + * + * @see _findRoot() + * @var AbstractContainer + */ + protected $root; + + /** + * Helper entry point + * + * @param string|AbstractContainer $container container to operate on + * @return Links + */ + public function __invoke($container = null) + { + if (null !== $container) { + $this->setContainer($container); + } + + return $this; + } + + /** + * Magic overload: Proxy calls to {@link findRelation()} or container + * + * Examples of finder calls: + * + * // METHOD // SAME AS + * $h->findRelNext($page); // $h->findRelation($page, 'rel', 'next') + * $h->findRevSection($page); // $h->findRelation($page, 'rev', 'section'); + * $h->findRelFoo($page); // $h->findRelation($page, 'rel', 'foo'); + * + * + * @param string $method + * @param array $arguments + * @return mixed + * @throws Exception\ExceptionInterface + */ + public function __call($method, array $arguments = array()) + { + ErrorHandler::start(E_WARNING); + $result = preg_match('/find(Rel|Rev)(.+)/', $method, $match); + ErrorHandler::stop(); + if ($result) { + return $this->findRelation($arguments[0], + strtolower($match[1]), + strtolower($match[2])); + } + + return parent::__call($method, $arguments); + } + + /** + * Renders helper + * + * Implements {@link HelperInterface::render()}. + * + * @param AbstractContainer|string|null $container [optional] container to render. + * Default is to render the + * container registered in the + * helper. + * @return string + */ + public function render($container = null) + { + $this->parseContainer($container); + if (null === $container) { + $container = $this->getContainer(); + } + + $active = $this->findActive($container); + if ($active) { + $active = $active['page']; + } else { + // no active page + return ''; + } + + $output = ''; + $indent = $this->getIndent(); + $this->root = $container; + + $result = $this->findAllRelations($active, $this->getRenderFlag()); + foreach ($result as $attrib => $types) { + foreach ($types as $relation => $pages) { + foreach ($pages as $page) { + $r = $this->renderLink($page, $attrib, $relation); + if ($r) { + $output .= $indent . $r . self::EOL; + } + } + } + } + + $this->root = null; + + // return output (trim last newline by spec) + return strlen($output) ? rtrim($output, self::EOL) : ''; + } + + /** + * Renders the given $page as a link element, with $attrib = $relation + * + * @param AbstractPage $page the page to render the link for + * @param string $attrib the attribute to use for $type, + * either 'rel' or 'rev' + * @param string $relation relation type, muse be one of; + * alternate, appendix, bookmark, + * chapter, contents, copyright, + * glossary, help, home, index, next, + * prev, section, start, stylesheet, + * subsection + * @return string + * @throws Exception\DomainException + */ + public function renderLink(AbstractPage $page, $attrib, $relation) + { + if (!in_array($attrib, array('rel', 'rev'))) { + throw new Exception\DomainException(sprintf( + 'Invalid relation attribute "%s", must be "rel" or "rev"', + $attrib + )); + } + + if (!$href = $page->getHref()) { + return ''; + } + + // TODO: add more attribs + // http://www.w3.org/TR/html401/struct/links.html#h-12.2 + $attribs = array( + $attrib => $relation, + 'href' => $href, + 'title' => $page->getLabel() + ); + + return 'htmlAttribs($attribs) . + $this->getClosingBracket(); + } + + // Finder methods: + + /** + * Finds all relations (forward and reverse) for the given $page + * + * The form of the returned array: + * + * // $page denotes an instance of Zend\Navigation\Page\AbstractPage + * $returned = array( + * 'rel' => array( + * 'alternate' => array($page, $page, $page), + * 'start' => array($page), + * 'next' => array($page), + * 'prev' => array($page), + * 'canonical' => array($page) + * ), + * 'rev' => array( + * 'section' => array($page) + * ) + * ); + * + * + * @param AbstractPage $page page to find links for + * @param null|int + * @return array + */ + public function findAllRelations(AbstractPage $page, $flag = null) + { + if (!is_int($flag)) { + $flag = self::RENDER_ALL; + } + + $result = array('rel' => array(), 'rev' => array()); + $native = array_values(static::$RELATIONS); + + foreach (array_keys($result) as $rel) { + $meth = 'getDefined' . ucfirst($rel); + $types = array_merge($native, array_diff($page->$meth(), $native)); + + foreach ($types as $type) { + if (!$relFlag = array_search($type, static::$RELATIONS)) { + $relFlag = self::RENDER_CUSTOM; + } + if (!($flag & $relFlag)) { + continue; + } + + $found = $this->findRelation($page, $rel, $type); + if ($found) { + if (!is_array($found)) { + $found = array($found); + } + $result[$rel][$type] = $found; + } + } + } + + return $result; + } + + /** + * Finds relations of the given $rel=$type from $page + * + * This method will first look for relations in the page instance, then + * by searching the root container if nothing was found in the page. + * + * @param AbstractPage $page page to find relations for + * @param string $rel relation, "rel" or "rev" + * @param string $type link type, e.g. 'start', 'next' + * @return AbstractPage|array|null + * @throws Exception\DomainException if $rel is not "rel" or "rev" + */ + public function findRelation(AbstractPage $page, $rel, $type) + { + if (!in_array($rel, array('rel', 'rev'))) { + throw new Exception\DomainException(sprintf( + 'Invalid argument: $rel must be "rel" or "rev"; "%s" given', + $rel + )); + } + + if (!$result = $this->findFromProperty($page, $rel, $type)) { + $result = $this->findFromSearch($page, $rel, $type); + } + + return $result; + } + + /** + * Finds relations of given $type for $page by checking if the + * relation is specified as a property of $page + * + * @param AbstractPage $page page to find relations for + * @param string $rel relation, 'rel' or 'rev' + * @param string $type link type, e.g. 'start', 'next' + * @return AbstractPage|array|null + */ + protected function findFromProperty(AbstractPage $page, $rel, $type) + { + $method = 'get' . ucfirst($rel); + $result = $page->$method($type); + if ($result) { + $result = $this->convertToPages($result); + if ($result) { + if (!is_array($result)) { + $result = array($result); + } + + foreach ($result as $key => $page) { + if (!$this->accept($page)) { + unset($result[$key]); + } + } + + return count($result) == 1 ? $result[0] : $result; + } + } + + return null; + } + + /** + * Finds relations of given $rel=$type for $page by using the helper to + * search for the relation in the root container + * + * @param AbstractPage $page page to find relations for + * @param string $rel relation, 'rel' or 'rev' + * @param string $type link type, e.g. 'start', 'next', etc + * @return array|null + */ + protected function findFromSearch(AbstractPage $page, $rel, $type) + { + $found = null; + + $method = 'search' . ucfirst($rel) . ucfirst($type); + if (method_exists($this, $method)) { + $found = $this->$method($page); + } + + return $found; + } + + // Search methods: + + /** + * Searches the root container for the forward 'start' relation of the given + * $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to the first document in a collection of documents. This link type + * tells search engines which document is considered by the author to be the + * starting point of the collection. + * + * @param AbstractPage $page + * @return AbstractPage|null + */ + public function searchRelStart(AbstractPage $page) + { + $found = $this->findRoot($page); + if (!$found instanceof AbstractPage) { + $found->rewind(); + $found = $found->current(); + } + + if ($found === $page || !$this->accept($found)) { + $found = null; + } + + return $found; + } + + /** + * Searches the root container for the forward 'next' relation of the given + * $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to the next document in a linear sequence of documents. User + * agents may choose to preload the "next" document, to reduce the perceived + * load time. + * + * @param AbstractPage $page + * @return AbstractPage|null + */ + public function searchRelNext(AbstractPage $page) + { + $found = null; + $break = false; + $iterator = new RecursiveIteratorIterator($this->findRoot($page), + RecursiveIteratorIterator::SELF_FIRST); + foreach ($iterator as $intermediate) { + if ($intermediate === $page) { + // current page; break at next accepted page + $break = true; + continue; + } + + if ($break && $this->accept($intermediate)) { + $found = $intermediate; + break; + } + } + + return $found; + } + + /** + * Searches the root container for the forward 'prev' relation of the given + * $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to the previous document in an ordered series of documents. Some + * user agents also support the synonym "Previous". + * + * @param AbstractPage $page + * @return AbstractPage|null + */ + public function searchRelPrev(AbstractPage $page) + { + $found = null; + $prev = null; + $iterator = new RecursiveIteratorIterator( + $this->findRoot($page), + RecursiveIteratorIterator::SELF_FIRST); + foreach ($iterator as $intermediate) { + if (!$this->accept($intermediate)) { + continue; + } + if ($intermediate === $page) { + $found = $prev; + break; + } + + $prev = $intermediate; + } + + return $found; + } + + /** + * Searches the root container for forward 'chapter' relations of the given + * $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to a document serving as a chapter in a collection of documents. + * + * @param AbstractPage $page + * @return AbstractPage|array|null + */ + public function searchRelChapter(AbstractPage $page) + { + $found = array(); + + // find first level of pages + $root = $this->findRoot($page); + + // find start page(s) + $start = $this->findRelation($page, 'rel', 'start'); + if (!is_array($start)) { + $start = array($start); + } + + foreach ($root as $chapter) { + // exclude self and start page from chapters + if ($chapter !== $page && + !in_array($chapter, $start) && + $this->accept($chapter)) { + $found[] = $chapter; + } + } + + switch (count($found)) { + case 0: + return null; + case 1: + return $found[0]; + default: + return $found; + } + } + + /** + * Searches the root container for forward 'section' relations of the given + * $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to a document serving as a section in a collection of documents. + * + * @param AbstractPage $page + * @return AbstractPage|array|null + */ + public function searchRelSection(AbstractPage $page) + { + $found = array(); + + // check if given page has pages and is a chapter page + if ($page->hasPages() && $this->findRoot($page)->hasPage($page)) { + foreach ($page as $section) { + if ($this->accept($section)) { + $found[] = $section; + } + } + } + + switch (count($found)) { + case 0: + return null; + case 1: + return $found[0]; + default: + return $found; + } + } + + /** + * Searches the root container for forward 'subsection' relations of the + * given $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to a document serving as a subsection in a collection of + * documents. + * + * @param AbstractPage $page + * @return AbstractPage|array|null + */ + public function searchRelSubsection(AbstractPage $page) + { + $found = array(); + + if ($page->hasPages()) { + // given page has child pages, loop chapters + foreach ($this->findRoot($page) as $chapter) { + // is page a section? + if ($chapter->hasPage($page)) { + foreach ($page as $subsection) { + if ($this->accept($subsection)) { + $found[] = $subsection; + } + } + } + } + } + + switch (count($found)) { + case 0: + return null; + case 1: + return $found[0]; + default: + return $found; + } + } + + /** + * Searches the root container for the reverse 'section' relation of the + * given $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to a document serving as a section in a collection of documents. + * + * @param AbstractPage $page + * @return AbstractPage|null + */ + public function searchRevSection(AbstractPage $page) + { + $found = null; + $parent = $page->getParent(); + if ($parent) { + if ($parent instanceof AbstractPage && + $this->findRoot($page)->hasPage($parent)) { + $found = $parent; + } + } + + return $found; + } + + /** + * Searches the root container for the reverse 'section' relation of the + * given $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to a document serving as a subsection in a collection of + * documents. + * + * @param AbstractPage $page + * @return AbstractPage|null + */ + public function searchRevSubsection(AbstractPage $page) + { + $found = null; + $parent = $page->getParent(); + if ($parent) { + if ($parent instanceof AbstractPage) { + $root = $this->findRoot($page); + foreach ($root as $chapter) { + if ($chapter->hasPage($parent)) { + $found = $parent; + break; + } + } + } + } + + return $found; + } + + // Util methods: + + /** + * Returns the root container of the given page + * + * When rendering a container, the render method still store the given + * container as the root container, and unset it when done rendering. This + * makes sure finder methods will not traverse above the container given + * to the render method. + * + * @param AbstractPage $page + * @return AbstractContainer + */ + protected function findRoot(AbstractPage $page) + { + if ($this->root) { + return $this->root; + } + + $root = $page; + + while ($parent = $page->getParent()) { + $root = $parent; + if ($parent instanceof AbstractPage) { + $page = $parent; + } else { + break; + } + } + + return $root; + } + + /** + * Converts a $mixed value to an array of pages + * + * @param mixed $mixed mixed value to get page(s) from + * @param bool $recursive whether $value should be looped + * if it is an array or a config + * @return AbstractPage|array|null + */ + protected function convertToPages($mixed, $recursive = true) + { + if ($mixed instanceof AbstractPage) { + // value is a page instance; return directly + return $mixed; + } elseif ($mixed instanceof AbstractContainer) { + // value is a container; return pages in it + $pages = array(); + foreach ($mixed as $page) { + $pages[] = $page; + } + return $pages; + } elseif ($mixed instanceof Traversable) { + $mixed = ArrayUtils::iteratorToArray($mixed); + } elseif (is_string($mixed)) { + // value is a string; make a URI page + return AbstractPage::factory(array( + 'type' => 'uri', + 'uri' => $mixed + )); + } + + if (is_array($mixed) && !empty($mixed)) { + if ($recursive && is_numeric(key($mixed))) { + // first key is numeric; assume several pages + $pages = array(); + foreach ($mixed as $value) { + $value = $this->convertToPages($value, false); + if ($value) { + $pages[] = $value; + } + } + return $pages; + } else { + // pass array to factory directly + try { + $page = AbstractPage::factory($mixed); + return $page; + } catch (\Exception $e) { + } + } + } + + // nothing found + return null; + } + + /** + * Sets the helper's render flag + * + * The helper uses the bitwise '&' operator against the hex values of the + * render constants. This means that the flag can is "bitwised" value of + * the render constants. Examples: + * + * // render all links except glossary + * $flag = Links:RENDER_ALL ^ Links:RENDER_GLOSSARY; + * $helper->setRenderFlag($flag); + * + * // render only chapters and sections + * $flag = Links:RENDER_CHAPTER | Links:RENDER_SECTION; + * $helper->setRenderFlag($flag); + * + * // render only relations that are not native W3C relations + * $helper->setRenderFlag(Links:RENDER_CUSTOM); + * + * // render all relations (default) + * $helper->setRenderFlag(Links:RENDER_ALL); + * + * + * Note that custom relations can also be rendered directly using the + * {@link renderLink()} method. + * + * @param int $renderFlag + * @return Links + */ + public function setRenderFlag($renderFlag) + { + $this->renderFlag = (int) $renderFlag; + + return $this; + } + + /** + * Returns the helper's render flag + * + * @return int + */ + public function getRenderFlag() + { + return $this->renderFlag; + } +} diff --git a/library/Zend/View/Helper/Navigation/Listener/AclListener.php b/library/Zend/View/Helper/Navigation/Listener/AclListener.php new file mode 100755 index 000000000..5c8656084 --- /dev/null +++ b/library/Zend/View/Helper/Navigation/Listener/AclListener.php @@ -0,0 +1,55 @@ +getParams(); + $acl = $params['acl']; + $page = $params['page']; + $role = $params['role']; + + if (!$acl) { + return $accepted; + } + + $resource = $page->getResource(); + $privilege = $page->getPrivilege(); + + if ($resource || $privilege) { + $accepted = $acl->hasResource($resource) + && $acl->isAllowed($role, $resource, $privilege); + } + + return $accepted; + } +} diff --git a/library/Zend/View/Helper/Navigation/Menu.php b/library/Zend/View/Helper/Navigation/Menu.php new file mode 100755 index 000000000..29d719923 --- /dev/null +++ b/library/Zend/View/Helper/Navigation/Menu.php @@ -0,0 +1,765 @@ + element + * + * @var bool + */ + protected $addClassToListItem = false; + + /** + * Whether labels should be escaped + * + * @var bool + */ + protected $escapeLabels = true; + + /** + * Whether only active branch should be rendered + * + * @var bool + */ + protected $onlyActiveBranch = false; + + /** + * Partial view script to use for rendering menu + * + * @var string|array + */ + protected $partial = null; + + /** + * Whether parents should be rendered when only rendering active branch + * + * @var bool + */ + protected $renderParents = true; + + /** + * CSS class to use for the ul element + * + * @var string + */ + protected $ulClass = 'navigation'; + + /** + * CSS class to use for the active li element + * + * @var string + */ + protected $liActiveClass = 'active'; + + /** + * View helper entry point: + * Retrieves helper and optionally sets container to operate on + * + * @param AbstractContainer $container [optional] container to operate on + * @return self + */ + public function __invoke($container = null) + { + if (null !== $container) { + $this->setContainer($container); + } + + return $this; + } + + /** + * Renders menu + * + * Implements {@link HelperInterface::render()}. + * + * If a partial view is registered in the helper, the menu will be rendered + * using the given partial script. If no partial is registered, the menu + * will be rendered as an 'ul' element by the helper's internal method. + * + * @see renderPartial() + * @see renderMenu() + * + * @param AbstractContainer $container [optional] container to render. Default is + * to render the container registered in the helper. + * @return string + */ + public function render($container = null) + { + $partial = $this->getPartial(); + if ($partial) { + return $this->renderPartial($container, $partial); + } + + return $this->renderMenu($container); + } + + /** + * Renders the deepest active menu within [$minDepth, $maxDepth], (called + * from {@link renderMenu()}) + * + * @param AbstractContainer $container container to render + * @param string $ulClass CSS class for first UL + * @param string $indent initial indentation + * @param int|null $minDepth minimum depth + * @param int|null $maxDepth maximum depth + * @param bool $escapeLabels Whether or not to escape the labels + * @param bool $addClassToListItem Whether or not page class applied to
  • element + * @param string $liActiveClass CSS class for active LI + * @return string + */ + protected function renderDeepestMenu( + AbstractContainer $container, + $ulClass, + $indent, + $minDepth, + $maxDepth, + $escapeLabels, + $addClassToListItem, + $liActiveClass + ) { + if (!$active = $this->findActive($container, $minDepth - 1, $maxDepth)) { + return ''; + } + + // special case if active page is one below minDepth + if ($active['depth'] < $minDepth) { + if (!$active['page']->hasPages(!$this->renderInvisible)) { + return ''; + } + } elseif (!$active['page']->hasPages(!$this->renderInvisible)) { + // found pages has no children; render siblings + $active['page'] = $active['page']->getParent(); + } elseif (is_int($maxDepth) && $active['depth'] +1 > $maxDepth) { + // children are below max depth; render siblings + $active['page'] = $active['page']->getParent(); + } + + /* @var $escaper \Zend\View\Helper\EscapeHtmlAttr */ + $escaper = $this->view->plugin('escapeHtmlAttr'); + $ulClass = $ulClass ? ' class="' . $escaper($ulClass) . '"' : ''; + $html = $indent . '' . PHP_EOL; + + foreach ($active['page'] as $subPage) { + if (!$this->accept($subPage)) { + continue; + } + + // render li tag and page + $liClasses = array(); + // Is page active? + if ($subPage->isActive(true)) { + $liClasses[] = $liActiveClass; + } + // Add CSS class from page to
  • + if ($addClassToListItem && $subPage->getClass()) { + $liClasses[] = $subPage->getClass(); + } + $liClass = empty($liClasses) ? '' : ' class="' . $escaper(implode(' ', $liClasses)) . '"'; + + $html .= $indent . ' ' . PHP_EOL; + $html .= $indent . ' ' . $this->htmlify($subPage, $escapeLabels, $addClassToListItem) . PHP_EOL; + $html .= $indent . '
  • ' . PHP_EOL; + } + + $html .= $indent . ''; + + return $html; + } + + /** + * Renders helper + * + * Renders a HTML 'ul' for the given $container. If $container is not given, + * the container registered in the helper will be used. + * + * Available $options: + * + * + * @param AbstractContainer $container [optional] container to create menu from. + * Default is to use the container retrieved + * from {@link getContainer()}. + * @param array $options [optional] options for controlling rendering + * @return string + */ + public function renderMenu($container = null, array $options = array()) + { + $this->parseContainer($container); + if (null === $container) { + $container = $this->getContainer(); + } + + + $options = $this->normalizeOptions($options); + + if ($options['onlyActiveBranch'] && !$options['renderParents']) { + $html = $this->renderDeepestMenu($container, + $options['ulClass'], + $options['indent'], + $options['minDepth'], + $options['maxDepth'], + $options['escapeLabels'], + $options['addClassToListItem'], + $options['liActiveClass'] + ); + } else { + $html = $this->renderNormalMenu($container, + $options['ulClass'], + $options['indent'], + $options['minDepth'], + $options['maxDepth'], + $options['onlyActiveBranch'], + $options['escapeLabels'], + $options['addClassToListItem'], + $options['liActiveClass'] + ); + } + + return $html; + } + + /** + * Renders a normal menu (called from {@link renderMenu()}) + * + * @param AbstractContainer $container container to render + * @param string $ulClass CSS class for first UL + * @param string $indent initial indentation + * @param int|null $minDepth minimum depth + * @param int|null $maxDepth maximum depth + * @param bool $onlyActive render only active branch? + * @param bool $escapeLabels Whether or not to escape the labels + * @param bool $addClassToListItem Whether or not page class applied to
  • element + * @param string $liActiveClass CSS class for active LI + * @return string + */ + protected function renderNormalMenu( + AbstractContainer $container, + $ulClass, + $indent, + $minDepth, + $maxDepth, + $onlyActive, + $escapeLabels, + $addClassToListItem, + $liActiveClass + ) { + $html = ''; + + // find deepest active + $found = $this->findActive($container, $minDepth, $maxDepth); + /* @var $escaper \Zend\View\Helper\EscapeHtmlAttr */ + $escaper = $this->view->plugin('escapeHtmlAttr'); + + if ($found) { + $foundPage = $found['page']; + $foundDepth = $found['depth']; + } else { + $foundPage = null; + } + + // create iterator + $iterator = new RecursiveIteratorIterator($container, + RecursiveIteratorIterator::SELF_FIRST); + if (is_int($maxDepth)) { + $iterator->setMaxDepth($maxDepth); + } + + // iterate container + $prevDepth = -1; + foreach ($iterator as $page) { + $depth = $iterator->getDepth(); + $isActive = $page->isActive(true); + if ($depth < $minDepth || !$this->accept($page)) { + // page is below minDepth or not accepted by acl/visibility + continue; + } elseif ($onlyActive && !$isActive) { + // page is not active itself, but might be in the active branch + $accept = false; + if ($foundPage) { + if ($foundPage->hasPage($page)) { + // accept if page is a direct child of the active page + $accept = true; + } elseif ($foundPage->getParent()->hasPage($page)) { + // page is a sibling of the active page... + if (!$foundPage->hasPages(!$this->renderInvisible) || + is_int($maxDepth) && $foundDepth + 1 > $maxDepth) { + // accept if active page has no children, or the + // children are too deep to be rendered + $accept = true; + } + } + } + + if (!$accept) { + continue; + } + } + + // make sure indentation is correct + $depth -= $minDepth; + $myIndent = $indent . str_repeat(' ', $depth); + + if ($depth > $prevDepth) { + // start new ul tag + if ($ulClass && $depth == 0) { + $ulClass = ' class="' . $escaper($ulClass) . '"'; + } else { + $ulClass = ''; + } + $html .= $myIndent . '' . PHP_EOL; + } elseif ($prevDepth > $depth) { + // close li/ul tags until we're at current depth + for ($i = $prevDepth; $i > $depth; $i--) { + $ind = $indent . str_repeat(' ', $i); + $html .= $ind . '
  • ' . PHP_EOL; + $html .= $ind . '' . PHP_EOL; + } + // close previous li tag + $html .= $myIndent . ' ' . PHP_EOL; + } else { + // close previous li tag + $html .= $myIndent . ' ' . PHP_EOL; + } + + // render li tag and page + $liClasses = array(); + // Is page active? + if ($isActive) { + $liClasses[] = $liActiveClass; + } + // Add CSS class from page to
  • + if ($addClassToListItem && $page->getClass()) { + $liClasses[] = $page->getClass(); + } + $liClass = empty($liClasses) ? '' : ' class="' . $escaper(implode(' ', $liClasses)) . '"'; + + $html .= $myIndent . ' ' . PHP_EOL + . $myIndent . ' ' . $this->htmlify($page, $escapeLabels, $addClassToListItem) . PHP_EOL; + + // store as previous depth for next iteration + $prevDepth = $depth; + } + + if ($html) { + // done iterating container; close open ul/li tags + for ($i = $prevDepth+1; $i > 0; $i--) { + $myIndent = $indent . str_repeat(' ', $i-1); + $html .= $myIndent . '
  • ' . PHP_EOL + . $myIndent . '' . PHP_EOL; + } + $html = rtrim($html, PHP_EOL); + } + + return $html; + } + + /** + * Renders the given $container by invoking the partial view helper + * + * The container will simply be passed on as a model to the view script + * as-is, and will be available in the partial script as 'container', e.g. + * echo 'Number of pages: ', count($this->container);. + * + * @param AbstractContainer $container [optional] container to pass to view + * script. Default is to use the container + * registered in the helper. + * @param string|array $partial [optional] partial view script to use. + * Default is to use the partial + * registered in the helper. If an array + * is given, it is expected to contain two + * values; the partial view script to use, + * and the module where the script can be + * found. + * @return string + * @throws Exception\RuntimeException if no partial provided + * @throws Exception\InvalidArgumentException if partial is invalid array + */ + public function renderPartial($container = null, $partial = null) + { + $this->parseContainer($container); + if (null === $container) { + $container = $this->getContainer(); + } + + if (null === $partial) { + $partial = $this->getPartial(); + } + + if (empty($partial)) { + throw new Exception\RuntimeException( + 'Unable to render menu: No partial view script provided' + ); + } + + $model = array( + 'container' => $container + ); + + /** @var \Zend\View\Helper\Partial $partialHelper */ + $partialHelper = $this->view->plugin('partial'); + + if (is_array($partial)) { + if (count($partial) != 2) { + throw new Exception\InvalidArgumentException( + 'Unable to render menu: A view partial supplied as ' + . 'an array must contain two values: partial view ' + . 'script and module where script can be found' + ); + } + + return $partialHelper($partial[0], $model); + } + + return $partialHelper($partial, $model); + } + + /** + * Renders the inner-most sub menu for the active page in the $container + * + * This is a convenience method which is equivalent to the following call: + * + * renderMenu($container, array( + * 'indent' => $indent, + * 'ulClass' => $ulClass, + * 'minDepth' => null, + * 'maxDepth' => null, + * 'onlyActiveBranch' => true, + * 'renderParents' => false, + * 'liActiveClass' => $liActiveClass + * )); + * + * + * @param AbstractContainer $container [optional] container to + * render. Default is to render + * the container registered in + * the helper. + * @param string $ulClass [optional] CSS class to + * use for UL element. Default + * is to use the value from + * {@link getUlClass()}. + * @param string|int $indent [optional] indentation as + * a string or number of + * spaces. Default is to use + * the value retrieved from + * {@link getIndent()}. + * @param string $liActiveClass [optional] CSS class to + * use for UL element. Default + * is to use the value from + * {@link getUlClass()}. + * @return string + */ + public function renderSubMenu( + AbstractContainer $container = null, + $ulClass = null, + $indent = null, + $liActiveClass = null + ) { + return $this->renderMenu($container, array( + 'indent' => $indent, + 'ulClass' => $ulClass, + 'minDepth' => null, + 'maxDepth' => null, + 'onlyActiveBranch' => true, + 'renderParents' => false, + 'escapeLabels' => true, + 'addClassToListItem' => false, + 'liActiveClass' => $liActiveClass + )); + } + + /** + * Returns an HTML string containing an 'a' element for the given page if + * the page's href is not empty, and a 'span' element if it is empty + * + * Overrides {@link AbstractHelper::htmlify()}. + * + * @param AbstractPage $page page to generate HTML for + * @param bool $escapeLabel Whether or not to escape the label + * @param bool $addClassToListItem Whether or not to add the page class to the list item + * @return string + */ + public function htmlify(AbstractPage $page, $escapeLabel = true, $addClassToListItem = false) + { + // get attribs for element + $attribs = array( + 'id' => $page->getId(), + 'title' => $this->translate($page->getTitle(), $page->getTextDomain()), + ); + + if ($addClassToListItem === false) { + $attribs['class'] = $page->getClass(); + } + + // does page have a href? + $href = $page->getHref(); + if ($href) { + $element = 'a'; + $attribs['href'] = $href; + $attribs['target'] = $page->getTarget(); + } else { + $element = 'span'; + } + + $html = '<' . $element . $this->htmlAttribs($attribs) . '>'; + $label = $this->translate($page->getLabel(), $page->getTextDomain()); + if ($escapeLabel === true) { + /** @var \Zend\View\Helper\EscapeHtml $escaper */ + $escaper = $this->view->plugin('escapeHtml'); + $html .= $escaper($label); + } else { + $html .= $label; + } + $html .= ''; + + return $html; + } + + /** + * Normalizes given render options + * + * @param array $options [optional] options to normalize + * @return array + */ + protected function normalizeOptions(array $options = array()) + { + if (isset($options['indent'])) { + $options['indent'] = $this->getWhitespace($options['indent']); + } else { + $options['indent'] = $this->getIndent(); + } + + if (isset($options['ulClass']) && $options['ulClass'] !== null) { + $options['ulClass'] = (string) $options['ulClass']; + } else { + $options['ulClass'] = $this->getUlClass(); + } + + if (array_key_exists('minDepth', $options)) { + if (null !== $options['minDepth']) { + $options['minDepth'] = (int) $options['minDepth']; + } + } else { + $options['minDepth'] = $this->getMinDepth(); + } + + if ($options['minDepth'] < 0 || $options['minDepth'] === null) { + $options['minDepth'] = 0; + } + + if (array_key_exists('maxDepth', $options)) { + if (null !== $options['maxDepth']) { + $options['maxDepth'] = (int) $options['maxDepth']; + } + } else { + $options['maxDepth'] = $this->getMaxDepth(); + } + + if (!isset($options['onlyActiveBranch'])) { + $options['onlyActiveBranch'] = $this->getOnlyActiveBranch(); + } + + if (!isset($options['escapeLabels'])) { + $options['escapeLabels'] = $this->escapeLabels; + } + + if (!isset($options['renderParents'])) { + $options['renderParents'] = $this->getRenderParents(); + } + + if (!isset($options['addClassToListItem'])) { + $options['addClassToListItem'] = $this->getAddClassToListItem(); + } + + if (isset($options['liActiveClass']) && $options['liActiveClass'] !== null) { + $options['liActiveClass'] = (string) $options['liActiveClass']; + } else { + $options['liActiveClass'] = $this->getLiActiveClass(); + } + + return $options; + } + + /** + * Sets a flag indicating whether labels should be escaped + * + * @param bool $flag [optional] escape labels + * @return self + */ + public function escapeLabels($flag = true) + { + $this->escapeLabels = (bool) $flag; + return $this; + } + + /** + * Enables/disables page class applied to
  • element + * + * @param bool $flag [optional] page class applied to
  • element + * Default is true. + * @return self fluent interface, returns self + */ + public function setAddClassToListItem($flag = true) + { + $this->addClassToListItem = (bool) $flag; + return $this; + } + + /** + * Returns flag indicating whether page class should be applied to
  • element + * + * By default, this value is false. + * + * @return bool whether parents should be rendered + */ + public function getAddClassToListItem() + { + return $this->addClassToListItem; + } + + /** + * Sets a flag indicating whether only active branch should be rendered + * + * @param bool $flag [optional] render only active branch. + * @return self + */ + public function setOnlyActiveBranch($flag = true) + { + $this->onlyActiveBranch = (bool) $flag; + return $this; + } + + /** + * Returns a flag indicating whether only active branch should be rendered + * + * By default, this value is false, meaning the entire menu will be + * be rendered. + * + * @return bool + */ + public function getOnlyActiveBranch() + { + return $this->onlyActiveBranch; + } + + /** + * Sets which partial view script to use for rendering menu + * + * @param string|array $partial partial view script or null. If an array is + * given, it is expected to contain two + * values; the partial view script to use, + * and the module where the script can be + * found. + * @return self + */ + public function setPartial($partial) + { + if (null === $partial || is_string($partial) || is_array($partial)) { + $this->partial = $partial; + } + + return $this; + } + + /** + * Returns partial view script to use for rendering menu + * + * @return string|array|null + */ + public function getPartial() + { + return $this->partial; + } + + /** + * Enables/disables rendering of parents when only rendering active branch + * + * See {@link setOnlyActiveBranch()} for more information. + * + * @param bool $flag [optional] render parents when rendering active branch. + * @return self + */ + public function setRenderParents($flag = true) + { + $this->renderParents = (bool) $flag; + return $this; + } + + /** + * Returns flag indicating whether parents should be rendered when rendering + * only the active branch + * + * By default, this value is true. + * + * @return bool + */ + public function getRenderParents() + { + return $this->renderParents; + } + + /** + * Sets CSS class to use for the first 'ul' element when rendering + * + * @param string $ulClass CSS class to set + * @return self + */ + public function setUlClass($ulClass) + { + if (is_string($ulClass)) { + $this->ulClass = $ulClass; + } + + return $this; + } + + /** + * Returns CSS class to use for the first 'ul' element when rendering + * + * @return string + */ + public function getUlClass() + { + return $this->ulClass; + } + + /** + * Sets CSS class to use for the active 'li' element when rendering + * + * @param string $liActiveClass CSS class to set + * @return self + */ + public function setLiActiveClass($liActiveClass) + { + if (is_string($liActiveClass)) { + $this->liActiveClass = $liActiveClass; + } + + return $this; + } + + /** + * Returns CSS class to use for the active 'li' element when rendering + * + * @return string + */ + public function getLiActiveClass() + { + return $this->liActiveClass; + } +} diff --git a/library/Zend/View/Helper/Navigation/PluginManager.php b/library/Zend/View/Helper/Navigation/PluginManager.php new file mode 100755 index 000000000..8faf86eb3 --- /dev/null +++ b/library/Zend/View/Helper/Navigation/PluginManager.php @@ -0,0 +1,58 @@ + 'Zend\View\Helper\Navigation\Breadcrumbs', + 'links' => 'Zend\View\Helper\Navigation\Links', + 'menu' => 'Zend\View\Helper\Navigation\Menu', + 'sitemap' => 'Zend\View\Helper\Navigation\Sitemap', + ); + + /** + * Validate the plugin + * + * Checks that the helper loaded is an instance of AbstractHelper. + * + * @param mixed $plugin + * @return void + * @throws Exception\InvalidArgumentException if invalid + */ + public function validatePlugin($plugin) + { + if ($plugin instanceof AbstractHelper) { + // we're okay + return; + } + + throw new Exception\InvalidArgumentException(sprintf( + 'Plugin of type %s is invalid; must implement %s\AbstractHelper', + (is_object($plugin) ? get_class($plugin) : gettype($plugin)), + __NAMESPACE__ + )); + } +} diff --git a/library/Zend/View/Helper/Navigation/Sitemap.php b/library/Zend/View/Helper/Navigation/Sitemap.php new file mode 100755 index 000000000..2ba2b4a4b --- /dev/null +++ b/library/Zend/View/Helper/Navigation/Sitemap.php @@ -0,0 +1,441 @@ + tag + * + * @var string + */ + const SITEMAP_NS = 'http://www.sitemaps.org/schemas/sitemap/0.9'; + + /** + * Schema URL + * + * @var string + */ + const SITEMAP_XSD = 'http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd'; + + /** + * Whether XML output should be formatted + * + * @var bool + */ + protected $formatOutput = false; + + /** + * Server url + * + * @var string + */ + protected $serverUrl; + + /** + * List of urls in the sitemap + * + * @var array + */ + protected $urls = array(); + + /** + * Whether sitemap should be validated using Zend\Validate\Sitemap\* + * + * @var bool + */ + protected $useSitemapValidators = true; + + /** + * Whether sitemap should be schema validated when generated + * + * @var bool + */ + protected $useSchemaValidation = false; + + /** + * Whether the XML declaration should be included in XML output + * + * @var bool + */ + protected $useXmlDeclaration = true; + + /** + * Helper entry point + * + * @param string|AbstractContainer $container container to operate on + * @return Sitemap + */ + public function __invoke($container = null) + { + if (null !== $container) { + $this->setContainer($container); + } + + return $this; + } + + /** + * Renders helper + * + * Implements {@link HelperInterface::render()}. + * + * @param AbstractContainer $container [optional] container to render. Default is + * to render the container registered in the helper. + * @return string + */ + public function render($container = null) + { + $dom = $this->getDomSitemap($container); + $xml = $this->getUseXmlDeclaration() ? + $dom->saveXML() : + $dom->saveXML($dom->documentElement); + + return rtrim($xml, PHP_EOL); + } + + /** + * Returns a DOMDocument containing the Sitemap XML for the given container + * + * @param AbstractContainer $container [optional] container to get + * breadcrumbs from, defaults + * to what is registered in the + * helper + * @return DOMDocument DOM representation of the + * container + * @throws Exception\RuntimeException if schema validation is on + * and the sitemap is invalid + * according to the sitemap + * schema, or if sitemap + * validators are used and the + * loc element fails validation + */ + public function getDomSitemap(AbstractContainer $container = null) + { + // Reset the urls + $this->urls = array(); + + if (null === $container) { + $container = $this->getContainer(); + } + + // check if we should validate using our own validators + if ($this->getUseSitemapValidators()) { + // create validators + $locValidator = new \Zend\Validator\Sitemap\Loc(); + $lastmodValidator = new \Zend\Validator\Sitemap\Lastmod(); + $changefreqValidator = new \Zend\Validator\Sitemap\Changefreq(); + $priorityValidator = new \Zend\Validator\Sitemap\Priority(); + } + + // create document + $dom = new DOMDocument('1.0', 'UTF-8'); + $dom->formatOutput = $this->getFormatOutput(); + + // ...and urlset (root) element + $urlSet = $dom->createElementNS(self::SITEMAP_NS, 'urlset'); + $dom->appendChild($urlSet); + + // create iterator + $iterator = new RecursiveIteratorIterator($container, + RecursiveIteratorIterator::SELF_FIRST); + + $maxDepth = $this->getMaxDepth(); + if (is_int($maxDepth)) { + $iterator->setMaxDepth($maxDepth); + } + $minDepth = $this->getMinDepth(); + if (!is_int($minDepth) || $minDepth < 0) { + $minDepth = 0; + } + + // iterate container + foreach ($iterator as $page) { + if ($iterator->getDepth() < $minDepth || !$this->accept($page)) { + // page should not be included + continue; + } + + // get absolute url from page + if (!$url = $this->url($page)) { + // skip page if it has no url (rare case) + // or already is in the sitemap + continue; + } + + // create url node for this page + $urlNode = $dom->createElementNS(self::SITEMAP_NS, 'url'); + $urlSet->appendChild($urlNode); + + if ($this->getUseSitemapValidators() + && !$locValidator->isValid($url) + ) { + throw new Exception\RuntimeException(sprintf( + 'Encountered an invalid URL for Sitemap XML: "%s"', + $url + )); + } + + // put url in 'loc' element + $urlNode->appendChild($dom->createElementNS(self::SITEMAP_NS, + 'loc', $url)); + + // add 'lastmod' element if a valid lastmod is set in page + if (isset($page->lastmod)) { + $lastmod = strtotime((string) $page->lastmod); + + // prevent 1970-01-01... + if ($lastmod !== false) { + $lastmod = date('c', $lastmod); + } + + if (!$this->getUseSitemapValidators() || + $lastmodValidator->isValid($lastmod)) { + $urlNode->appendChild( + $dom->createElementNS(self::SITEMAP_NS, 'lastmod', + $lastmod) + ); + } + } + + // add 'changefreq' element if a valid changefreq is set in page + if (isset($page->changefreq)) { + $changefreq = $page->changefreq; + if (!$this->getUseSitemapValidators() || + $changefreqValidator->isValid($changefreq)) { + $urlNode->appendChild( + $dom->createElementNS(self::SITEMAP_NS, 'changefreq', + $changefreq) + ); + } + } + + // add 'priority' element if a valid priority is set in page + if (isset($page->priority)) { + $priority = $page->priority; + if (!$this->getUseSitemapValidators() || + $priorityValidator->isValid($priority)) { + $urlNode->appendChild( + $dom->createElementNS(self::SITEMAP_NS, 'priority', $priority) + ); + } + } + } + + // validate using schema if specified + if ($this->getUseSchemaValidation()) { + ErrorHandler::start(); + $test = $dom->schemaValidate(self::SITEMAP_XSD); + $error = ErrorHandler::stop(); + if (!$test) { + throw new Exception\RuntimeException(sprintf( + 'Sitemap is invalid according to XML Schema at "%s"', + self::SITEMAP_XSD + ), 0, $error); + } + } + + return $dom; + } + + /** + * Returns an escaped absolute URL for the given page + * + * @param AbstractPage $page + * @return string + */ + public function url(AbstractPage $page) + { + $href = $page->getHref(); + + if (!isset($href{0})) { + // no href + return ''; + } elseif ($href{0} == '/') { + // href is relative to root; use serverUrl helper + $url = $this->getServerUrl() . $href; + } elseif (preg_match('/^[a-z]+:/im', (string) $href)) { + // scheme is given in href; assume absolute URL already + $url = (string) $href; + } else { + // href is relative to current document; use url helpers + $basePathHelper = $this->getView()->plugin('basepath'); + $curDoc = $basePathHelper(); + $curDoc = ('/' == $curDoc) ? '' : trim($curDoc, '/'); + $url = rtrim($this->getServerUrl(), '/') . '/' + . $curDoc + . (empty($curDoc) ? '' : '/') . $href; + } + + if (! in_array($url, $this->urls)) { + $this->urls[] = $url; + return $this->xmlEscape($url); + } + + return null; + } + + /** + * Escapes string for XML usage + * + * @param string $string + * @return string + */ + protected function xmlEscape($string) + { + $escaper = $this->view->plugin('escapeHtml'); + return $escaper($string); + } + + /** + * Sets whether XML output should be formatted + * + * @param bool $formatOutput + * @return Sitemap + */ + public function setFormatOutput($formatOutput = true) + { + $this->formatOutput = (bool) $formatOutput; + return $this; + } + + /** + * Returns whether XML output should be formatted + * + * @return bool + */ + public function getFormatOutput() + { + return $this->formatOutput; + } + + /** + * Sets server url (scheme and host-related stuff without request URI) + * + * E.g. http://www.example.com + * + * @param string $serverUrl + * @return Sitemap + * @throws Exception\InvalidArgumentException + */ + public function setServerUrl($serverUrl) + { + $uri = Uri\UriFactory::factory($serverUrl); + $uri->setFragment(''); + $uri->setPath(''); + $uri->setQuery(''); + + if ($uri->isValid()) { + $this->serverUrl = $uri->toString(); + } else { + throw new Exception\InvalidArgumentException(sprintf( + 'Invalid server URL: "%s"', + $serverUrl + )); + } + + return $this; + } + + /** + * Returns server URL + * + * @return string + */ + public function getServerUrl() + { + if (!isset($this->serverUrl)) { + $serverUrlHelper = $this->getView()->plugin('serverUrl'); + $this->serverUrl = $serverUrlHelper(); + } + + return $this->serverUrl; + } + + /** + * Sets whether sitemap should be validated using Zend\Validate\Sitemap_* + * + * @param bool $useSitemapValidators + * @return Sitemap + */ + public function setUseSitemapValidators($useSitemapValidators) + { + $this->useSitemapValidators = (bool) $useSitemapValidators; + return $this; + } + + /** + * Returns whether sitemap should be validated using Zend\Validate\Sitemap_* + * + * @return bool + */ + public function getUseSitemapValidators() + { + return $this->useSitemapValidators; + } + + /** + * Sets whether sitemap should be schema validated when generated + * + * @param bool $schemaValidation + * @return Sitemap + */ + public function setUseSchemaValidation($schemaValidation) + { + $this->useSchemaValidation = (bool) $schemaValidation; + return $this; + } + + /** + * Returns true if sitemap should be schema validated when generated + * + * @return bool + */ + public function getUseSchemaValidation() + { + return $this->useSchemaValidation; + } + + /** + * Sets whether the XML declaration should be used in output + * + * @param bool $useXmlDecl + * @return Sitemap + */ + public function setUseXmlDeclaration($useXmlDecl) + { + $this->useXmlDeclaration = (bool) $useXmlDecl; + return $this; + } + + /** + * Returns whether the XML declaration should be used in output + * + * @return bool + */ + public function getUseXmlDeclaration() + { + return $this->useXmlDeclaration; + } +} diff --git a/library/Zend/View/Helper/PaginationControl.php b/library/Zend/View/Helper/PaginationControl.php new file mode 100755 index 000000000..9963fdd35 --- /dev/null +++ b/library/Zend/View/Helper/PaginationControl.php @@ -0,0 +1,131 @@ +paginator is set and, + * if so, uses that. Also, if no scrolling style or partial are specified, + * the defaults will be used (if set). + * + * @param Paginator\Paginator $paginator (Optional) + * @param string $scrollingStyle (Optional) Scrolling style + * @param string $partial (Optional) View partial + * @param array|string $params (Optional) params to pass to the partial + * @throws Exception\RuntimeException if no paginator or no view partial provided + * @throws Exception\InvalidArgumentException if partial is invalid array + * @return string + */ + public function __invoke(Paginator\Paginator $paginator = null, $scrollingStyle = null, $partial = null, $params = null) + { + if ($paginator === null) { + if (isset($this->view->paginator) and $this->view->paginator !== null and $this->view->paginator instanceof Paginator\Paginator) { + $paginator = $this->view->paginator; + } else { + throw new Exception\RuntimeException('No paginator instance provided or incorrect type'); + } + } + + if ($partial === null) { + if (static::$defaultViewPartial === null) { + throw new Exception\RuntimeException('No view partial provided and no default set'); + } + + $partial = static::$defaultViewPartial; + } + + if ($scrollingStyle === null) { + $scrollingStyle = static::$defaultScrollingStyle; + } + + $pages = get_object_vars($paginator->getPages($scrollingStyle)); + + if ($params !== null) { + $pages = array_merge($pages, (array) $params); + } + + if (is_array($partial)) { + if (count($partial) != 2) { + throw new Exception\InvalidArgumentException( + 'A view partial supplied as an array must contain two values: the filename and its module' + ); + } + + if ($partial[1] !== null) { + $partialHelper = $this->view->plugin('partial'); + return $partialHelper($partial[0], $pages); + } + + $partial = $partial[0]; + } + + $partialHelper = $this->view->plugin('partial'); + return $partialHelper($partial, $pages); + } + + /** + * Sets the default Scrolling Style + * + * @param string $style string 'all' | 'elastic' | 'sliding' | 'jumping' + */ + public static function setDefaultScrollingStyle($style) + { + static::$defaultScrollingStyle = $style; + } + + /** + * Gets the default scrolling style + * + * @return string + */ + public static function getDefaultScrollingStyle() + { + return static::$defaultScrollingStyle; + } + + /** + * Sets the default view partial. + * + * @param string|array $partial View partial + */ + public static function setDefaultViewPartial($partial) + { + static::$defaultViewPartial = $partial; + } + + /** + * Gets the default view partial + * + * @return string|array + */ + public static function getDefaultViewPartial() + { + return static::$defaultViewPartial; + } +} diff --git a/library/Zend/View/Helper/Partial.php b/library/Zend/View/Helper/Partial.php new file mode 100755 index 000000000..444f161b9 --- /dev/null +++ b/library/Zend/View/Helper/Partial.php @@ -0,0 +1,94 @@ +getView()->render($name); + } + + if (is_scalar($values)) { + $values = array(); + } elseif ($values instanceof ModelInterface) { + $values = $values->getVariables(); + } elseif (is_object($values)) { + if (null !== ($objectKey = $this->getObjectKey())) { + $values = array($objectKey => $values); + } elseif (method_exists($values, 'toArray')) { + $values = $values->toArray(); + } else { + $values = get_object_vars($values); + } + } + + return $this->getView()->render($name, $values); + } + + /** + * Set object key + * + * @param string $key + * @return Partial + */ + public function setObjectKey($key) + { + if (null === $key) { + $this->objectKey = null; + return $this; + } + + $this->objectKey = (string) $key; + + return $this; + } + + /** + * Retrieve object key + * + * The objectKey is the variable to which an object in the iterator will be + * assigned. + * + * @return null|string + */ + public function getObjectKey() + { + return $this->objectKey; + } +} diff --git a/library/Zend/View/Helper/PartialLoop.php b/library/Zend/View/Helper/PartialLoop.php new file mode 100755 index 000000000..f66297e67 --- /dev/null +++ b/library/Zend/View/Helper/PartialLoop.php @@ -0,0 +1,77 @@ +toArray(); + } else { + throw new Exception\InvalidArgumentException('PartialLoop helper requires iterable data'); + } + } + + // reset the counter if it's called again + $this->partialCounter = 0; + $content = ''; + + foreach ($values as $item) { + $this->partialCounter++; + $content .= parent::__invoke($name, $item); + } + + return $content; + } + + /** + * Get the partial counter + * + * @return int + */ + public function getPartialCounter() + { + return $this->partialCounter; + } +} diff --git a/library/Zend/View/Helper/Placeholder.php b/library/Zend/View/Helper/Placeholder.php new file mode 100755 index 000000000..297c17a55 --- /dev/null +++ b/library/Zend/View/Helper/Placeholder.php @@ -0,0 +1,98 @@ +getContainer($name); + } + + /** + * createContainer + * + * @param string $key + * @param array $value + * @return Container\AbstractContainer + */ + public function createContainer($key, array $value = array()) + { + $key = (string) $key; + + $this->items[$key] = new $this->containerClass($value); + return $this->items[$key]; + } + + /** + * Retrieve a placeholder container + * + * @param string $key + * @return Container\AbstractContainer + */ + public function getContainer($key) + { + $key = (string) $key; + if (isset($this->items[$key])) { + return $this->items[$key]; + } + + $container = $this->createContainer($key); + + return $container; + } + + /** + * Does a particular container exist? + * + * @param string $key + * @return bool + */ + public function containerExists($key) + { + $key = (string) $key; + $return = array_key_exists($key, $this->items); + return $return; + } +} diff --git a/library/Zend/View/Helper/Placeholder/Container.php b/library/Zend/View/Helper/Placeholder/Container.php new file mode 100755 index 000000000..35220176c --- /dev/null +++ b/library/Zend/View/Helper/Placeholder/Container.php @@ -0,0 +1,17 @@ +toString(); + } + + /** + * Render the placeholder + * + * @param null|int|string $indent + * @return string + */ + public function toString($indent = null) + { + $indent = ($indent !== null) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + $items = $this->getArrayCopy(); + $return = $indent + . $this->getPrefix() + . implode($this->getSeparator(), $items) + . $this->getPostfix(); + $return = preg_replace("/(\r\n?|\n)/", '$1' . $indent, $return); + + return $return; + } + + /** + * Start capturing content to push into placeholder + * + * @param string $type How to capture content into placeholder; append, prepend, or set + * @param mixed $key Key to which to capture content + * @throws Exception\RuntimeException if nested captures detected + * @return void + */ + public function captureStart($type = AbstractContainer::APPEND, $key = null) + { + if ($this->captureLock) { + throw new Exception\RuntimeException( + 'Cannot nest placeholder captures for the same placeholder' + ); + } + + $this->captureLock = true; + $this->captureType = $type; + if ((null !== $key) && is_scalar($key)) { + $this->captureKey = (string) $key; + } + ob_start(); + } + + /** + * End content capture + * + * @return void + */ + public function captureEnd() + { + $data = ob_get_clean(); + $key = null; + $this->captureLock = false; + if (null !== $this->captureKey) { + $key = $this->captureKey; + } + switch ($this->captureType) { + case self::SET: + if (null !== $key) { + $this[$key] = $data; + } else { + $this->exchangeArray(array($data)); + } + break; + case self::PREPEND: + if (null !== $key) { + $array = array($key => $data); + $values = $this->getArrayCopy(); + $final = $array + $values; + $this->exchangeArray($final); + } else { + $this->prepend($data); + } + break; + case self::APPEND: + default: + if (null !== $key) { + if (empty($this[$key])) { + $this[$key] = $data; + } else { + $this[$key] .= $data; + } + } else { + $this[$this->nextIndex()] = $data; + } + break; + } + } + + /** + * Get keys + * + * @return array + */ + public function getKeys() + { + $array = $this->getArrayCopy(); + + return array_keys($array); + } + + /** + * Retrieve container value + * + * If single element registered, returns that element; otherwise, + * serializes to array. + * + * @return mixed + */ + public function getValue() + { + if (1 == count($this)) { + $keys = $this->getKeys(); + $key = array_shift($keys); + return $this[$key]; + } + + return $this->getArrayCopy(); + } + + /** + * Retrieve whitespace representation of $indent + * + * @param int|string $indent + * @return string + */ + public function getWhitespace($indent) + { + if (is_int($indent)) { + $indent = str_repeat(' ', $indent); + } + + return (string) $indent; + } + + /** + * Set a single value + * + * @param mixed $value + * @return void + */ + public function set($value) + { + $this->exchangeArray(array($value)); + + return $this; + } + + /** + * Prepend a value to the top of the container + * + * @param mixed $value + * @return self + */ + public function prepend($value) + { + $values = $this->getArrayCopy(); + array_unshift($values, $value); + $this->exchangeArray($values); + + return $this; + } + + /** + * Append a value to the end of the container + * + * @param mixed $value + * @return self + */ + public function append($value) + { + parent::append($value); + return $this; + } + + /** + * Next Index as defined by the PHP manual + * + * @return int + */ + public function nextIndex() + { + $keys = $this->getKeys(); + if (0 == count($keys)) { + return 0; + } + + return $nextIndex = max($keys) + 1; + } + + /** + * Set the indentation string for __toString() serialization, + * optionally, if a number is passed, it will be the number of spaces + * + * @param string|int $indent + * @return self + */ + public function setIndent($indent) + { + $this->indent = $this->getWhitespace($indent); + return $this; + } + + /** + * Retrieve indentation + * + * @return string + */ + public function getIndent() + { + return $this->indent; + } + + /** + * Set postfix for __toString() serialization + * + * @param string $postfix + * @return self + */ + public function setPostfix($postfix) + { + $this->postfix = (string) $postfix; + return $this; + } + + /** + * Retrieve postfix + * + * @return string + */ + public function getPostfix() + { + return $this->postfix; + } + + /** + * Set prefix for __toString() serialization + * + * @param string $prefix + * @return self + */ + public function setPrefix($prefix) + { + $this->prefix = (string) $prefix; + return $this; + } + + /** + * Retrieve prefix + * + * @return string + */ + public function getPrefix() + { + return $this->prefix; + } + + /** + * Set separator for __toString() serialization + * + * Used to implode elements in container + * + * @param string $separator + * @return self + */ + public function setSeparator($separator) + { + $this->separator = (string) $separator; + return $this; + } + + /** + * Retrieve separator + * + * @return string + */ + public function getSeparator() + { + return $this->separator; + } +} diff --git a/library/Zend/View/Helper/Placeholder/Container/AbstractStandalone.php b/library/Zend/View/Helper/Placeholder/Container/AbstractStandalone.php new file mode 100755 index 000000000..619ba7073 --- /dev/null +++ b/library/Zend/View/Helper/Placeholder/Container/AbstractStandalone.php @@ -0,0 +1,376 @@ +setContainer($this->getContainer()); + } + + /** + * Overload + * + * Proxy to container methods + * + * @param string $method + * @param array $args + * @throws Exception\BadMethodCallException + * @return mixed + */ + public function __call($method, $args) + { + $container = $this->getContainer(); + if (method_exists($container, $method)) { + $return = call_user_func_array(array($container, $method), $args); + if ($return === $container) { + // If the container is returned, we really want the current object + return $this; + } + return $return; + } + + throw new Exception\BadMethodCallException('Method "' . $method . '" does not exist'); + } + + /** + * Overloading: set property value + * + * @param string $key + * @param mixed $value + * @return void + */ + public function __set($key, $value) + { + $container = $this->getContainer(); + $container[$key] = $value; + } + + /** + * Overloading: retrieve property + * + * @param string $key + * @return mixed + */ + public function __get($key) + { + $container = $this->getContainer(); + if (isset($container[$key])) { + return $container[$key]; + } + + return null; + } + + /** + * Overloading: check if property is set + * + * @param string $key + * @return bool + */ + public function __isset($key) + { + $container = $this->getContainer(); + return isset($container[$key]); + } + + /** + * Overloading: unset property + * + * @param string $key + * @return void + */ + public function __unset($key) + { + $container = $this->getContainer(); + if (isset($container[$key])) { + unset($container[$key]); + } + } + + /** + * Cast to string representation + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * String representation + * + * @return string + */ + public function toString() + { + return $this->getContainer()->toString(); + } + + /** + * Escape a string + * + * @param string $string + * @return string + */ + protected function escape($string) + { + if ($this->getView() instanceof RendererInterface + && method_exists($this->getView(), 'getEncoding') + ) { + $escaper = $this->getView()->plugin('escapeHtml'); + return $escaper((string) $string); + } + + return $this->getEscaper()->escapeHtml((string) $string); + } + + /** + * Set whether or not auto escaping should be used + * + * @param bool $autoEscape whether or not to auto escape output + * @return AbstractStandalone + */ + public function setAutoEscape($autoEscape = true) + { + $this->autoEscape = ($autoEscape) ? true : false; + return $this; + } + + /** + * Return whether autoEscaping is enabled or disabled + * + * return bool + */ + public function getAutoEscape() + { + return $this->autoEscape; + } + + /** + * Set container on which to operate + * + * @param AbstractContainer $container + * @return AbstractStandalone + */ + public function setContainer(AbstractContainer $container) + { + $this->container = $container; + return $this; + } + + /** + * Retrieve placeholder container + * + * @return AbstractContainer + */ + public function getContainer() + { + if (!$this->container instanceof AbstractContainer) { + $this->container = new $this->containerClass(); + } + return $this->container; + } + + /** + * Delete a container + * + * @return bool + */ + public function deleteContainer() + { + if (null != $this->container) { + $this->container = null; + return true; + } + + return false; + } + + /** + * Set the container class to use + * + * @param string $name + * @throws Exception\InvalidArgumentException + * @throws Exception\DomainException + * @return \Zend\View\Helper\Placeholder\Container\AbstractStandalone + */ + public function setContainerClass($name) + { + if (!class_exists($name)) { + throw new Exception\DomainException( + sprintf( + '%s expects a valid container class name; received "%s", which did not resolve', + __METHOD__, + $name + ) + ); + } + + if (!in_array('Zend\View\Helper\Placeholder\Container\AbstractContainer', class_parents($name))) { + throw new Exception\InvalidArgumentException('Invalid Container class specified'); + } + + $this->containerClass = $name; + return $this; + } + + /** + * Retrieve the container class + * + * @return string + */ + public function getContainerClass() + { + return $this->containerClass; + } + + /** + * Set Escaper instance + * + * @param Escaper $escaper + * @return AbstractStandalone + */ + public function setEscaper(Escaper $escaper) + { + $encoding = $escaper->getEncoding(); + $this->escapers[$encoding] = $escaper; + + return $this; + } + + /** + * Get Escaper instance + * + * Lazy-loads one if none available + * + * @param string|null $enc Encoding to use + * @return mixed + */ + public function getEscaper($enc = 'UTF-8') + { + $enc = strtolower($enc); + if (!isset($this->escapers[$enc])) { + $this->setEscaper(new Escaper($enc)); + } + + return $this->escapers[$enc]; + } + + /** + * Countable + * + * @return int + */ + public function count() + { + $container = $this->getContainer(); + return count($container); + } + + /** + * ArrayAccess: offsetExists + * + * @param string|int $offset + * @return bool + */ + public function offsetExists($offset) + { + return $this->getContainer()->offsetExists($offset); + } + + /** + * ArrayAccess: offsetGet + * + * @param string|int $offset + * @return mixed + */ + public function offsetGet($offset) + { + return $this->getContainer()->offsetGet($offset); + } + + /** + * ArrayAccess: offsetSet + * + * @param string|int $offset + * @param mixed $value + * @return void + */ + public function offsetSet($offset, $value) + { + return $this->getContainer()->offsetSet($offset, $value); + } + + /** + * ArrayAccess: offsetUnset + * + * @param string|int $offset + * @return void + */ + public function offsetUnset($offset) + { + return $this->getContainer()->offsetUnset($offset); + } + + /** + * IteratorAggregate: get Iterator + * + * @return \Iterator + */ + public function getIterator() + { + return $this->getContainer()->getIterator(); + } +} diff --git a/library/Zend/View/Helper/Placeholder/Registry.php b/library/Zend/View/Helper/Placeholder/Registry.php new file mode 100755 index 000000000..f86b4e1ad --- /dev/null +++ b/library/Zend/View/Helper/Placeholder/Registry.php @@ -0,0 +1,185 @@ +items[$key] = $container; + + return $this; + } + + /** + * Retrieve a placeholder container + * + * @param string $key + * @return Container\AbstractContainer + */ + public function getContainer($key) + { + $key = (string) $key; + if (isset($this->items[$key])) { + return $this->items[$key]; + } + + $container = $this->createContainer($key); + + return $container; + } + + /** + * Does a particular container exist? + * + * @param string $key + * @return bool + */ + public function containerExists($key) + { + $key = (string) $key; + + return array_key_exists($key, $this->items); + } + + /** + * createContainer + * + * @param string $key + * @param array $value + * @return Container\AbstractContainer + */ + public function createContainer($key, array $value = array()) + { + $key = (string) $key; + + $this->items[$key] = new $this->containerClass($value); + + return $this->items[$key]; + } + + /** + * Delete a container + * + * @param string $key + * @return bool + */ + public function deleteContainer($key) + { + $key = (string) $key; + if (isset($this->items[$key])) { + unset($this->items[$key]); + return true; + } + + return false; + } + + /** + * Set the container class to use + * + * @param string $name + * @throws Exception\InvalidArgumentException + * @throws Exception\DomainException + * @return Registry + */ + public function setContainerClass($name) + { + if (!class_exists($name)) { + throw new Exception\DomainException( + sprintf( + '%s expects a valid registry class name; received "%s", which did not resolve', + __METHOD__, + $name + ) + ); + } + + if (!in_array('Zend\View\Helper\Placeholder\Container\AbstractContainer', class_parents($name))) { + throw new Exception\InvalidArgumentException('Invalid Container class specified'); + } + + $this->containerClass = $name; + + return $this; + } + + /** + * Retrieve the container class + * + * @return string + */ + public function getContainerClass() + { + return $this->containerClass; + } +} diff --git a/library/Zend/View/Helper/RenderChildModel.php b/library/Zend/View/Helper/RenderChildModel.php new file mode 100755 index 000000000..d59edfe05 --- /dev/null +++ b/library/Zend/View/Helper/RenderChildModel.php @@ -0,0 +1,133 @@ +render($child); + } + + /** + * Render a model + * + * If a matching child model is found, it is rendered. If not, an empty + * string is returned. + * + * @param string $child + * @return string + */ + public function render($child) + { + $model = $this->findChild($child); + if (!$model) { + return ''; + } + + $current = $this->current; + $view = $this->getView(); + $return = $view->render($model); + $helper = $this->getViewModelHelper(); + $helper->setCurrent($current); + + return $return; + } + + /** + * Find the named child model + * + * Iterates through the current view model, looking for a child model that + * has a captureTo value matching the requested $child. If found, that child + * model is returned; otherwise, a boolean false is returned. + * + * @param string $child + * @return false|Model + */ + protected function findChild($child) + { + $this->current = $model = $this->getCurrent(); + foreach ($model->getChildren() as $childModel) { + if ($childModel->captureTo() == $child) { + return $childModel; + } + } + + return false; + } + + /** + * Get the current view model + * + * @throws Exception\RuntimeException + * @return null|Model + */ + protected function getCurrent() + { + $helper = $this->getViewModelHelper(); + if (!$helper->hasCurrent()) { + throw new Exception\RuntimeException(sprintf( + '%s: no view model currently registered in renderer; cannot query for children', + __METHOD__ + )); + } + + return $helper->getCurrent(); + } + + /** + * Retrieve the view model helper + * + * @return ViewModel + */ + protected function getViewModelHelper() + { + if ($this->viewModelHelper) { + return $this->viewModelHelper; + } + + if (method_exists($this->getView(), 'plugin')) { + $this->viewModelHelper = $this->view->plugin('view_model'); + } + + return $this->viewModelHelper; + } +} diff --git a/library/Zend/View/Helper/RenderToPlaceholder.php b/library/Zend/View/Helper/RenderToPlaceholder.php new file mode 100755 index 000000000..3707995b3 --- /dev/null +++ b/library/Zend/View/Helper/RenderToPlaceholder.php @@ -0,0 +1,35 @@ +view->plugin('placeholder'); + $placeholderHelper($placeholder)->captureStart(); + echo $this->view->render($script); + $placeholderHelper($placeholder)->captureEnd(); + } +} diff --git a/library/Zend/View/Helper/ServerUrl.php b/library/Zend/View/Helper/ServerUrl.php new file mode 100755 index 000000000..ae846a9ba --- /dev/null +++ b/library/Zend/View/Helper/ServerUrl.php @@ -0,0 +1,330 @@ +getScheme() . '://' . $this->getHost() . $path; + } + + /** + * Detect the host based on headers + * + * @return void + */ + protected function detectHost() + { + if ($this->setHostFromProxy()) { + return; + } + + if (isset($_SERVER['HTTP_HOST']) && !empty($_SERVER['HTTP_HOST'])) { + // Detect if the port is set in SERVER_PORT and included in HTTP_HOST + if (isset($_SERVER['SERVER_PORT'])) { + $portStr = ':' . $_SERVER['SERVER_PORT']; + if (substr($_SERVER['HTTP_HOST'], 0-strlen($portStr), strlen($portStr)) == $portStr) { + $this->setHost(substr($_SERVER['HTTP_HOST'], 0, 0-strlen($portStr))); + return; + } + } + + $this->setHost($_SERVER['HTTP_HOST']); + + return; + } + + if (!isset($_SERVER['SERVER_NAME']) || !isset($_SERVER['SERVER_PORT'])) { + return; + } + + $name = $_SERVER['SERVER_NAME']; + $this->setHost($name); + } + + /** + * Detect the port + * + * @return null + */ + protected function detectPort() + { + if ($this->setPortFromProxy()) { + return; + } + + if (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT']) { + $this->setPort($_SERVER['SERVER_PORT']); + return; + } + } + + /** + * Detect the scheme + * + * @return null + */ + protected function detectScheme() + { + if ($this->setSchemeFromProxy()) { + return; + } + + switch (true) { + case (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] === true)): + case (isset($_SERVER['HTTP_SCHEME']) && ($_SERVER['HTTP_SCHEME'] == 'https')): + case (443 === $this->getPort()): + $scheme = 'https'; + break; + default: + $scheme = 'http'; + break; + } + + $this->setScheme($scheme); + } + + /** + * Detect if a proxy is in use, and, if so, set the host based on it + * + * @return bool + */ + protected function setHostFromProxy() + { + if (!$this->useProxy) { + return false; + } + + if (!isset($_SERVER['HTTP_X_FORWARDED_HOST']) || empty($_SERVER['HTTP_X_FORWARDED_HOST'])) { + return false; + } + + $host = $_SERVER['HTTP_X_FORWARDED_HOST']; + if (strpos($host, ',') !== false) { + $hosts = explode(',', $host); + $host = trim(array_pop($hosts)); + } + if (empty($host)) { + return false; + } + $this->setHost($host); + + return true; + } + + /** + * Set port based on detected proxy headers + * + * @return bool + */ + protected function setPortFromProxy() + { + if (!$this->useProxy) { + return false; + } + + if (!isset($_SERVER['HTTP_X_FORWARDED_PORT']) || empty($_SERVER['HTTP_X_FORWARDED_PORT'])) { + return false; + } + + $port = $_SERVER['HTTP_X_FORWARDED_PORT']; + $this->setPort($port); + + return true; + } + + /** + * Set the current scheme based on detected proxy headers + * + * @return bool + */ + protected function setSchemeFromProxy() + { + if (!$this->useProxy) { + return false; + } + + if (isset($_SERVER['SSL_HTTPS'])) { + $sslHttps = strtolower($_SERVER['SSL_HTTPS']); + if (in_array($sslHttps, array('on', 1))) { + $this->setScheme('https'); + return true; + } + } + + if (!isset($_SERVER['HTTP_X_FORWARDED_PROTO']) || empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) { + return false; + } + + $scheme = trim(strtolower($_SERVER['HTTP_X_FORWARDED_PROTO'])); + if (empty($scheme)) { + return false; + } + + $this->setScheme($scheme); + + return true; + } + + /** + * Sets host + * + * @param string $host + * @return ServerUrl + */ + public function setHost($host) + { + $port = $this->getPort(); + $scheme = $this->getScheme(); + + if (($scheme == 'http' && (null === $port || $port == 80)) + || ($scheme == 'https' && (null === $port || $port == 443)) + ) { + $this->host = $host; + return $this; + } + + $this->host = $host . ':' . $port; + + return $this; + } + + /** + * Returns host + * + * @return string + */ + public function getHost() + { + if (null === $this->host) { + $this->detectHost(); + } + + return $this->host; + } + + /** + * Set server port + * + * @param int $port + * @return ServerUrl + */ + public function setPort($port) + { + $this->port = (int) $port; + + return $this; + } + + /** + * Retrieve the server port + * + * @return int|null + */ + public function getPort() + { + if (null === $this->port) { + $this->detectPort(); + } + + return $this->port; + } + + /** + * Sets scheme (typically http or https) + * + * @param string $scheme + * @return ServerUrl + */ + public function setScheme($scheme) + { + $this->scheme = $scheme; + + return $this; + } + + /** + * Returns scheme (typically http or https) + * + * @return string + */ + public function getScheme() + { + if (null === $this->scheme) { + $this->detectScheme(); + } + + return $this->scheme; + } + + /** + * Set flag indicating whether or not to query proxy servers + * + * @param bool $useProxy + * @return ServerUrl + */ + public function setUseProxy($useProxy = false) + { + $this->useProxy = (bool) $useProxy; + + return $this; + } +} diff --git a/library/Zend/View/Helper/Service/FlashMessengerFactory.php b/library/Zend/View/Helper/Service/FlashMessengerFactory.php new file mode 100755 index 000000000..fbaf53e8b --- /dev/null +++ b/library/Zend/View/Helper/Service/FlashMessengerFactory.php @@ -0,0 +1,47 @@ +getServiceLocator(); + $helper = new FlashMessenger(); + $controllerPluginManager = $serviceLocator->get('ControllerPluginManager'); + $flashMessenger = $controllerPluginManager->get('flashmessenger'); + $helper->setPluginFlashMessenger($flashMessenger); + $config = $serviceLocator->get('Config'); + if (isset($config['view_helper_config']['flashmessenger'])) { + $configHelper = $config['view_helper_config']['flashmessenger']; + if (isset($configHelper['message_open_format'])) { + $helper->setMessageOpenFormat($configHelper['message_open_format']); + } + if (isset($configHelper['message_separator_string'])) { + $helper->setMessageSeparatorString($configHelper['message_separator_string']); + } + if (isset($configHelper['message_close_string'])) { + $helper->setMessageCloseString($configHelper['message_close_string']); + } + } + + return $helper; + } +} diff --git a/library/Zend/View/Helper/Service/IdentityFactory.php b/library/Zend/View/Helper/Service/IdentityFactory.php new file mode 100755 index 000000000..a065a1d9d --- /dev/null +++ b/library/Zend/View/Helper/Service/IdentityFactory.php @@ -0,0 +1,32 @@ +getServiceLocator(); + $helper = new Identity(); + if ($services->has('Zend\Authentication\AuthenticationService')) { + $helper->setAuthenticationService($services->get('Zend\Authentication\AuthenticationService')); + } + return $helper; + } +} diff --git a/library/Zend/View/Helper/Url.php b/library/Zend/View/Helper/Url.php new file mode 100755 index 000000000..9b2af7e97 --- /dev/null +++ b/library/Zend/View/Helper/Url.php @@ -0,0 +1,126 @@ +router) { + throw new Exception\RuntimeException('No RouteStackInterface instance provided'); + } + + if (3 == func_num_args() && is_bool($options)) { + $reuseMatchedParams = $options; + $options = array(); + } + + if ($name === null) { + if ($this->routeMatch === null) { + throw new Exception\RuntimeException('No RouteMatch instance provided'); + } + + $name = $this->routeMatch->getMatchedRouteName(); + + if ($name === null) { + throw new Exception\RuntimeException('RouteMatch does not contain a matched route name'); + } + } + + if (!is_array($params)) { + if (!$params instanceof Traversable) { + throw new Exception\InvalidArgumentException( + 'Params is expected to be an array or a Traversable object' + ); + } + $params = iterator_to_array($params); + } + + if ($reuseMatchedParams && $this->routeMatch !== null) { + $routeMatchParams = $this->routeMatch->getParams(); + + if (isset($routeMatchParams[ModuleRouteListener::ORIGINAL_CONTROLLER])) { + $routeMatchParams['controller'] = $routeMatchParams[ModuleRouteListener::ORIGINAL_CONTROLLER]; + unset($routeMatchParams[ModuleRouteListener::ORIGINAL_CONTROLLER]); + } + + if (isset($routeMatchParams[ModuleRouteListener::MODULE_NAMESPACE])) { + unset($routeMatchParams[ModuleRouteListener::MODULE_NAMESPACE]); + } + + $params = array_merge($routeMatchParams, $params); + } + + $options['name'] = $name; + + return $this->router->assemble($params, $options); + } + + /** + * Set the router to use for assembling. + * + * @param RouteStackInterface $router + * @return Url + */ + public function setRouter(RouteStackInterface $router) + { + $this->router = $router; + return $this; + } + + /** + * Set route match returned by the router. + * + * @param RouteMatch $routeMatch + * @return Url + */ + public function setRouteMatch(RouteMatch $routeMatch) + { + $this->routeMatch = $routeMatch; + return $this; + } +} diff --git a/library/Zend/View/Helper/ViewModel.php b/library/Zend/View/Helper/ViewModel.php new file mode 100755 index 000000000..49b130649 --- /dev/null +++ b/library/Zend/View/Helper/ViewModel.php @@ -0,0 +1,92 @@ +current = $model; + return $this; + } + + /** + * Get the current view model + * + * @return null|Model + */ + public function getCurrent() + { + return $this->current; + } + + /** + * Is a current view model composed? + * + * @return bool + */ + public function hasCurrent() + { + return ($this->current instanceof Model); + } + + /** + * Set the root view model + * + * @param Model $model + * @return ViewModel + */ + public function setRoot(Model $model) + { + $this->root = $model; + return $this; + } + + /** + * Get the root view model + * + * @return null|Model + */ + public function getRoot() + { + return $this->root; + } + + /** + * Is a root view model composed? + * + * @return bool + */ + public function hasRoot() + { + return ($this->root instanceof Model); + } +} diff --git a/library/Zend/View/HelperPluginManager.php b/library/Zend/View/HelperPluginManager.php new file mode 100755 index 000000000..d2ddc6904 --- /dev/null +++ b/library/Zend/View/HelperPluginManager.php @@ -0,0 +1,194 @@ + 'Zend\View\Helper\Service\FlashMessengerFactory', + 'identity' => 'Zend\View\Helper\Service\IdentityFactory', + ); + + /** + * Default set of helpers + * + * @var array + */ + protected $invokableClasses = array( + // basepath, doctype, and url are set up as factories in the ViewHelperManagerFactory. + // basepath and url are not very useful without their factories, however the doctype + // helper works fine as an invokable. The factory for doctype simply checks for the + // config value from the merged config. + 'basepath' => 'Zend\View\Helper\BasePath', + 'cycle' => 'Zend\View\Helper\Cycle', + 'declarevars' => 'Zend\View\Helper\DeclareVars', + 'doctype' => 'Zend\View\Helper\Doctype', // overridden by a factory in ViewHelperManagerFactory + 'escapehtml' => 'Zend\View\Helper\EscapeHtml', + 'escapehtmlattr' => 'Zend\View\Helper\EscapeHtmlAttr', + 'escapejs' => 'Zend\View\Helper\EscapeJs', + 'escapecss' => 'Zend\View\Helper\EscapeCss', + 'escapeurl' => 'Zend\View\Helper\EscapeUrl', + 'gravatar' => 'Zend\View\Helper\Gravatar', + 'headlink' => 'Zend\View\Helper\HeadLink', + 'headmeta' => 'Zend\View\Helper\HeadMeta', + 'headscript' => 'Zend\View\Helper\HeadScript', + 'headstyle' => 'Zend\View\Helper\HeadStyle', + 'headtitle' => 'Zend\View\Helper\HeadTitle', + 'htmlflash' => 'Zend\View\Helper\HtmlFlash', + 'htmllist' => 'Zend\View\Helper\HtmlList', + 'htmlobject' => 'Zend\View\Helper\HtmlObject', + 'htmlpage' => 'Zend\View\Helper\HtmlPage', + 'htmlquicktime' => 'Zend\View\Helper\HtmlQuicktime', + 'inlinescript' => 'Zend\View\Helper\InlineScript', + 'json' => 'Zend\View\Helper\Json', + 'layout' => 'Zend\View\Helper\Layout', + 'paginationcontrol' => 'Zend\View\Helper\PaginationControl', + 'partialloop' => 'Zend\View\Helper\PartialLoop', + 'partial' => 'Zend\View\Helper\Partial', + 'placeholder' => 'Zend\View\Helper\Placeholder', + 'renderchildmodel' => 'Zend\View\Helper\RenderChildModel', + 'rendertoplaceholder' => 'Zend\View\Helper\RenderToPlaceholder', + 'serverurl' => 'Zend\View\Helper\ServerUrl', + 'url' => 'Zend\View\Helper\Url', + 'viewmodel' => 'Zend\View\Helper\ViewModel', + ); + + /** + * @var Renderer\RendererInterface + */ + protected $renderer; + + /** + * Constructor + * + * After invoking parent constructor, add an initializer to inject the + * attached renderer and translator, if any, to the currently requested helper. + * + * @param null|ConfigInterface $configuration + */ + public function __construct(ConfigInterface $configuration = null) + { + parent::__construct($configuration); + + $this->addInitializer(array($this, 'injectRenderer')) + ->addInitializer(array($this, 'injectTranslator')); + } + + /** + * Set renderer + * + * @param Renderer\RendererInterface $renderer + * @return HelperPluginManager + */ + public function setRenderer(Renderer\RendererInterface $renderer) + { + $this->renderer = $renderer; + + return $this; + } + + /** + * Retrieve renderer instance + * + * @return null|Renderer\RendererInterface + */ + public function getRenderer() + { + return $this->renderer; + } + + /** + * Inject a helper instance with the registered renderer + * + * @param Helper\HelperInterface $helper + * @return void + */ + public function injectRenderer($helper) + { + $renderer = $this->getRenderer(); + if (null === $renderer) { + return; + } + $helper->setView($renderer); + } + + /** + * Inject a helper instance with the registered translator + * + * @param Helper\HelperInterface $helper + * @return void + */ + public function injectTranslator($helper) + { + if (!$helper instanceof TranslatorAwareInterface) { + return; + } + + $locator = $this->getServiceLocator(); + + if (!$locator) { + return; + } + + if ($locator->has('MvcTranslator')) { + $helper->setTranslator($locator->get('MvcTranslator')); + return; + } + + if ($locator->has('Zend\I18n\Translator\TranslatorInterface')) { + $helper->setTranslator($locator->get('Zend\I18n\Translator\TranslatorInterface')); + return; + } + + if ($locator->has('Translator')) { + $helper->setTranslator($locator->get('Translator')); + return; + } + } + + /** + * Validate the plugin + * + * Checks that the helper loaded is an instance of Helper\HelperInterface. + * + * @param mixed $plugin + * @return void + * @throws Exception\InvalidHelperException if invalid + */ + public function validatePlugin($plugin) + { + if ($plugin instanceof Helper\HelperInterface) { + // we're okay + return; + } + + throw new Exception\InvalidHelperException(sprintf( + 'Plugin of type %s is invalid; must implement %s\Helper\HelperInterface', + (is_object($plugin) ? get_class($plugin) : gettype($plugin)), + __NAMESPACE__ + )); + } +} diff --git a/library/Zend/View/Model/ClearableModelInterface.php b/library/Zend/View/Model/ClearableModelInterface.php new file mode 100755 index 000000000..2edfe719e --- /dev/null +++ b/library/Zend/View/Model/ClearableModelInterface.php @@ -0,0 +1,23 @@ +options['errorLevel'] = $errorLevel; + } + + /** + * @return int + */ + public function getErrorLevel() + { + if (array_key_exists('errorLevel', $this->options)) { + return $this->options['errorLevel']; + } + } + + /** + * Set result text. + * + * @param string $text + * @return \Zend\View\Model\ConsoleModel + */ + public function setResult($text) + { + $this->setVariable(self::RESULT, $text); + return $this; + } + + /** + * Get result text. + * + * @return mixed + */ + public function getResult() + { + return $this->getVariable(self::RESULT); + } +} diff --git a/library/Zend/View/Model/FeedModel.php b/library/Zend/View/Model/FeedModel.php new file mode 100755 index 000000000..fc8351cd0 --- /dev/null +++ b/library/Zend/View/Model/FeedModel.php @@ -0,0 +1,89 @@ +feed instanceof Feed) { + return $this->feed; + } + + if (!$this->type) { + $options = $this->getOptions(); + if (isset($options['feed_type'])) { + $this->type = $options['feed_type']; + } + } + + $variables = $this->getVariables(); + $feed = FeedFactory::factory($variables); + $this->setFeed($feed); + + return $this->feed; + } + + /** + * Set the feed object + * + * @param Feed $feed + * @return FeedModel + */ + public function setFeed(Feed $feed) + { + $this->feed = $feed; + return $this; + } + + /** + * Get the feed type + * + * @return false|string + */ + public function getFeedType() + { + if ($this->type) { + return $this->type; + } + + $options = $this->getOptions(); + if (isset($options['feed_type'])) { + $this->type = $options['feed_type']; + } + return $this->type; + } +} diff --git a/library/Zend/View/Model/JsonModel.php b/library/Zend/View/Model/JsonModel.php new file mode 100755 index 000000000..191d3f5ec --- /dev/null +++ b/library/Zend/View/Model/JsonModel.php @@ -0,0 +1,69 @@ +jsonpCallback = $callback; + return $this; + } + + /** + * Serialize to JSON + * + * @return string + */ + public function serialize() + { + $variables = $this->getVariables(); + if ($variables instanceof Traversable) { + $variables = ArrayUtils::iteratorToArray($variables); + } + + if (null !== $this->jsonpCallback) { + return $this->jsonpCallback.'('.Json::encode($variables).');'; + } + return Json::encode($variables); + } +} diff --git a/library/Zend/View/Model/ModelInterface.php b/library/Zend/View/Model/ModelInterface.php new file mode 100755 index 000000000..810540d70 --- /dev/null +++ b/library/Zend/View/Model/ModelInterface.php @@ -0,0 +1,167 @@ +setVariables($variables, true); + + if (null !== $options) { + $this->setOptions($options); + } + } + + /** + * Property overloading: set variable value + * + * @param string $name + * @param mixed $value + * @return void + */ + public function __set($name, $value) + { + $this->setVariable($name, $value); + } + + /** + * Property overloading: get variable value + * + * @param string $name + * @return mixed + */ + public function __get($name) + { + if (!$this->__isset($name)) { + return null; + } + + $variables = $this->getVariables(); + return $variables[$name]; + } + + /** + * Property overloading: do we have the requested variable value? + * + * @param string $name + * @return bool + */ + public function __isset($name) + { + $variables = $this->getVariables(); + return isset($variables[$name]); + } + + /** + * Property overloading: unset the requested variable + * + * @param string $name + * @return void + */ + public function __unset($name) + { + if (!$this->__isset($name)) { + return null; + } + + unset($this->variables[$name]); + } + + /** + * Set a single option + * + * @param string $name + * @param mixed $value + * @return ViewModel + */ + public function setOption($name, $value) + { + $this->options[(string) $name] = $value; + return $this; + } + + /** + * Get a single option + * + * @param string $name The option to get. + * @param mixed|null $default (optional) A default value if the option is not yet set. + * @return mixed + */ + public function getOption($name, $default = null) + { + $name = (string) $name; + return array_key_exists($name, $this->options) ? $this->options[$name] : $default; + } + + /** + * Set renderer options/hints en masse + * + * @param array|Traversable $options + * @throws \Zend\View\Exception\InvalidArgumentException + * @return ViewModel + */ + public function setOptions($options) + { + // Assumption is that lowest common denominator for renderer configuration + // is an array + if ($options instanceof Traversable) { + $options = ArrayUtils::iteratorToArray($options); + } + + if (!is_array($options)) { + throw new Exception\InvalidArgumentException(sprintf( + '%s: expects an array, or Traversable argument; received "%s"', + __METHOD__, + (is_object($options) ? get_class($options) : gettype($options)) + )); + } + + $this->options = $options; + return $this; + } + + /** + * Get renderer options/hints + * + * @return array + */ + public function getOptions() + { + return $this->options; + } + + /** + * Clear any existing renderer options/hints + * + * @return ViewModel + */ + public function clearOptions() + { + $this->options = array(); + return $this; + } + + /** + * Get a single view variable + * + * @param string $name + * @param mixed|null $default (optional) default value if the variable is not present. + * @return mixed + */ + public function getVariable($name, $default = null) + { + $name = (string) $name; + if (array_key_exists($name, $this->variables)) { + return $this->variables[$name]; + } + + return $default; + } + + /** + * Set view variable + * + * @param string $name + * @param mixed $value + * @return ViewModel + */ + public function setVariable($name, $value) + { + $this->variables[(string) $name] = $value; + return $this; + } + + /** + * Set view variables en masse + * + * Can be an array or a Traversable + ArrayAccess object. + * + * @param array|ArrayAccess|Traversable $variables + * @param bool $overwrite Whether or not to overwrite the internal container with $variables + * @throws Exception\InvalidArgumentException + * @return ViewModel + */ + public function setVariables($variables, $overwrite = false) + { + if (!is_array($variables) && !$variables instanceof Traversable) { + throw new Exception\InvalidArgumentException(sprintf( + '%s: expects an array, or Traversable argument; received "%s"', + __METHOD__, + (is_object($variables) ? get_class($variables) : gettype($variables)) + )); + } + + if ($overwrite) { + if (is_object($variables) && !$variables instanceof ArrayAccess) { + $variables = ArrayUtils::iteratorToArray($variables); + } + + $this->variables = $variables; + return $this; + } + + foreach ($variables as $key => $value) { + $this->setVariable($key, $value); + } + + return $this; + } + + /** + * Get view variables + * + * @return array|ArrayAccess|Traversable + */ + public function getVariables() + { + return $this->variables; + } + + /** + * Clear all variables + * + * Resets the internal variable container to an empty container. + * + * @return ViewModel + */ + public function clearVariables() + { + $this->variables = new ViewVariables(); + return $this; + } + + /** + * Set the template to be used by this model + * + * @param string $template + * @return ViewModel + */ + public function setTemplate($template) + { + $this->template = (string) $template; + return $this; + } + + /** + * Get the template to be used by this model + * + * @return string + */ + public function getTemplate() + { + return $this->template; + } + + /** + * Add a child model + * + * @param ModelInterface $child + * @param null|string $captureTo Optional; if specified, the "capture to" value to set on the child + * @param null|bool $append Optional; if specified, append to child with the same capture + * @return ViewModel + */ + public function addChild(ModelInterface $child, $captureTo = null, $append = null) + { + $this->children[] = $child; + if (null !== $captureTo) { + $child->setCaptureTo($captureTo); + } + if (null !== $append) { + $child->setAppend($append); + } + + return $this; + } + + /** + * Return all children. + * + * Return specifies an array, but may be any iterable object. + * + * @return array + */ + public function getChildren() + { + return $this->children; + } + + /** + * Does the model have any children? + * + * @return bool + */ + public function hasChildren() + { + return (0 < count($this->children)); + } + + /** + * Clears out all child models + * + * @return ViewModel + */ + public function clearChildren() + { + $this->children = array(); + return $this; + } + + /** + * Returns an array of Viewmodels with captureTo value $capture + * + * @param string $capture + * @param bool $recursive search recursive through children, default true + * @return array + */ + public function getChildrenByCaptureTo($capture, $recursive = true) + { + $children = array(); + + foreach ($this->children as $child) { + if ($recursive === true) { + $children += $child->getChildrenByCaptureTo($capture); + } + + if ($child->captureTo() === $capture) { + $children[] = $child; + } + } + + return $children; + } + + /** + * Set the name of the variable to capture this model to, if it is a child model + * + * @param string $capture + * @return ViewModel + */ + public function setCaptureTo($capture) + { + $this->captureTo = (string) $capture; + return $this; + } + + /** + * Get the name of the variable to which to capture this model + * + * @return string + */ + public function captureTo() + { + return $this->captureTo; + } + + /** + * Set flag indicating whether or not this is considered a terminal or standalone model + * + * @param bool $terminate + * @return ViewModel + */ + public function setTerminal($terminate) + { + $this->terminate = (bool) $terminate; + return $this; + } + + /** + * Is this considered a terminal or standalone model? + * + * @return bool + */ + public function terminate() + { + return $this->terminate; + } + + /** + * Set flag indicating whether or not append to child with the same capture + * + * @param bool $append + * @return ViewModel + */ + public function setAppend($append) + { + $this->append = (bool) $append; + return $this; + } + + /** + * Is this append to child with the same capture? + * + * @return bool + */ + public function isAppend() + { + return $this->append; + } + + /** + * Return count of children + * + * @return int + */ + public function count() + { + return count($this->children); + } + + /** + * Get iterator of children + * + * @return ArrayIterator + */ + public function getIterator() + { + return new ArrayIterator($this->children); + } +} diff --git a/library/Zend/View/README.md b/library/Zend/View/README.md new file mode 100755 index 000000000..ec19b2c01 --- /dev/null +++ b/library/Zend/View/README.md @@ -0,0 +1,15 @@ +View Component from ZF2 +======================= + +This is the View component for ZF2. + +- File issues at https://github.com/zendframework/zf2/issues +- Create pull requests against https://github.com/zendframework/zf2 +- Documentation is at http://framework.zend.com/docs + +LICENSE +------- + +The files in this archive are released under the [Zend Framework +license](http://framework.zend.com/license), which is a 3-clause BSD license. + diff --git a/library/Zend/View/Renderer/ConsoleRenderer.php b/library/Zend/View/Renderer/ConsoleRenderer.php new file mode 100755 index 000000000..5f0cf10b2 --- /dev/null +++ b/library/Zend/View/Renderer/ConsoleRenderer.php @@ -0,0 +1,149 @@ +init(); + } + + public function setResolver(ResolverInterface $resolver) + { + return $this; + } + + /** + * Return the template engine object + * + * Returns the object instance, as it is its own template engine + * + * @return PhpRenderer + */ + public function getEngine() + { + return $this; + } + + /** + * Allow custom object initialization when extending ConsoleRenderer + * + * Triggered by {@link __construct() the constructor} as its final action. + * + * @return void + */ + public function init() + { + } + + /** + * Set filter chain + * + * @param FilterChain $filters + * @return ConsoleRenderer + */ + public function setFilterChain(FilterChain $filters) + { + $this->__filterChain = $filters; + return $this; + } + + /** + * Retrieve filter chain for post-filtering script content + * + * @return FilterChain + */ + public function getFilterChain() + { + if (null === $this->__filterChain) { + $this->setFilterChain(new FilterChain()); + } + return $this->__filterChain; + } + + /** + * Recursively processes all ViewModels and returns output. + * + * @param string|ModelInterface $model A ViewModel instance. + * @param null|array|\Traversable $values Values to use when rendering. If none + * provided, uses those in the composed + * variables container. + * @return string Console output. + */ + public function render($model, $values = null) + { + if (!$model instanceof ModelInterface) { + return ''; + } + + $result = ''; + $options = $model->getOptions(); + foreach ($options as $setting => $value) { + $method = 'set' . $setting; + if (method_exists($this, $method)) { + $this->$method($value); + } + unset($method, $setting, $value); + } + unset($options); + + $values = $model->getVariables(); + + if (isset($values['result'])) { + // filter and append the result + $result .= $this->getFilterChain()->filter($values['result']); + } + + if ($model->hasChildren()) { + // recursively render all children + foreach ($model->getChildren() as $child) { + $result .= $this->render($child, $values); + } + } + + return $result; + } + + /** + * @see Zend\View\Renderer\TreeRendererInterface + * @return bool + */ + public function canRenderTrees() + { + return true; + } +} diff --git a/library/Zend/View/Renderer/FeedRenderer.php b/library/Zend/View/Renderer/FeedRenderer.php new file mode 100755 index 000000000..b91964683 --- /dev/null +++ b/library/Zend/View/Renderer/FeedRenderer.php @@ -0,0 +1,138 @@ +resolver = $resolver; + } + + /** + * Renders values as JSON + * + * @todo Determine what use case exists for accepting only $nameOrModel + * @param string|Model $nameOrModel The script/resource process, or a view model + * @param null|array|\ArrayAccess $values Values to use during rendering + * @throws Exception\InvalidArgumentException + * @return string The script output. + */ + public function render($nameOrModel, $values = null) + { + if ($nameOrModel instanceof Model) { + // Use case 1: View Model provided + // Non-FeedModel: cast to FeedModel + if (!$nameOrModel instanceof FeedModel) { + $vars = $nameOrModel->getVariables(); + $options = $nameOrModel->getOptions(); + $type = $this->getFeedType(); + if (isset($options['feed_type'])) { + $type = $options['feed_type']; + } else { + $this->setFeedType($type); + } + $nameOrModel = new FeedModel($vars, array('feed_type' => $type)); + } + } elseif (is_string($nameOrModel)) { + // Use case 2: string $nameOrModel + array|Traversable|Feed $values + $nameOrModel = new FeedModel($values, (array) $nameOrModel); + } else { + // Use case 3: failure + throw new Exception\InvalidArgumentException(sprintf( + '%s expects a ViewModel or a string feed type as the first argument; received "%s"', + __METHOD__, + (is_object($nameOrModel) ? get_class($nameOrModel) : gettype($nameOrModel)) + )); + } + + // Get feed and type + $feed = $nameOrModel->getFeed(); + $type = $nameOrModel->getFeedType(); + if (!$type) { + $type = $this->getFeedType(); + } else { + $this->setFeedType($type); + } + + // Render feed + return $feed->export($type); + } + + /** + * Set feed type ('rss' or 'atom') + * + * @param string $feedType + * @throws Exception\InvalidArgumentException + * @return FeedRenderer + */ + public function setFeedType($feedType) + { + $feedType = strtolower($feedType); + if (!in_array($feedType, array('rss', 'atom'))) { + throw new Exception\InvalidArgumentException(sprintf( + '%s expects a string of either "rss" or "atom"', + __METHOD__ + )); + } + + $this->feedType = $feedType; + return $this; + } + + /** + * Get feed type + * + * @return string + */ + public function getFeedType() + { + return $this->feedType; + } +} diff --git a/library/Zend/View/Renderer/JsonRenderer.php b/library/Zend/View/Renderer/JsonRenderer.php new file mode 100755 index 000000000..9666261db --- /dev/null +++ b/library/Zend/View/Renderer/JsonRenderer.php @@ -0,0 +1,243 @@ +resolver = $resolver; + } + + /** + * Set flag indicating whether or not to merge unnamed children + * + * @param bool $mergeUnnamedChildren + * @return JsonRenderer + */ + public function setMergeUnnamedChildren($mergeUnnamedChildren) + { + $this->mergeUnnamedChildren = (bool) $mergeUnnamedChildren; + return $this; + } + + /** + * Set the JSONP callback function name + * + * @param string $callback + * @return JsonRenderer + */ + public function setJsonpCallback($callback) + { + $callback = (string) $callback; + if (!empty($callback)) { + $this->jsonpCallback = $callback; + } + return $this; + } + + /** + * Returns whether or not the jsonpCallback has been set + * + * @return bool + */ + public function hasJsonpCallback() + { + return (null !== $this->jsonpCallback); + } + + /** + * Should we merge unnamed children? + * + * @return bool + */ + public function mergeUnnamedChildren() + { + return $this->mergeUnnamedChildren; + } + + /** + * Renders values as JSON + * + * @todo Determine what use case exists for accepting both $nameOrModel and $values + * @param string|Model $nameOrModel The script/resource process, or a view model + * @param null|array|\ArrayAccess $values Values to use during rendering + * @throws Exception\DomainException + * @return string The script output. + */ + public function render($nameOrModel, $values = null) + { + // use case 1: View Models + // Serialize variables in view model + if ($nameOrModel instanceof Model) { + if ($nameOrModel instanceof JsonModel) { + $children = $this->recurseModel($nameOrModel, false); + $this->injectChildren($nameOrModel, $children); + $values = $nameOrModel->serialize(); + } else { + $values = $this->recurseModel($nameOrModel); + $values = Json::encode($values); + } + + if ($this->hasJsonpCallback()) { + $values = $this->jsonpCallback . '(' . $values . ');'; + } + return $values; + } + + // use case 2: $nameOrModel is populated, $values is not + // Serialize $nameOrModel + if (null === $values) { + if (!is_object($nameOrModel) || $nameOrModel instanceof JsonSerializable) { + $return = Json::encode($nameOrModel); + } elseif ($nameOrModel instanceof Traversable) { + $nameOrModel = ArrayUtils::iteratorToArray($nameOrModel); + $return = Json::encode($nameOrModel); + } else { + $return = Json::encode(get_object_vars($nameOrModel)); + } + + if ($this->hasJsonpCallback()) { + $return = $this->jsonpCallback . '(' . $return . ');'; + } + return $return; + } + + // use case 3: Both $nameOrModel and $values are populated + throw new Exception\DomainException(sprintf( + '%s: Do not know how to handle operation when both $nameOrModel and $values are populated', + __METHOD__ + )); + } + + /** + * Can this renderer render trees of view models? + * + * Yes. + * + * @return true + */ + public function canRenderTrees() + { + return true; + } + + /** + * Retrieve values from a model and recurse its children to build a data structure + * + * @param Model $model + * @param bool $mergeWithVariables Whether or not to merge children with + * the variables of the $model + * @return array + */ + protected function recurseModel(Model $model, $mergeWithVariables = true) + { + $values = array(); + if ($mergeWithVariables) { + $values = $model->getVariables(); + } + + if ($values instanceof Traversable) { + $values = ArrayUtils::iteratorToArray($values); + } + + if (!$model->hasChildren()) { + return $values; + } + + $mergeChildren = $this->mergeUnnamedChildren(); + foreach ($model as $child) { + $captureTo = $child->captureTo(); + if (!$captureTo && !$mergeChildren) { + // We don't want to do anything with this child + continue; + } + + $childValues = $this->recurseModel($child); + if ($captureTo) { + // Capturing to a specific key + // TODO please complete if append is true. must change old + // value to array and append to array? + $values[$captureTo] = $childValues; + } elseif ($mergeChildren) { + // Merging values with parent + $values = array_replace_recursive($values, $childValues); + } + } + return $values; + } + + /** + * Inject discovered child model values into parent model + * + * @todo detect collisions and decide whether to append and/or aggregate? + * @param Model $model + * @param array $children + */ + protected function injectChildren(Model $model, array $children) + { + foreach ($children as $child => $value) { + // TODO detect collisions and decide whether to append and/or aggregate? + $model->setVariable($child, $value); + } + } +} diff --git a/library/Zend/View/Renderer/PhpRenderer.php b/library/Zend/View/Renderer/PhpRenderer.php new file mode 100755 index 000000000..87baf3d98 --- /dev/null +++ b/library/Zend/View/Renderer/PhpRenderer.php @@ -0,0 +1,574 @@ +init(); + } + + /** + * Return the template engine object + * + * Returns the object instance, as it is its own template engine + * + * @return PhpRenderer + */ + public function getEngine() + { + return $this; + } + + /** + * Allow custom object initialization when extending PhpRenderer + * + * Triggered by {@link __construct() the constructor} as its final action. + * + * @return void + */ + public function init() + { + } + + /** + * Set script resolver + * + * @param Resolver $resolver + * @return PhpRenderer + * @throws Exception\InvalidArgumentException + */ + public function setResolver(Resolver $resolver) + { + $this->__templateResolver = $resolver; + return $this; + } + + /** + * Retrieve template name or template resolver + * + * @param null|string $name + * @return string|Resolver + */ + public function resolver($name = null) + { + if (null === $this->__templateResolver) { + $this->setResolver(new TemplatePathStack()); + } + + if (null !== $name) { + return $this->__templateResolver->resolve($name, $this); + } + + return $this->__templateResolver; + } + + /** + * Set variable storage + * + * Expects either an array, or an object implementing ArrayAccess. + * + * @param array|ArrayAccess $variables + * @return PhpRenderer + * @throws Exception\InvalidArgumentException + */ + public function setVars($variables) + { + if (!is_array($variables) && !$variables instanceof ArrayAccess) { + throw new Exception\InvalidArgumentException(sprintf( + 'Expected array or ArrayAccess object; received "%s"', + (is_object($variables) ? get_class($variables) : gettype($variables)) + )); + } + + // Enforce a Variables container + if (!$variables instanceof Variables) { + $variablesAsArray = array(); + foreach ($variables as $key => $value) { + $variablesAsArray[$key] = $value; + } + $variables = new Variables($variablesAsArray); + } + + $this->__vars = $variables; + return $this; + } + + /** + * Get a single variable, or all variables + * + * @param mixed $key + * @return mixed + */ + public function vars($key = null) + { + if (null === $this->__vars) { + $this->setVars(new Variables()); + } + + if (null === $key) { + return $this->__vars; + } + return $this->__vars[$key]; + } + + /** + * Get a single variable + * + * @param mixed $key + * @return mixed + */ + public function get($key) + { + if (null === $this->__vars) { + $this->setVars(new Variables()); + } + + return $this->__vars[$key]; + } + + /** + * Overloading: proxy to Variables container + * + * @param string $name + * @return mixed + */ + public function __get($name) + { + $vars = $this->vars(); + return $vars[$name]; + } + + /** + * Overloading: proxy to Variables container + * + * @param string $name + * @param mixed $value + * @return void + */ + public function __set($name, $value) + { + $vars = $this->vars(); + $vars[$name] = $value; + } + + /** + * Overloading: proxy to Variables container + * + * @param string $name + * @return bool + */ + public function __isset($name) + { + $vars = $this->vars(); + return isset($vars[$name]); + } + + /** + * Overloading: proxy to Variables container + * + * @param string $name + * @return void + */ + public function __unset($name) + { + $vars = $this->vars(); + if (!isset($vars[$name])) { + return; + } + unset($vars[$name]); + } + + /** + * Set helper plugin manager instance + * + * @param string|HelperPluginManager $helpers + * @return PhpRenderer + * @throws Exception\InvalidArgumentException + */ + public function setHelperPluginManager($helpers) + { + if (is_string($helpers)) { + if (!class_exists($helpers)) { + throw new Exception\InvalidArgumentException(sprintf( + 'Invalid helper helpers class provided (%s)', + $helpers + )); + } + $helpers = new $helpers(); + } + if (!$helpers instanceof HelperPluginManager) { + throw new Exception\InvalidArgumentException(sprintf( + 'Helper helpers must extend Zend\View\HelperPluginManager; got type "%s" instead', + (is_object($helpers) ? get_class($helpers) : gettype($helpers)) + )); + } + $helpers->setRenderer($this); + $this->__helpers = $helpers; + + return $this; + } + + /** + * Get helper plugin manager instance + * + * @return HelperPluginManager + */ + public function getHelperPluginManager() + { + if (null === $this->__helpers) { + $this->setHelperPluginManager(new HelperPluginManager()); + } + return $this->__helpers; + } + + /** + * Get plugin instance + * + * @param string $name Name of plugin to return + * @param null|array $options Options to pass to plugin constructor (if not already instantiated) + * @return AbstractHelper + */ + public function plugin($name, array $options = null) + { + return $this->getHelperPluginManager()->get($name, $options); + } + + /** + * Overloading: proxy to helpers + * + * Proxies to the attached plugin manager to retrieve, return, and potentially + * execute helpers. + * + * * If the helper does not define __invoke, it will be returned + * * If the helper does define __invoke, it will be called as a functor + * + * @param string $method + * @param array $argv + * @return mixed + */ + public function __call($method, $argv) + { + if (!isset($this->__pluginCache[$method])) { + $this->__pluginCache[$method] = $this->plugin($method); + } + if (is_callable($this->__pluginCache[$method])) { + return call_user_func_array($this->__pluginCache[$method], $argv); + } + return $this->__pluginCache[$method]; + } + + /** + * Set filter chain + * + * @param FilterChain $filters + * @return PhpRenderer + */ + public function setFilterChain(FilterChain $filters) + { + $this->__filterChain = $filters; + return $this; + } + + /** + * Retrieve filter chain for post-filtering script content + * + * @return FilterChain + */ + public function getFilterChain() + { + if (null === $this->__filterChain) { + $this->setFilterChain(new FilterChain()); + } + return $this->__filterChain; + } + + /** + * Processes a view script and returns the output. + * + * @param string|Model $nameOrModel Either the template to use, or a + * ViewModel. The ViewModel must have the + * template as an option in order to be + * valid. + * @param null|array|Traversable $values Values to use when rendering. If none + * provided, uses those in the composed + * variables container. + * @return string The script output. + * @throws Exception\DomainException if a ViewModel is passed, but does not + * contain a template option. + * @throws Exception\InvalidArgumentException if the values passed are not + * an array or ArrayAccess object + * @throws Exception\RuntimeException if the template cannot be rendered + */ + public function render($nameOrModel, $values = null) + { + if ($nameOrModel instanceof Model) { + $model = $nameOrModel; + $nameOrModel = $model->getTemplate(); + if (empty($nameOrModel)) { + throw new Exception\DomainException(sprintf( + '%s: received View Model argument, but template is empty', + __METHOD__ + )); + } + $options = $model->getOptions(); + foreach ($options as $setting => $value) { + $method = 'set' . $setting; + if (method_exists($this, $method)) { + $this->$method($value); + } + unset($method, $setting, $value); + } + unset($options); + + // Give view model awareness via ViewModel helper + $helper = $this->plugin('view_model'); + $helper->setCurrent($model); + + $values = $model->getVariables(); + unset($model); + } + + // find the script file name using the parent private method + $this->addTemplate($nameOrModel); + unset($nameOrModel); // remove $name from local scope + + $this->__varsCache[] = $this->vars(); + + if (null !== $values) { + $this->setVars($values); + } + unset($values); + + // extract all assigned vars (pre-escaped), but not 'this'. + // assigns to a double-underscored variable, to prevent naming collisions + $__vars = $this->vars()->getArrayCopy(); + if (array_key_exists('this', $__vars)) { + unset($__vars['this']); + } + extract($__vars); + unset($__vars); // remove $__vars from local scope + + while ($this->__template = array_pop($this->__templates)) { + $this->__file = $this->resolver($this->__template); + if (!$this->__file) { + throw new Exception\RuntimeException(sprintf( + '%s: Unable to render template "%s"; resolver could not resolve to a file', + __METHOD__, + $this->__template + )); + } + try { + ob_start(); + $includeReturn = include $this->__file; + $this->__content = ob_get_clean(); + } catch (\Exception $ex) { + ob_end_clean(); + throw $ex; + } + if ($includeReturn === false && empty($this->__content)) { + throw new Exception\UnexpectedValueException(sprintf( + '%s: Unable to render template "%s"; file include failed', + __METHOD__, + $this->__file + )); + } + } + + $this->setVars(array_pop($this->__varsCache)); + + return $this->getFilterChain()->filter($this->__content); // filter output + } + + /** + * Set flag indicating whether or not we should render trees of view models + * + * If set to true, the View instance will not attempt to render children + * separately, but instead pass the root view model directly to the PhpRenderer. + * It is then up to the developer to render the children from within the + * view script. + * + * @param bool $renderTrees + * @return PhpRenderer + */ + public function setCanRenderTrees($renderTrees) + { + $this->__renderTrees = (bool) $renderTrees; + return $this; + } + + /** + * Can we render trees, or are we configured to do so? + * + * @return bool + */ + public function canRenderTrees() + { + return $this->__renderTrees; + } + + /** + * Add a template to the stack + * + * @param string $template + * @return PhpRenderer + */ + public function addTemplate($template) + { + $this->__templates[] = $template; + return $this; + } + + /** + * Make sure View variables are cloned when the view is cloned. + * + * @return PhpRenderer + */ + public function __clone() + { + $this->__vars = clone $this->vars(); + } +} diff --git a/library/Zend/View/Renderer/RendererInterface.php b/library/Zend/View/Renderer/RendererInterface.php new file mode 100755 index 000000000..d3dfa77f7 --- /dev/null +++ b/library/Zend/View/Renderer/RendererInterface.php @@ -0,0 +1,47 @@ +queue = new PriorityQueue(); + } + + /** + * Return count of attached resolvers + * + * @return int + */ + public function count() + { + return $this->queue->count(); + } + + /** + * IteratorAggregate: return internal iterator + * + * @return PriorityQueue + */ + public function getIterator() + { + return $this->queue; + } + + /** + * Attach a resolver + * + * @param Resolver $resolver + * @param int $priority + * @return AggregateResolver + */ + public function attach(Resolver $resolver, $priority = 1) + { + $this->queue->insert($resolver, $priority); + return $this; + } + + /** + * Resolve a template/pattern name to a resource the renderer can consume + * + * @param string $name + * @param null|Renderer $renderer + * @return false|string + */ + public function resolve($name, Renderer $renderer = null) + { + $this->lastLookupFailure = false; + $this->lastSuccessfulResolver = null; + + if (0 === count($this->queue)) { + $this->lastLookupFailure = static::FAILURE_NO_RESOLVERS; + return false; + } + + foreach ($this->queue as $resolver) { + $resource = $resolver->resolve($name, $renderer); + if (!$resource) { + // No resource found; try next resolver + continue; + } + + // Resource found; return it + $this->lastSuccessfulResolver = $resolver; + return $resource; + } + + $this->lastLookupFailure = static::FAILURE_NOT_FOUND; + return false; + } + + /** + * Return the last successful resolver, if any + * + * @return Resolver + */ + public function getLastSuccessfulResolver() + { + return $this->lastSuccessfulResolver; + } + + /** + * Get last lookup failure + * + * @return false|string + */ + public function getLastLookupFailure() + { + return $this->lastLookupFailure; + } +} diff --git a/library/Zend/View/Resolver/ResolverInterface.php b/library/Zend/View/Resolver/ResolverInterface.php new file mode 100755 index 000000000..8ffe130c6 --- /dev/null +++ b/library/Zend/View/Resolver/ResolverInterface.php @@ -0,0 +1,24 @@ +setMap($map); + } + + /** + * IteratorAggregate: return internal iterator + * + * @return Traversable + */ + public function getIterator() + { + return new ArrayIterator($this->map); + } + + /** + * Set (overwrite) template map + * + * Maps should be arrays or Traversable objects with name => path pairs + * + * @param array|Traversable $map + * @throws Exception\InvalidArgumentException + * @return TemplateMapResolver + */ + public function setMap($map) + { + if (!is_array($map) && !$map instanceof Traversable) { + throw new Exception\InvalidArgumentException(sprintf( + '%s: expects an array or Traversable, received "%s"', + __METHOD__, + (is_object($map) ? get_class($map) : gettype($map)) + )); + } + + if ($map instanceof Traversable) { + $map = ArrayUtils::iteratorToArray($map); + } + + $this->map = $map; + return $this; + } + + /** + * Add an entry to the map + * + * @param string|array|Traversable $nameOrMap + * @param null|string $path + * @throws Exception\InvalidArgumentException + * @return TemplateMapResolver + */ + public function add($nameOrMap, $path = null) + { + if (is_array($nameOrMap) || $nameOrMap instanceof Traversable) { + $this->merge($nameOrMap); + return $this; + } + + if (!is_string($nameOrMap)) { + throw new Exception\InvalidArgumentException(sprintf( + '%s: expects a string, array, or Traversable for the first argument; received "%s"', + __METHOD__, + (is_object($nameOrMap) ? get_class($nameOrMap) : gettype($nameOrMap)) + )); + } + + if (empty($path)) { + if (isset($this->map[$nameOrMap])) { + unset($this->map[$nameOrMap]); + } + return $this; + } + + $this->map[$nameOrMap] = $path; + return $this; + } + + /** + * Merge internal map with provided map + * + * @param array|Traversable $map + * @throws Exception\InvalidArgumentException + * @return TemplateMapResolver + */ + public function merge($map) + { + if (!is_array($map) && !$map instanceof Traversable) { + throw new Exception\InvalidArgumentException(sprintf( + '%s: expects an array or Traversable, received "%s"', + __METHOD__, + (is_object($map) ? get_class($map) : gettype($map)) + )); + } + + if ($map instanceof Traversable) { + $map = ArrayUtils::iteratorToArray($map); + } + + $this->map = array_replace_recursive($this->map, $map); + return $this; + } + + /** + * Does the resolver contain an entry for the given name? + * + * @param string $name + * @return bool + */ + public function has($name) + { + return array_key_exists($name, $this->map); + } + + /** + * Retrieve a template path by name + * + * @param string $name + * @return false|string + * @throws Exception\DomainException if no entry exists + */ + public function get($name) + { + if (!$this->has($name)) { + return false; + } + return $this->map[$name]; + } + + /** + * Retrieve the template map + * + * @return array + */ + public function getMap() + { + return $this->map; + } + + /** + * Resolve a template/pattern name to a resource the renderer can consume + * + * @param string $name + * @param null|Renderer $renderer + * @return string + */ + public function resolve($name, Renderer $renderer = null) + { + return $this->get($name); + } +} diff --git a/library/Zend/View/Resolver/TemplatePathStack.php b/library/Zend/View/Resolver/TemplatePathStack.php new file mode 100755 index 000000000..359be18f3 --- /dev/null +++ b/library/Zend/View/Resolver/TemplatePathStack.php @@ -0,0 +1,338 @@ +useViewStream = (bool) ini_get('short_open_tag'); + if ($this->useViewStream) { + if (!in_array('zend.view', stream_get_wrappers())) { + stream_wrapper_register('zend.view', 'Zend\View\Stream'); + } + } + + $this->paths = new SplStack; + if (null !== $options) { + $this->setOptions($options); + } + } + + /** + * Configure object + * + * @param array|Traversable $options + * @return void + * @throws Exception\InvalidArgumentException + */ + public function setOptions($options) + { + if (!is_array($options) && !$options instanceof Traversable) { + throw new Exception\InvalidArgumentException(sprintf( + 'Expected array or Traversable object; received "%s"', + (is_object($options) ? get_class($options) : gettype($options)) + )); + } + + foreach ($options as $key => $value) { + switch (strtolower($key)) { + case 'lfi_protection': + $this->setLfiProtection($value); + break; + case 'script_paths': + $this->addPaths($value); + break; + case 'use_stream_wrapper': + $this->setUseStreamWrapper($value); + break; + case 'default_suffix': + $this->setDefaultSuffix($value); + break; + default: + break; + } + } + } + + /** + * Set default file suffix + * + * @param string $defaultSuffix + * @return TemplatePathStack + */ + public function setDefaultSuffix($defaultSuffix) + { + $this->defaultSuffix = (string) $defaultSuffix; + $this->defaultSuffix = ltrim($this->defaultSuffix, '.'); + return $this; + } + + /** + * Get default file suffix + * + * @return string + */ + public function getDefaultSuffix() + { + return $this->defaultSuffix; + } + + /** + * Add many paths to the stack at once + * + * @param array $paths + * @return TemplatePathStack + */ + public function addPaths(array $paths) + { + foreach ($paths as $path) { + $this->addPath($path); + } + return $this; + } + + /** + * Rest the path stack to the paths provided + * + * @param SplStack|array $paths + * @return TemplatePathStack + * @throws Exception\InvalidArgumentException + */ + public function setPaths($paths) + { + if ($paths instanceof SplStack) { + $this->paths = $paths; + } elseif (is_array($paths)) { + $this->clearPaths(); + $this->addPaths($paths); + } else { + throw new Exception\InvalidArgumentException( + "Invalid argument provided for \$paths, expecting either an array or SplStack object" + ); + } + + return $this; + } + + /** + * Normalize a path for insertion in the stack + * + * @param string $path + * @return string + */ + public static function normalizePath($path) + { + $path = rtrim($path, '/'); + $path = rtrim($path, '\\'); + $path .= DIRECTORY_SEPARATOR; + return $path; + } + + /** + * Add a single path to the stack + * + * @param string $path + * @return TemplatePathStack + * @throws Exception\InvalidArgumentException + */ + public function addPath($path) + { + if (!is_string($path)) { + throw new Exception\InvalidArgumentException(sprintf( + 'Invalid path provided; must be a string, received %s', + gettype($path) + )); + } + $this->paths[] = static::normalizePath($path); + return $this; + } + + /** + * Clear all paths + * + * @return void + */ + public function clearPaths() + { + $this->paths = new SplStack; + } + + /** + * Returns stack of paths + * + * @return SplStack + */ + public function getPaths() + { + return $this->paths; + } + + /** + * Set LFI protection flag + * + * @param bool $flag + * @return TemplatePathStack + */ + public function setLfiProtection($flag) + { + $this->lfiProtectionOn = (bool) $flag; + return $this; + } + + /** + * Return status of LFI protection flag + * + * @return bool + */ + public function isLfiProtectionOn() + { + return $this->lfiProtectionOn; + } + + /** + * Set flag indicating if stream wrapper should be used if short_open_tag is off + * + * @param bool $flag + * @return TemplatePathStack + */ + public function setUseStreamWrapper($flag) + { + $this->useStreamWrapper = (bool) $flag; + return $this; + } + + /** + * Should the stream wrapper be used if short_open_tag is off? + * + * Returns true if the use_stream_wrapper flag is set, and if short_open_tag + * is disabled. + * + * @return bool + */ + public function useStreamWrapper() + { + return ($this->useViewStream && $this->useStreamWrapper); + } + + /** + * Retrieve the filesystem path to a view script + * + * @param string $name + * @param null|Renderer $renderer + * @return string + * @throws Exception\DomainException + */ + public function resolve($name, Renderer $renderer = null) + { + $this->lastLookupFailure = false; + + if ($this->isLfiProtectionOn() && preg_match('#\.\.[\\\/]#', $name)) { + throw new Exception\DomainException( + 'Requested scripts may not include parent directory traversal ("../", "..\\" notation)' + ); + } + + if (!count($this->paths)) { + $this->lastLookupFailure = static::FAILURE_NO_PATHS; + return false; + } + + // Ensure we have the expected file extension + $defaultSuffix = $this->getDefaultSuffix(); + if (pathinfo($name, PATHINFO_EXTENSION) == '') { + $name .= '.' . $defaultSuffix; + } + + foreach ($this->paths as $path) { + $file = new SplFileInfo($path . $name); + if ($file->isReadable()) { + // Found! Return it. + if (($filePath = $file->getRealPath()) === false && substr($path, 0, 7) === 'phar://') { + // Do not try to expand phar paths (realpath + phars == fail) + $filePath = $path . $name; + if (!file_exists($filePath)) { + break; + } + } + if ($this->useStreamWrapper()) { + // If using a stream wrapper, prepend the spec to the path + $filePath = 'zend.view://' . $filePath; + } + return $filePath; + } + } + + $this->lastLookupFailure = static::FAILURE_NOT_FOUND; + return false; + } + + /** + * Get the last lookup failure message, if any + * + * @return false|string + */ + public function getLastLookupFailure() + { + return $this->lastLookupFailure; + } +} diff --git a/library/Zend/View/Strategy/FeedStrategy.php b/library/Zend/View/Strategy/FeedStrategy.php new file mode 100755 index 000000000..40140da5a --- /dev/null +++ b/library/Zend/View/Strategy/FeedStrategy.php @@ -0,0 +1,111 @@ +renderer = $renderer; + } + + /** + * {@inheritDoc} + */ + public function attach(EventManagerInterface $events, $priority = 1) + { + $this->listeners[] = $events->attach(ViewEvent::EVENT_RENDERER, array($this, 'selectRenderer'), $priority); + $this->listeners[] = $events->attach(ViewEvent::EVENT_RESPONSE, array($this, 'injectResponse'), $priority); + } + + /** + * Detect if we should use the FeedRenderer based on model type and/or + * Accept header + * + * @param ViewEvent $e + * @return null|FeedRenderer + */ + public function selectRenderer(ViewEvent $e) + { + $model = $e->getModel(); + + if (!$model instanceof Model\FeedModel) { + // no FeedModel present; do nothing + return; + } + + // FeedModel found + return $this->renderer; + } + + /** + * Inject the response with the feed payload and appropriate Content-Type header + * + * @param ViewEvent $e + * @return void + */ + public function injectResponse(ViewEvent $e) + { + $renderer = $e->getRenderer(); + if ($renderer !== $this->renderer) { + // Discovered renderer is not ours; do nothing + return; + } + + $result = $e->getResult(); + if (!is_string($result) && !$result instanceof Feed) { + // We don't have a string, and thus, no feed + return; + } + + // If the result is a feed, export it + if ($result instanceof Feed) { + $result = $result->export($renderer->getFeedType()); + } + + // Get the content-type header based on feed type + $feedType = $renderer->getFeedType(); + $feedType = ('rss' == $feedType) + ? 'application/rss+xml' + : 'application/atom+xml'; + + $model = $e->getModel(); + $charset = ''; + + if ($model instanceof Model\FeedModel) { + $feed = $model->getFeed(); + + $charset = '; charset=' . $feed->getEncoding() . ';'; + } + + // Populate response + $response = $e->getResponse(); + $response->setContent($result); + $headers = $response->getHeaders(); + $headers->addHeaderLine('content-type', $feedType . $charset); + } +} diff --git a/library/Zend/View/Strategy/JsonStrategy.php b/library/Zend/View/Strategy/JsonStrategy.php new file mode 100755 index 000000000..7cf4b91f0 --- /dev/null +++ b/library/Zend/View/Strategy/JsonStrategy.php @@ -0,0 +1,141 @@ +renderer = $renderer; + } + + /** + * {@inheritDoc} + */ + public function attach(EventManagerInterface $events, $priority = 1) + { + $this->listeners[] = $events->attach(ViewEvent::EVENT_RENDERER, array($this, 'selectRenderer'), $priority); + $this->listeners[] = $events->attach(ViewEvent::EVENT_RESPONSE, array($this, 'injectResponse'), $priority); + } + + /** + * Set the content-type character set + * + * @param string $charset + * @return JsonStrategy + */ + public function setCharset($charset) + { + $this->charset = (string) $charset; + return $this; + } + + /** + * Retrieve the current character set + * + * @return string + */ + public function getCharset() + { + return $this->charset; + } + + /** + * Detect if we should use the JsonRenderer based on model type and/or + * Accept header + * + * @param ViewEvent $e + * @return null|JsonRenderer + */ + public function selectRenderer(ViewEvent $e) + { + $model = $e->getModel(); + + if (!$model instanceof Model\JsonModel) { + // no JsonModel; do nothing + return; + } + + // JsonModel found + return $this->renderer; + } + + /** + * Inject the response with the JSON payload and appropriate Content-Type header + * + * @param ViewEvent $e + * @return void + */ + public function injectResponse(ViewEvent $e) + { + $renderer = $e->getRenderer(); + if ($renderer !== $this->renderer) { + // Discovered renderer is not ours; do nothing + return; + } + + $result = $e->getResult(); + if (!is_string($result)) { + // We don't have a string, and thus, no JSON + return; + } + + // Populate response + $response = $e->getResponse(); + $response->setContent($result); + $headers = $response->getHeaders(); + + if ($this->renderer->hasJsonpCallback()) { + $contentType = 'application/javascript'; + } else { + $contentType = 'application/json'; + } + + $contentType .= '; charset=' . $this->charset; + $headers->addHeaderLine('content-type', $contentType); + + if (in_array(strtoupper($this->charset), $this->multibyteCharsets)) { + $headers->addHeaderLine('content-transfer-encoding', 'BINARY'); + } + } +} diff --git a/library/Zend/View/Strategy/PhpRendererStrategy.php b/library/Zend/View/Strategy/PhpRendererStrategy.php new file mode 100755 index 000000000..e8e04ceb3 --- /dev/null +++ b/library/Zend/View/Strategy/PhpRendererStrategy.php @@ -0,0 +1,127 @@ +renderer = $renderer; + } + + /** + * Retrieve the composed renderer + * + * @return PhpRenderer + */ + public function getRenderer() + { + return $this->renderer; + } + + /** + * Set list of possible content placeholders + * + * @param array $contentPlaceholders + * @return PhpRendererStrategy + */ + public function setContentPlaceholders(array $contentPlaceholders) + { + $this->contentPlaceholders = $contentPlaceholders; + return $this; + } + + /** + * Get list of possible content placeholders + * + * @return array + */ + public function getContentPlaceholders() + { + return $this->contentPlaceholders; + } + + /** + * {@inheritDoc} + */ + public function attach(EventManagerInterface $events, $priority = 1) + { + $this->listeners[] = $events->attach(ViewEvent::EVENT_RENDERER, array($this, 'selectRenderer'), $priority); + $this->listeners[] = $events->attach(ViewEvent::EVENT_RESPONSE, array($this, 'injectResponse'), $priority); + } + + /** + * Select the PhpRenderer; typically, this will be registered last or at + * low priority. + * + * @param ViewEvent $e + * @return PhpRenderer + */ + public function selectRenderer(ViewEvent $e) + { + return $this->renderer; + } + + /** + * Populate the response object from the View + * + * Populates the content of the response object from the view rendering + * results. + * + * @param ViewEvent $e + * @return void + */ + public function injectResponse(ViewEvent $e) + { + $renderer = $e->getRenderer(); + if ($renderer !== $this->renderer) { + return; + } + + $result = $e->getResult(); + $response = $e->getResponse(); + + // Set content + // If content is empty, check common placeholders to determine if they are + // populated, and set the content from them. + if (empty($result)) { + $placeholders = $renderer->plugin('placeholder'); + foreach ($this->contentPlaceholders as $placeholder) { + if ($placeholders->containerExists($placeholder)) { + $result = (string) $placeholders->getContainer($placeholder); + break; + } + } + } + $response->setContent($result); + } +} diff --git a/library/Zend/View/Stream.php b/library/Zend/View/Stream.php new file mode 100755 index 000000000..42bb7a962 --- /dev/null +++ b/library/Zend/View/Stream.php @@ -0,0 +1,183 @@ +data = file_get_contents($path); + + /** + * If reading the file failed, update our local stat store + * to reflect the real stat of the file, then return on failure + */ + if ($this->data === false) { + $this->stat = stat($path); + return false; + } + + /** + * Convert to long-form and to + * + */ + $this->data = preg_replace('/\<\?\=/', "data); + $this->data = preg_replace('/<\?(?!xml|php)/s', 'data); + + /** + * file_get_contents() won't update PHP's stat cache, so we grab a stat + * of the file to prevent additional reads should the script be + * requested again, which will make include() happy. + */ + $this->stat = stat($path); + + return true; + } + + /** + * Included so that __FILE__ returns the appropriate info + * + * @return array + */ + public function url_stat() + { + return $this->stat; + } + + /** + * Reads from the stream. + * + * @param int $count + * @return string + */ + public function stream_read($count) + { + $ret = substr($this->data, $this->pos, $count); + $this->pos += strlen($ret); + return $ret; + } + + /** + * Tells the current position in the stream. + * + * @return int + */ + public function stream_tell() + { + return $this->pos; + } + + /** + * Tells if we are at the end of the stream. + * + * @return bool + */ + public function stream_eof() + { + return $this->pos >= strlen($this->data); + } + + /** + * Stream statistics. + * + * @return array + */ + public function stream_stat() + { + return $this->stat; + } + + /** + * Seek to a specific point in the stream. + * + * @param $offset + * @param $whence + * @return bool + */ + public function stream_seek($offset, $whence) + { + switch ($whence) { + case SEEK_SET: + if ($offset < strlen($this->data) && $offset >= 0) { + $this->pos = $offset; + return true; + } else { + return false; + } + break; + + case SEEK_CUR: + if ($offset >= 0) { + $this->pos += $offset; + return true; + } else { + return false; + } + break; + + case SEEK_END: + if (strlen($this->data) + $offset >= 0) { + $this->pos = strlen($this->data) + $offset; + return true; + } else { + return false; + } + break; + + default: + return false; + } + } +} diff --git a/library/Zend/View/Variables.php b/library/Zend/View/Variables.php new file mode 100755 index 000000000..17b14724c --- /dev/null +++ b/library/Zend/View/Variables.php @@ -0,0 +1,162 @@ +setOptions($options); + } + + /** + * Configure object + * + * @param array $options + * @return Variables + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + switch (strtolower($key)) { + case 'strict_vars': + $this->setStrictVars($value); + break; + default: + // Unknown options are considered variables + $this[$key] = $value; + break; + } + } + return $this; + } + + /** + * Set status of "strict vars" flag + * + * @param bool $flag + * @return Variables + */ + public function setStrictVars($flag) + { + $this->strictVars = (bool) $flag; + return $this; + } + + /** + * Are we operating with strict variables? + * + * @return bool + */ + public function isStrict() + { + return $this->strictVars; + } + + /** + * Assign many values at once + * + * @param array|object $spec + * @return Variables + * @throws Exception\InvalidArgumentException + */ + public function assign($spec) + { + if (is_object($spec)) { + if (method_exists($spec, 'toArray')) { + $spec = $spec->toArray(); + } else { + $spec = (array) $spec; + } + } + if (!is_array($spec)) { + throw new Exception\InvalidArgumentException(sprintf( + 'assign() expects either an array or an object as an argument; received "%s"', + gettype($spec) + )); + } + foreach ($spec as $key => $value) { + $this[$key] = $value; + } + + return $this; + } + + /** + * Get the variable value + * + * If the value has not been defined, a null value will be returned; if + * strict vars on in place, a notice will also be raised. + * + * Otherwise, returns _escaped_ version of the value. + * + * @param mixed $key + * @return mixed + */ + public function offsetGet($key) + { + if (!$this->offsetExists($key)) { + if ($this->isStrict()) { + trigger_error(sprintf( + 'View variable "%s" does not exist', $key + ), E_USER_NOTICE); + } + return null; + } + + $return = parent::offsetGet($key); + + // If we have a closure/functor, invoke it, and return its return value + if (is_object($return) && is_callable($return)) { + $return = call_user_func($return); + } + + return $return; + } + + /** + * Clear all variables + * + * @return void + */ + public function clear() + { + $this->exchangeArray(array()); + } +} diff --git a/library/Zend/View/View.php b/library/Zend/View/View.php new file mode 100755 index 000000000..aebae58a0 --- /dev/null +++ b/library/Zend/View/View.php @@ -0,0 +1,264 @@ +request = $request; + return $this; + } + + /** + * Set MVC response object + * + * @param Response $response + * @return View + */ + public function setResponse(Response $response) + { + $this->response = $response; + return $this; + } + + /** + * Get MVC request object + * + * @return null|Request + */ + public function getRequest() + { + return $this->request; + } + + /** + * Get MVC response object + * + * @return null|Response + */ + public function getResponse() + { + return $this->response; + } + + /** + * Set the event manager instance + * + * @param EventManagerInterface $events + * @return View + */ + public function setEventManager(EventManagerInterface $events) + { + $events->setIdentifiers(array( + __CLASS__, + get_class($this), + )); + $this->events = $events; + return $this; + } + + /** + * Retrieve the event manager instance + * + * Lazy-loads a default instance if none available + * + * @return EventManagerInterface + */ + public function getEventManager() + { + if (!$this->events instanceof EventManagerInterface) { + $this->setEventManager(new EventManager()); + } + return $this->events; + } + + /** + * Add a rendering strategy + * + * Expects a callable. Strategies should accept a ViewEvent object, and should + * return a Renderer instance if the strategy is selected. + * + * Internally, the callable provided will be subscribed to the "renderer" + * event, at the priority specified. + * + * @param callable $callable + * @param int $priority + * @return View + */ + public function addRenderingStrategy($callable, $priority = 1) + { + $this->getEventManager()->attach(ViewEvent::EVENT_RENDERER, $callable, $priority); + return $this; + } + + /** + * Add a response strategy + * + * Expects a callable. Strategies should accept a ViewEvent object. The return + * value will be ignored. + * + * Typical usages for a response strategy are to populate the Response object. + * + * Internally, the callable provided will be subscribed to the "response" + * event, at the priority specified. + * + * @param callable $callable + * @param int $priority + * @return View + */ + public function addResponseStrategy($callable, $priority = 1) + { + $this->getEventManager()->attach(ViewEvent::EVENT_RESPONSE, $callable, $priority); + return $this; + } + + /** + * Render the provided model. + * + * Internally, the following workflow is used: + * + * - Trigger the "renderer" event to select a renderer. + * - Call the selected renderer with the provided Model + * - Trigger the "response" event + * + * @triggers renderer(ViewEvent) + * @triggers response(ViewEvent) + * @param Model $model + * @throws Exception\RuntimeException + * @return void + */ + public function render(Model $model) + { + $event = $this->getEvent(); + $event->setModel($model); + $events = $this->getEventManager(); + $results = $events->trigger(ViewEvent::EVENT_RENDERER, $event, function ($result) { + return ($result instanceof Renderer); + }); + $renderer = $results->last(); + if (!$renderer instanceof Renderer) { + throw new Exception\RuntimeException(sprintf( + '%s: no renderer selected!', + __METHOD__ + )); + } + + $event->setRenderer($renderer); + $events->trigger(ViewEvent::EVENT_RENDERER_POST, $event); + + // If EVENT_RENDERER or EVENT_RENDERER_POST changed the model, make sure + // we use this new model instead of the current $model + $model = $event->getModel(); + + // If we have children, render them first, but only if: + // a) the renderer does not implement TreeRendererInterface, or + // b) it does, but canRenderTrees() returns false + if ($model->hasChildren() + && (!$renderer instanceof TreeRendererInterface + || !$renderer->canRenderTrees()) + ) { + $this->renderChildren($model); + } + + // Reset the model, in case it has changed, and set the renderer + $event->setModel($model); + $event->setRenderer($renderer); + + $rendered = $renderer->render($model); + + // If this is a child model, return the rendered content; do not + // invoke the response strategy. + $options = $model->getOptions(); + if (array_key_exists('has_parent', $options) && $options['has_parent']) { + return $rendered; + } + + $event->setResult($rendered); + + $events->trigger(ViewEvent::EVENT_RESPONSE, $event); + } + + /** + * Loop through children, rendering each + * + * @param Model $model + * @throws Exception\DomainException + * @return void + */ + protected function renderChildren(Model $model) + { + foreach ($model as $child) { + if ($child->terminate()) { + throw new Exception\DomainException('Inconsistent state; child view model is marked as terminal'); + } + $child->setOption('has_parent', true); + $result = $this->render($child); + $child->setOption('has_parent', null); + $capture = $child->captureTo(); + if (!empty($capture)) { + if ($child->isAppend()) { + $oldResult=$model->{$capture}; + $model->setVariable($capture, $oldResult . $result); + } else { + $model->setVariable($capture, $result); + } + } + } + } + + /** + * Create and return ViewEvent used by render() + * + * @return ViewEvent + */ + protected function getEvent() + { + $event = new ViewEvent(); + $event->setTarget($this); + if (null !== ($request = $this->getRequest())) { + $event->setRequest($request); + } + if (null !== ($response = $this->getResponse())) { + $event->setResponse($response); + } + return $event; + } +} diff --git a/library/Zend/View/ViewEvent.php b/library/Zend/View/ViewEvent.php new file mode 100755 index 000000000..34baa2136 --- /dev/null +++ b/library/Zend/View/ViewEvent.php @@ -0,0 +1,258 @@ +model = $model; + return $this; + } + + /** + * Set the MVC request object + * + * @param Request $request + * @return ViewEvent + */ + public function setRequest(Request $request) + { + $this->request = $request; + return $this; + } + + /** + * Set the MVC response object + * + * @param Response $response + * @return ViewEvent + */ + public function setResponse(Response $response) + { + $this->response = $response; + return $this; + } + + /** + * Set result of rendering + * + * @param mixed $result + * @return ViewEvent + */ + public function setResult($result) + { + $this->result = $result; + return $this; + } + + /** + * Retrieve the view model + * + * @return null|Model + */ + public function getModel() + { + return $this->model; + } + + /** + * Set value for renderer + * + * @param Renderer $renderer + * @return ViewEvent + */ + public function setRenderer(Renderer $renderer) + { + $this->renderer = $renderer; + return $this; + } + + /** + * Get value for renderer + * + * @return null|Renderer + */ + public function getRenderer() + { + return $this->renderer; + } + + /** + * Retrieve the MVC request object + * + * @return null|Request + */ + public function getRequest() + { + return $this->request; + } + + /** + * Retrieve the MVC response object + * + * @return null|Response + */ + public function getResponse() + { + return $this->response; + } + + /** + * Retrieve the result of rendering + * + * @return mixed + */ + public function getResult() + { + return $this->result; + } + + /** + * Get event parameter + * + * @param string $name + * @param mixed $default + * @return mixed + */ + public function getParam($name, $default = null) + { + switch ($name) { + case 'model': + return $this->getModel(); + case 'renderer': + return $this->getRenderer(); + case 'request': + return $this->getRequest(); + case 'response': + return $this->getResponse(); + case 'result': + return $this->getResult(); + default: + return parent::getParam($name, $default); + } + } + + /** + * Get all event parameters + * + * @return array|\ArrayAccess + */ + public function getParams() + { + $params = parent::getParams(); + $params['model'] = $this->getModel(); + $params['renderer'] = $this->getRenderer(); + $params['request'] = $this->getRequest(); + $params['response'] = $this->getResponse(); + $params['result'] = $this->getResult(); + return $params; + } + + /** + * Set event parameters + * + * @param array|object|ArrayAccess $params + * @return ViewEvent + */ + public function setParams($params) + { + parent::setParams($params); + if (!is_array($params) && !$params instanceof ArrayAccess) { + return $this; + } + + foreach (array('model', 'renderer', 'request', 'response', 'result') as $param) { + if (isset($params[$param])) { + $method = 'set' . $param; + $this->$method($params[$param]); + } + } + return $this; + } + + /** + * Set an individual event parameter + * + * @param string $name + * @param mixed $value + * @return ViewEvent + */ + public function setParam($name, $value) + { + switch ($name) { + case 'model': + $this->setModel($value); + break; + case 'renderer': + $this->setRenderer($value); + break; + case 'request': + $this->setRequest($value); + break; + case 'response': + $this->setResponse($value); + break; + case 'result': + $this->setResult($value); + break; + default: + parent::setParam($name, $value); + break; + } + return $this; + } +} diff --git a/library/Zend/View/composer.json b/library/Zend/View/composer.json new file mode 100755 index 000000000..44bb5c275 --- /dev/null +++ b/library/Zend/View/composer.json @@ -0,0 +1,58 @@ +{ + "name": "zendframework/zend-view", + "description": "provides a system of helpers, output filters, and variable escaping", + "license": "BSD-3-Clause", + "keywords": [ + "zf2", + "view" + ], + "homepage": "https://github.com/zendframework/zf2", + "autoload": { + "psr-0": { + "Zend\\View\\": "" + } + }, + "target-dir": "Zend/View", + "require": { + "php": ">=5.3.23", + "zendframework/zend-eventmanager": "self.version", + "zendframework/zend-loader": "self.version", + "zendframework/zend-stdlib": "self.version" + }, + "require-dev": { + "zendframework/zend-authentication": "self.version", + "zendframework/zend-escaper": "self.version", + "zendframework/zend-feed": "self.version", + "zendframework/zend-filter": "self.version", + "zendframework/zend-http": "self.version", + "zendframework/zend-i18n": "self.version", + "zendframework/zend-json": "self.version", + "zendframework/zend-mvc": "self.version", + "zendframework/zend-navigation": "self.version", + "zendframework/zend-paginator": "self.version", + "zendframework/zend-permissions-acl": "self.version", + "zendframework/zend-servicemanager": "self.version", + "zendframework/zend-uri": "self.version" + }, + "suggest": { + "zendframework/zend-authentication": "Zend\\Authentication component", + "zendframework/zend-escaper": "Zend\\Escaper component", + "zendframework/zend-feed": "Zend\\Feed component", + "zendframework/zend-filter": "Zend\\Filter component", + "zendframework/zend-http": "Zend\\Http component", + "zendframework/zend-i18n": "Zend\\I18n component", + "zendframework/zend-json": "Zend\\Json component", + "zendframework/zend-mvc": "Zend\\Mvc component", + "zendframework/zend-navigation": "Zend\\Navigation component", + "zendframework/zend-paginator": "Zend\\Paginator component", + "zendframework/zend-permissions-acl": "Zend\\Permissions\\Acl component", + "zendframework/zend-servicemanager": "Zend\\ServiceManager component", + "zendframework/zend-uri": "Zend\\Uri component" + }, + "extra": { + "branch-alias": { + "dev-master": "2.3-dev", + "dev-develop": "2.4-dev" + } + } +} diff --git a/library/Zend/XmlRpc/AbstractValue.php b/library/Zend/XmlRpc/AbstractValue.php new file mode 100755 index 000000000..221238a09 --- /dev/null +++ b/library/Zend/XmlRpc/AbstractValue.php @@ -0,0 +1,462 @@ +type; + } + + /** + * Get XML generator instance + * + * @return \Zend\XmlRpc\Generator\GeneratorInterface + */ + public static function getGenerator() + { + if (!static::$generator) { + if (extension_loaded('xmlwriter')) { + static::$generator = new Generator\XmlWriter(); + } else { + static::$generator = new Generator\DomDocument(); + } + } + + return static::$generator; + } + + /** + * Sets XML generator instance + * + * @param null|Generator\GeneratorInterface $generator + * @return void + */ + public static function setGenerator(Generator\GeneratorInterface $generator = null) + { + static::$generator = $generator; + } + + /** + * Changes the encoding of the generator + * + * @param string $encoding + * @return void + */ + public static function setEncoding($encoding) + { + $generator = static::getGenerator(); + $newGenerator = new $generator($encoding); + static::setGenerator($newGenerator); + } + + /** + * Return the value of this object, convert the XML-RPC native value into a PHP variable + * + * @return mixed + */ + abstract public function getValue(); + + + /** + * Return the XML code that represent a native MXL-RPC value + * + * @return string + */ + public function saveXml() + { + if (!$this->xml) { + $this->generateXml(); + $this->xml = (string) $this->getGenerator(); + } + return $this->xml; + } + + /** + * Generate XML code that represent a native XML/RPC value + * + * @return void + */ + public function generateXml() + { + $this->_generateXml(); + } + + /** + * Creates a Value* object, representing a native XML-RPC value + * A XmlRpcValue object can be created in 3 ways: + * 1. Autodetecting the native type out of a PHP variable + * (if $type is not set or equal to Value::AUTO_DETECT_TYPE) + * 2. By specifying the native type ($type is one of the Value::XMLRPC_TYPE_* constants) + * 3. From a XML string ($type is set to Value::XML_STRING) + * + * By default the value type is autodetected according to it's PHP type + * + * @param mixed $value + * @param Zend\XmlRpc\Value::constant $type + * @throws Exception\ValueException + * @return AbstractValue + */ + public static function getXmlRpcValue($value, $type = self::AUTO_DETECT_TYPE) + { + switch ($type) { + case self::AUTO_DETECT_TYPE: + // Auto detect the XML-RPC native type from the PHP type of $value + return static::_phpVarToNativeXmlRpc($value); + + case self::XML_STRING: + // Parse the XML string given in $value and get the XML-RPC value in it + return static::_xmlStringToNativeXmlRpc($value); + + case self::XMLRPC_TYPE_I4: + // fall through to the next case + case self::XMLRPC_TYPE_INTEGER: + return new Value\Integer($value); + + case self::XMLRPC_TYPE_I8: + // fall through to the next case + case self::XMLRPC_TYPE_APACHEI8: + return new Value\BigInteger($value); + + case self::XMLRPC_TYPE_DOUBLE: + return new Value\Double($value); + + case self::XMLRPC_TYPE_BOOLEAN: + return new Value\Boolean($value); + + case self::XMLRPC_TYPE_STRING: + return new Value\String($value); + + case self::XMLRPC_TYPE_BASE64: + return new Value\Base64($value); + + case self::XMLRPC_TYPE_NIL: + // fall through to the next case + case self::XMLRPC_TYPE_APACHENIL: + return new Value\Nil(); + + case self::XMLRPC_TYPE_DATETIME: + return new Value\DateTime($value); + + case self::XMLRPC_TYPE_ARRAY: + return new Value\ArrayValue($value); + + case self::XMLRPC_TYPE_STRUCT: + return new Value\Struct($value); + + default: + throw new Exception\ValueException('Given type is not a '. __CLASS__ .' constant'); + } + } + + /** + * Get XML-RPC type for a PHP native variable + * + * @static + * @param mixed $value + * @throws Exception\InvalidArgumentException + * @return string + */ + public static function getXmlRpcTypeByValue($value) + { + if (is_object($value)) { + if ($value instanceof AbstractValue) { + return $value->getType(); + } elseif ($value instanceof DateTime) { + return self::XMLRPC_TYPE_DATETIME; + } + return static::getXmlRpcTypeByValue(get_object_vars($value)); + } elseif (is_array($value)) { + if (!empty($value) && is_array($value) && (array_keys($value) !== range(0, count($value) - 1))) { + return self::XMLRPC_TYPE_STRUCT; + } + return self::XMLRPC_TYPE_ARRAY; + } elseif (is_int($value)) { + return ($value > PHP_INT_MAX) ? self::XMLRPC_TYPE_I8 : self::XMLRPC_TYPE_INTEGER; + } elseif (is_double($value)) { + return self::XMLRPC_TYPE_DOUBLE; + } elseif (is_bool($value)) { + return self::XMLRPC_TYPE_BOOLEAN; + } elseif (null === $value) { + return self::XMLRPC_TYPE_NIL; + } elseif (is_string($value)) { + return self::XMLRPC_TYPE_STRING; + } + throw new Exception\InvalidArgumentException(sprintf( + 'No matching XMLRPC type found for php type %s.', + gettype($value) + )); + } + + /** + * Transform a PHP native variable into a XML-RPC native value + * + * @param mixed $value The PHP variable for conversion + * + * @throws Exception\InvalidArgumentException + * @return AbstractValue + * @static + */ + protected static function _phpVarToNativeXmlRpc($value) + { + // @see http://framework.zend.com/issues/browse/ZF-8623 + if ($value instanceof AbstractValue) { + return $value; + } + + switch (static::getXmlRpcTypeByValue($value)) { + case self::XMLRPC_TYPE_DATETIME: + return new Value\DateTime($value); + + case self::XMLRPC_TYPE_ARRAY: + return new Value\ArrayValue($value); + + case self::XMLRPC_TYPE_STRUCT: + return new Value\Struct($value); + + case self::XMLRPC_TYPE_INTEGER: + return new Value\Integer($value); + + case self::XMLRPC_TYPE_DOUBLE: + return new Value\Double($value); + + case self::XMLRPC_TYPE_BOOLEAN: + return new Value\Boolean($value); + + case self::XMLRPC_TYPE_NIL: + return new Value\Nil; + + case self::XMLRPC_TYPE_STRING: + // Fall through to the next case + default: + // If type isn't identified (or identified as string), it treated as string + return new Value\String($value); + } + } + + /** + * Transform an XML string into a XML-RPC native value + * + * @param string|\SimpleXMLElement $xml A SimpleXMLElement object represent the XML string + * It can be also a valid XML string for conversion + * + * @throws Exception\ValueException + * @return \Zend\XmlRpc\AbstractValue + * @static + */ + protected static function _xmlStringToNativeXmlRpc($xml) + { + static::_createSimpleXMLElement($xml); + + static::_extractTypeAndValue($xml, $type, $value); + + switch ($type) { + // All valid and known XML-RPC native values + case self::XMLRPC_TYPE_I4: + // Fall through to the next case + case self::XMLRPC_TYPE_INTEGER: + $xmlrpcValue = new Value\Integer($value); + break; + case self::XMLRPC_TYPE_APACHEI8: + // Fall through to the next case + case self::XMLRPC_TYPE_I8: + $xmlrpcValue = new Value\BigInteger($value); + break; + case self::XMLRPC_TYPE_DOUBLE: + $xmlrpcValue = new Value\Double($value); + break; + case self::XMLRPC_TYPE_BOOLEAN: + $xmlrpcValue = new Value\Boolean($value); + break; + case self::XMLRPC_TYPE_STRING: + $xmlrpcValue = new Value\String($value); + break; + case self::XMLRPC_TYPE_DATETIME: // The value should already be in an iso8601 format + $xmlrpcValue = new Value\DateTime($value); + break; + case self::XMLRPC_TYPE_BASE64: // The value should already be base64 encoded + $xmlrpcValue = new Value\Base64($value, true); + break; + case self::XMLRPC_TYPE_NIL: + // Fall through to the next case + case self::XMLRPC_TYPE_APACHENIL: + // The value should always be NULL + $xmlrpcValue = new Value\Nil(); + break; + case self::XMLRPC_TYPE_ARRAY: + // PHP 5.2.4 introduced a regression in how empty($xml->value) + // returns; need to look for the item specifically + $data = null; + foreach ($value->children() as $key => $value) { + if ('data' == $key) { + $data = $value; + break; + } + } + + if (null === $data) { + throw new Exception\ValueException('Invalid XML for XML-RPC native '. self::XMLRPC_TYPE_ARRAY .' type: ARRAY tag must contain DATA tag'); + } + $values = array(); + // Parse all the elements of the array from the XML string + // (simple xml element) to Value objects + foreach ($data->value as $element) { + $values[] = static::_xmlStringToNativeXmlRpc($element); + } + $xmlrpcValue = new Value\ArrayValue($values); + break; + case self::XMLRPC_TYPE_STRUCT: + $values = array(); + // Parse all the members of the struct from the XML string + // (simple xml element) to Value objects + foreach ($value->member as $member) { + // @todo? If a member doesn't have a tag, we don't add it to the struct + // Maybe we want to throw an exception here ? + if (!isset($member->value) or !isset($member->name)) { + continue; + //throw new Value_Exception('Member of the '. self::XMLRPC_TYPE_STRUCT .' XML-RPC native type must contain a VALUE tag'); + } + $values[(string) $member->name] = static::_xmlStringToNativeXmlRpc($member->value); + } + $xmlrpcValue = new Value\Struct($values); + break; + default: + throw new Exception\ValueException('Value type \''. $type .'\' parsed from the XML string is not a known XML-RPC native type'); + break; + } + $xmlrpcValue->_setXML($xml->asXML()); + + return $xmlrpcValue; + } + + protected static function _createSimpleXMLElement(&$xml) + { + if ($xml instanceof \SimpleXMLElement) { + return; + } + + try { + $xml = new \SimpleXMLElement($xml); + } catch (\Exception $e) { + // The given string is not a valid XML + throw new Exception\ValueException('Failed to create XML-RPC value from XML string: ' . $e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Extract XML/RPC type and value from SimpleXMLElement object + * + * @param \SimpleXMLElement $xml + * @param string &$type Type bind variable + * @param string &$value Value bind variable + * @return void + */ + protected static function _extractTypeAndValue(\SimpleXMLElement $xml, &$type, &$value) + { + list($type, $value) = each($xml); + if (!$type and $value === null) { + $namespaces = array('ex' => 'http://ws.apache.org/xmlrpc/namespaces/extensions'); + foreach ($namespaces as $namespaceName => $namespaceUri) { + $namespaceXml = $xml->children($namespaceUri); + list($type, $value) = each($namespaceXml); + if ($type !== null) { + $type = $namespaceName . ':' . $type; + break; + } + } + } + + // If no type was specified, the default is string + if (!$type) { + $type = self::XMLRPC_TYPE_STRING; + if (empty($value) and preg_match('#^.*$#', $xml->asXML())) { + $value = str_replace(array('', ''), '', $xml->asXML()); + } + } + } + + /** + * @param $xml + * @return void + */ + protected function _setXML($xml) + { + $this->xml = $this->getGenerator()->stripDeclaration($xml); + } +} diff --git a/library/Zend/XmlRpc/CONTRIBUTING.md b/library/Zend/XmlRpc/CONTRIBUTING.md new file mode 100755 index 000000000..e77f5d2d5 --- /dev/null +++ b/library/Zend/XmlRpc/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# CONTRIBUTING + +Please don't open pull requests against this repository, please use https://github.com/zendframework/zf2. \ No newline at end of file diff --git a/library/Zend/XmlRpc/Client.php b/library/Zend/XmlRpc/Client.php new file mode 100755 index 000000000..504a3bf23 --- /dev/null +++ b/library/Zend/XmlRpc/Client.php @@ -0,0 +1,343 @@ +httpClient = new Http\Client(); + } else { + $this->httpClient = $httpClient; + } + + $this->introspector = new Client\ServerIntrospection($this); + $this->serverAddress = $server; + } + + + /** + * Sets the HTTP client object to use for connecting the XML-RPC server. + * + * @param \Zend\Http\Client $httpClient + * @return \Zend\Http\Client + */ + public function setHttpClient(Http\Client $httpClient) + { + return $this->httpClient = $httpClient; + } + + + /** + * Gets the HTTP client object. + * + * @return \Zend\Http\Client + */ + public function getHttpClient() + { + return $this->httpClient; + } + + + /** + * Sets the object used to introspect remote servers + * + * @param \Zend\XmlRpc\Client\ServerIntrospection + * @return \Zend\XmlRpc\Client\ServerIntrospection + */ + public function setIntrospector(Client\ServerIntrospection $introspector) + { + return $this->introspector = $introspector; + } + + + /** + * Gets the introspection object. + * + * @return \Zend\XmlRpc\Client\ServerIntrospection + */ + public function getIntrospector() + { + return $this->introspector; + } + + + /** + * The request of the last method call + * + * @return \Zend\XmlRpc\Request + */ + public function getLastRequest() + { + return $this->lastRequest; + } + + + /** + * The response received from the last method call + * + * @return \Zend\XmlRpc\Response + */ + public function getLastResponse() + { + return $this->lastResponse; + } + + + /** + * Returns a proxy object for more convenient method calls + * + * @param string $namespace Namespace to proxy or empty string for none + * @return \Zend\XmlRpc\Client\ServerProxy + */ + public function getProxy($namespace = '') + { + if (empty($this->proxyCache[$namespace])) { + $proxy = new Client\ServerProxy($this, $namespace); + $this->proxyCache[$namespace] = $proxy; + } + return $this->proxyCache[$namespace]; + } + + /** + * Set skip system lookup flag + * + * @param bool $flag + * @return \Zend\XmlRpc\Client + */ + public function setSkipSystemLookup($flag = true) + { + $this->skipSystemLookup = (bool) $flag; + return $this; + } + + /** + * Skip system lookup when determining if parameter should be array or struct? + * + * @return bool + */ + public function skipSystemLookup() + { + return $this->skipSystemLookup; + } + + /** + * Perform an XML-RPC request and return a response. + * + * @param \Zend\XmlRpc\Request $request + * @param null|\Zend\XmlRpc\Response $response + * @return void + * @throws \Zend\XmlRpc\Client\Exception\HttpException + */ + public function doRequest($request, $response = null) + { + $this->lastRequest = $request; + + if (PHP_VERSION_ID < 50600) { + iconv_set_encoding('input_encoding', 'UTF-8'); + iconv_set_encoding('output_encoding', 'UTF-8'); + iconv_set_encoding('internal_encoding', 'UTF-8'); + } else { + ini_set('default_charset', 'UTF-8'); + } + + $http = $this->getHttpClient(); + $httpRequest = $http->getRequest(); + if ($httpRequest->getUriString() === null) { + $http->setUri($this->serverAddress); + } + + $headers = $httpRequest->getHeaders(); + $headers->addHeaders(array( + 'Content-Type: text/xml; charset=utf-8', + 'Accept: text/xml', + )); + + if (!$headers->get('user-agent')) { + $headers->addHeaderLine('user-agent', 'Zend_XmlRpc_Client'); + } + + $xml = $this->lastRequest->__toString(); + $http->setRawBody($xml); + $httpResponse = $http->setMethod('POST')->send(); + + if (!$httpResponse->isSuccess()) { + /** + * Exception thrown when an HTTP error occurs + */ + throw new Client\Exception\HttpException( + $httpResponse->getReasonPhrase(), + $httpResponse->getStatusCode() + ); + } + + if ($response === null) { + $response = new Response(); + } + + $this->lastResponse = $response; + $this->lastResponse->loadXml(trim($httpResponse->getBody())); + } + + /** + * Send an XML-RPC request to the service (for a specific method) + * + * @param string $method Name of the method we want to call + * @param array $params Array of parameters for the method + * @return mixed + * @throws \Zend\XmlRpc\Client\Exception\FaultException + */ + public function call($method, $params=array()) + { + if (!$this->skipSystemLookup() && ('system.' != substr($method, 0, 7))) { + // Ensure empty array/struct params are cast correctly + // If system.* methods are not available, bypass. (ZF-2978) + $success = true; + try { + $signatures = $this->getIntrospector()->getMethodSignature($method); + } catch (\Zend\XmlRpc\Exception\ExceptionInterface $e) { + $success = false; + } + if ($success) { + $validTypes = array( + AbstractValue::XMLRPC_TYPE_ARRAY, + AbstractValue::XMLRPC_TYPE_BASE64, + AbstractValue::XMLRPC_TYPE_BOOLEAN, + AbstractValue::XMLRPC_TYPE_DATETIME, + AbstractValue::XMLRPC_TYPE_DOUBLE, + AbstractValue::XMLRPC_TYPE_I4, + AbstractValue::XMLRPC_TYPE_INTEGER, + AbstractValue::XMLRPC_TYPE_NIL, + AbstractValue::XMLRPC_TYPE_STRING, + AbstractValue::XMLRPC_TYPE_STRUCT, + ); + + if (!is_array($params)) { + $params = array($params); + } + foreach ($params as $key => $param) { + if ($param instanceof AbstractValue) { + continue; + } + + if (count($signatures) > 1) { + $type = AbstractValue::getXmlRpcTypeByValue($param); + foreach ($signatures as $signature) { + if (!is_array($signature)) { + continue; + } + if (isset($signature['parameters'][$key])) { + if ($signature['parameters'][$key] == $type) { + break; + } + } + } + } elseif (isset($signatures[0]['parameters'][$key])) { + $type = $signatures[0]['parameters'][$key]; + } else { + $type = null; + } + + if (empty($type) || !in_array($type, $validTypes)) { + $type = AbstractValue::AUTO_DETECT_TYPE; + } + + $params[$key] = AbstractValue::getXmlRpcValue($param, $type); + } + } + } + + $request = $this->_createRequest($method, $params); + + $this->doRequest($request); + + if ($this->lastResponse->isFault()) { + $fault = $this->lastResponse->getFault(); + /** + * Exception thrown when an XML-RPC fault is returned + */ + throw new Client\Exception\FaultException( + $fault->getMessage(), + $fault->getCode() + ); + } + + return $this->lastResponse->getReturnValue(); + } + + /** + * Create request object + * + * @param string $method + * @param array $params + * @return \Zend\XmlRpc\Request + */ + protected function _createRequest($method, $params) + { + return new Request($method, $params); + } +} diff --git a/library/Zend/XmlRpc/Client/Exception/ExceptionInterface.php b/library/Zend/XmlRpc/Client/Exception/ExceptionInterface.php new file mode 100755 index 000000000..03c09959c --- /dev/null +++ b/library/Zend/XmlRpc/Client/Exception/ExceptionInterface.php @@ -0,0 +1,19 @@ +system = $client->getProxy('system'); + } + + /** + * Returns the signature for each method on the server, + * autodetecting whether system.multicall() is supported and + * using it if so. + * + * @return array + */ + public function getSignatureForEachMethod() + { + $methods = $this->listMethods(); + + try { + $signatures = $this->getSignatureForEachMethodByMulticall($methods); + } catch (Exception\FaultException $e) { + // degrade to looping + } + + if (empty($signatures)) { + $signatures = $this->getSignatureForEachMethodByLooping($methods); + } + + return $signatures; + } + + /** + * Attempt to get the method signatures in one request via system.multicall(). + * This is a boxcar feature of XML-RPC and is found on fewer servers. However, + * can significantly improve performance if present. + * + * @param array $methods + * @throws Exception\IntrospectException + * @return array array(array(return, param, param, param...)) + */ + public function getSignatureForEachMethodByMulticall($methods = null) + { + if ($methods === null) { + $methods = $this->listMethods(); + } + + $multicallParams = array(); + foreach ($methods as $method) { + $multicallParams[] = array('methodName' => 'system.methodSignature', + 'params' => array($method)); + } + + $serverSignatures = $this->system->multicall($multicallParams); + + if (! is_array($serverSignatures)) { + $type = gettype($serverSignatures); + $error = "Multicall return is malformed. Expected array, got $type"; + throw new Exception\IntrospectException($error); + } + + if (count($serverSignatures) != count($methods)) { + $error = 'Bad number of signatures received from multicall'; + throw new Exception\IntrospectException($error); + } + + // Create a new signatures array with the methods name as keys and the signature as value + $signatures = array(); + foreach ($serverSignatures as $i => $signature) { + $signatures[$methods[$i]] = $signature; + } + + return $signatures; + } + + /** + * Get the method signatures for every method by + * successively calling system.methodSignature + * + * @param array $methods + * @return array + */ + public function getSignatureForEachMethodByLooping($methods = null) + { + if ($methods === null) { + $methods = $this->listMethods(); + } + + $signatures = array(); + foreach ($methods as $method) { + $signatures[$method] = $this->getMethodSignature($method); + } + + return $signatures; + } + + /** + * Call system.methodSignature() for the given method + * + * @param array $method + * @throws Exception\IntrospectException + * @return array array(array(return, param, param, param...)) + */ + public function getMethodSignature($method) + { + $signature = $this->system->methodSignature($method); + if (!is_array($signature)) { + $error = 'Invalid signature for method "' . $method . '"'; + throw new Exception\IntrospectException($error); + } + return $signature; + } + + /** + * Call system.listMethods() + * + * @return array array(method, method, method...) + */ + public function listMethods() + { + return $this->system->listMethods(); + } +} diff --git a/library/Zend/XmlRpc/Client/ServerProxy.php b/library/Zend/XmlRpc/Client/ServerProxy.php new file mode 100755 index 000000000..861b61590 --- /dev/null +++ b/library/Zend/XmlRpc/Client/ServerProxy.php @@ -0,0 +1,79 @@ +foo->bar->baz()". + */ +class ServerProxy +{ + /** + * @var \Zend\XmlRpc\Client + */ + private $client = null; + + /** + * @var string + */ + private $namespace = ''; + + + /** + * @var array of \Zend\XmlRpc\Client\ServerProxy + */ + private $cache = array(); + + + /** + * Class constructor + * + * @param \Zend\XmlRpc\Client $client + * @param string $namespace + */ + public function __construct(XMLRPCClient $client, $namespace = '') + { + $this->client = $client; + $this->namespace = $namespace; + } + + + /** + * Get the next successive namespace + * + * @param string $namespace + * @return \Zend\XmlRpc\Client\ServerProxy + */ + public function __get($namespace) + { + $namespace = ltrim("$this->namespace.$namespace", '.'); + if (!isset($this->cache[$namespace])) { + $this->cache[$namespace] = new $this($this->client, $namespace); + } + return $this->cache[$namespace]; + } + + + /** + * Call a method in this namespace. + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + $method = ltrim("{$this->namespace}.{$method}", '.'); + return $this->client->call($method, $args); + } +} diff --git a/library/Zend/XmlRpc/Exception/BadMethodCallException.php b/library/Zend/XmlRpc/Exception/BadMethodCallException.php new file mode 100755 index 000000000..db36424ab --- /dev/null +++ b/library/Zend/XmlRpc/Exception/BadMethodCallException.php @@ -0,0 +1,14 @@ + messages + * @var array + */ + protected $internal = array( + 404 => 'Unknown Error', + + // 610 - 619 reflection errors + 610 => 'Invalid method class', + 611 => 'Unable to attach function or callback; not callable', + 612 => 'Unable to load array; not an array', + 613 => 'One or more method records are corrupt or otherwise unusable', + + // 620 - 629 dispatch errors + 620 => 'Method does not exist', + 621 => 'Error instantiating class to invoke method', + 622 => 'Method missing implementation', + 623 => 'Calling parameters do not match signature', + + // 630 - 639 request errors + 630 => 'Unable to read request', + 631 => 'Failed to parse request', + 632 => 'Invalid request, no method passed; request must contain a \'methodName\' tag', + 633 => 'Param must contain a value', + 634 => 'Invalid method name', + 635 => 'Invalid XML provided to request', + 636 => 'Error creating xmlrpc value', + + // 640 - 649 system.* errors + 640 => 'Method does not exist', + + // 650 - 659 response errors + 650 => 'Invalid XML provided for response', + 651 => 'Failed to parse response', + 652 => 'Invalid response', + 653 => 'Invalid XMLRPC value in response', + ); + + /** + * Constructor + * + */ + public function __construct($code = 404, $message = '') + { + $this->setCode($code); + $code = $this->getCode(); + + if (empty($message) && isset($this->internal[$code])) { + $message = $this->internal[$code]; + } elseif (empty($message)) { + $message = 'Unknown error'; + } + $this->setMessage($message); + } + + /** + * Set the fault code + * + * @param int $code + * @return Fault + */ + public function setCode($code) + { + $this->code = (int) $code; + return $this; + } + + /** + * Return fault code + * + * @return int + */ + public function getCode() + { + return $this->code; + } + + /** + * Retrieve fault message + * + * @param string + * @return Fault + */ + public function setMessage($message) + { + $this->message = (string) $message; + return $this; + } + + /** + * Retrieve fault message + * + * @return string + */ + public function getMessage() + { + return $this->message; + } + + /** + * Set encoding to use in fault response + * + * @param string $encoding + * @return Fault + */ + public function setEncoding($encoding) + { + $this->encoding = $encoding; + AbstractValue::setEncoding($encoding); + return $this; + } + + /** + * Retrieve current fault encoding + * + * @return string + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * Load an XMLRPC fault from XML + * + * @param string $fault + * @return bool Returns true if successfully loaded fault response, false + * if response was not a fault response + * @throws Exception\ExceptionInterface if no or faulty XML provided, or if fault + * response does not contain either code or message + */ + public function loadXml($fault) + { + if (!is_string($fault)) { + throw new Exception\InvalidArgumentException('Invalid XML provided to fault'); + } + + $xmlErrorsFlag = libxml_use_internal_errors(true); + try { + $xml = XmlSecurity::scan($fault); + } catch (\ZendXml\Exception\RuntimeException $e) { + // Unsecure XML + throw new Exception\RuntimeException('Failed to parse XML fault: ' . $e->getMessage(), 500, $e); + } + if (!$xml instanceof SimpleXMLElement) { + $errors = libxml_get_errors(); + $errors = array_reduce($errors, function ($result, $item) { + if (empty($result)) { + return $item->message; + } + return $result . '; ' . $item->message; + }, ''); + libxml_use_internal_errors($xmlErrorsFlag); + throw new Exception\InvalidArgumentException('Failed to parse XML fault: ' . $errors, 500); + } + libxml_use_internal_errors($xmlErrorsFlag); + + // Check for fault + if (!$xml->fault) { + // Not a fault + return false; + } + + if (!$xml->fault->value->struct) { + // not a proper fault + throw new Exception\InvalidArgumentException('Invalid fault structure', 500); + } + + $structXml = $xml->fault->value->asXML(); + $struct = AbstractValue::getXmlRpcValue($structXml, AbstractValue::XML_STRING); + $struct = $struct->getValue(); + + if (isset($struct['faultCode'])) { + $code = $struct['faultCode']; + } + if (isset($struct['faultString'])) { + $message = $struct['faultString']; + } + + if (empty($code) && empty($message)) { + throw new Exception\InvalidArgumentException('Fault code and string required'); + } + + if (empty($code)) { + $code = '404'; + } + + if (empty($message)) { + if (isset($this->internal[$code])) { + $message = $this->internal[$code]; + } else { + $message = 'Unknown Error'; + } + } + + $this->setCode($code); + $this->setMessage($message); + + return true; + } + + /** + * Determine if an XML response is an XMLRPC fault + * + * @param string $xml + * @return bool + */ + public static function isFault($xml) + { + $fault = new static(); + try { + $isFault = $fault->loadXml($xml); + } catch (Exception\ExceptionInterface $e) { + $isFault = false; + } + + return $isFault; + } + + /** + * Serialize fault to XML + * + * @return string + */ + public function saveXml() + { + // Create fault value + $faultStruct = array( + 'faultCode' => $this->getCode(), + 'faultString' => $this->getMessage() + ); + $value = AbstractValue::getXmlRpcValue($faultStruct); + + $generator = AbstractValue::getGenerator(); + $generator->openElement('methodResponse') + ->openElement('fault'); + $value->generateXml(); + $generator->closeElement('fault') + ->closeElement('methodResponse'); + + return $generator->flush(); + } + + /** + * Return XML fault response + * + * @return string + */ + public function __toString() + { + return $this->saveXML(); + } +} diff --git a/library/Zend/XmlRpc/Generator/AbstractGenerator.php b/library/Zend/XmlRpc/Generator/AbstractGenerator.php new file mode 100755 index 000000000..693f026c0 --- /dev/null +++ b/library/Zend/XmlRpc/Generator/AbstractGenerator.php @@ -0,0 +1,151 @@ +setEncoding($encoding); + $this->_init(); + } + + /** + * Initialize internal objects + * + * @return void + */ + abstract protected function _init(); + + /** + * Start XML element + * + * Method opens a new XML element with an element name and an optional value + * + * @param string $name XML tag name + * @param string $value Optional value of the XML tag + * @return AbstractGenerator Fluent interface + */ + public function openElement($name, $value = null) + { + $this->_openElement($name); + if ($value !== null) { + $this->_writeTextData($value); + } + + return $this; + } + + /** + * End of an XML element + * + * Method marks the end of an XML element + * + * @param string $name XML tag name + * @return AbstractGenerator Fluent interface + */ + public function closeElement($name) + { + $this->_closeElement($name); + + return $this; + } + + /** + * Return encoding + * + * @return string + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * Set XML encoding + * + * @param string $encoding + * @return AbstractGenerator + */ + public function setEncoding($encoding) + { + $this->encoding = $encoding; + return $this; + } + + /** + * Returns the XML as a string and flushes all internal buffers + * + * @return string + */ + public function flush() + { + $xml = $this->saveXml(); + $this->_init(); + return $xml; + } + + /** + * Returns XML without document declaration + * + * @return string + */ + public function __toString() + { + return $this->stripDeclaration($this->saveXml()); + } + + /** + * Removes XML declaration from a string + * + * @param string $xml + * @return string + */ + public function stripDeclaration($xml) + { + return preg_replace('/<\?xml version="1.0"( encoding="[^\"]*")?\?>\n/u', '', $xml); + } + + /** + * Start XML element + * + * @param string $name XML element name + */ + abstract protected function _openElement($name); + + /** + * Write XML text data into the currently opened XML element + * + * @param string $text + */ + abstract protected function _writeTextData($text); + + /** + * End XML element + * + * @param string $name + */ + abstract protected function _closeElement($name); +} diff --git a/library/Zend/XmlRpc/Generator/DomDocument.php b/library/Zend/XmlRpc/Generator/DomDocument.php new file mode 100755 index 000000000..47e7a7223 --- /dev/null +++ b/library/Zend/XmlRpc/Generator/DomDocument.php @@ -0,0 +1,85 @@ +dom->createElement($name); + + $this->currentElement = $this->currentElement->appendChild($newElement); + } + + /** + * Write XML text data into the currently opened XML element + * + * @param string $text + */ + protected function _writeTextData($text) + { + $this->currentElement->appendChild($this->dom->createTextNode($text)); + } + + /** + * Close a previously opened XML element + * + * Resets $currentElement to the next parent node in the hierarchy + * + * @param string $name + * @return void + */ + protected function _closeElement($name) + { + if (isset($this->currentElement->parentNode)) { + $this->currentElement = $this->currentElement->parentNode; + } + } + + /** + * Save XML as a string + * + * @return string + */ + public function saveXml() + { + return $this->dom->saveXml(); + } + + /** + * Initializes internal objects + * + * @return void + */ + protected function _init() + { + $this->dom = new \DOMDocument('1.0', $this->encoding); + $this->currentElement = $this->dom; + } +} diff --git a/library/Zend/XmlRpc/Generator/GeneratorInterface.php b/library/Zend/XmlRpc/Generator/GeneratorInterface.php new file mode 100755 index 000000000..ca2af243b --- /dev/null +++ b/library/Zend/XmlRpc/Generator/GeneratorInterface.php @@ -0,0 +1,32 @@ +xmlWriter = new \XMLWriter(); + $this->xmlWriter->openMemory(); + $this->xmlWriter->startDocument('1.0', $this->encoding); + } + + + /** + * Open a new XML element + * + * @param string $name XML element name + * @return void + */ + protected function _openElement($name) + { + $this->xmlWriter->startElement($name); + } + + /** + * Write XML text data into the currently opened XML element + * + * @param string $text XML text data + * @return void + */ + protected function _writeTextData($text) + { + $this->xmlWriter->text($text); + } + + /** + * Close a previously opened XML element + * + * @param string $name + * @return XmlWriter + */ + protected function _closeElement($name) + { + $this->xmlWriter->endElement(); + + return $this; + } + + /** + * Emit XML document + * + * @return string + */ + public function saveXml() + { + return $this->xmlWriter->flush(false); + } +} diff --git a/library/Zend/XmlRpc/README.md b/library/Zend/XmlRpc/README.md new file mode 100755 index 000000000..f003296a4 --- /dev/null +++ b/library/Zend/XmlRpc/README.md @@ -0,0 +1,15 @@ +XML-RPC Component from ZF2 +========================== + +This is the XML-RPC component for ZF2. + +- File issues at https://github.com/zendframework/zf2/issues +- Create pull requests against https://github.com/zendframework/zf2 +- Documentation is at http://framework.zend.com/docs + +LICENSE +------- + +The files in this archive are released under the [Zend Framework +license](http://framework.zend.com/license), which is a 3-clause BSD license. + diff --git a/library/Zend/XmlRpc/Request.php b/library/Zend/XmlRpc/Request.php new file mode 100755 index 000000000..82a7eedbe --- /dev/null +++ b/library/Zend/XmlRpc/Request.php @@ -0,0 +1,444 @@ +setMethod($method); + } + + if ($params !== null) { + $this->setParams($params); + } + } + + + /** + * Set encoding to use in request + * + * @param string $encoding + * @return \Zend\XmlRpc\Request + */ + public function setEncoding($encoding) + { + $this->encoding = $encoding; + AbstractValue::setEncoding($encoding); + return $this; + } + + /** + * Retrieve current request encoding + * + * @return string + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * Set method to call + * + * @param string $method + * @return bool Returns true on success, false if method name is invalid + */ + public function setMethod($method) + { + if (!is_string($method) || !preg_match('/^[a-z0-9_.:\\\\\/]+$/i', $method)) { + $this->fault = new Fault(634, 'Invalid method name ("' . $method . '")'); + $this->fault->setEncoding($this->getEncoding()); + return false; + } + + $this->method = $method; + return true; + } + + /** + * Retrieve call method + * + * @return string + */ + public function getMethod() + { + return $this->method; + } + + /** + * Add a parameter to the parameter stack + * + * Adds a parameter to the parameter stack, associating it with the type + * $type if provided + * + * @param mixed $value + * @param string $type Optional; type hinting + * @return void + */ + public function addParam($value, $type = null) + { + $this->params[] = $value; + if (null === $type) { + // Detect type if not provided explicitly + if ($value instanceof AbstractValue) { + $type = $value->getType(); + } else { + $xmlRpcValue = AbstractValue::getXmlRpcValue($value); + $type = $xmlRpcValue->getType(); + } + } + $this->types[] = $type; + $this->xmlRpcParams[] = array('value' => $value, 'type' => $type); + } + + /** + * Set the parameters array + * + * If called with a single, array value, that array is used to set the + * parameters stack. If called with multiple values or a single non-array + * value, the arguments are used to set the parameters stack. + * + * Best is to call with array of the format, in order to allow type hinting + * when creating the XMLRPC values for each parameter: + * + * $array = array( + * array( + * 'value' => $value, + * 'type' => $type + * )[, ... ] + * ); + * + * + * @access public + * @return void + */ + public function setParams() + { + $argc = func_num_args(); + $argv = func_get_args(); + if (0 == $argc) { + return; + } + + if ((1 == $argc) && is_array($argv[0])) { + $params = array(); + $types = array(); + $wellFormed = true; + foreach ($argv[0] as $arg) { + if (!is_array($arg) || !isset($arg['value'])) { + $wellFormed = false; + break; + } + $params[] = $arg['value']; + + if (!isset($arg['type'])) { + $xmlRpcValue = AbstractValue::getXmlRpcValue($arg['value']); + $arg['type'] = $xmlRpcValue->getType(); + } + $types[] = $arg['type']; + } + if ($wellFormed) { + $this->xmlRpcParams = $argv[0]; + $this->params = $params; + $this->types = $types; + } else { + $this->params = $argv[0]; + $this->types = array(); + $xmlRpcParams = array(); + foreach ($argv[0] as $arg) { + if ($arg instanceof AbstractValue) { + $type = $arg->getType(); + } else { + $xmlRpcValue = AbstractValue::getXmlRpcValue($arg); + $type = $xmlRpcValue->getType(); + } + $xmlRpcParams[] = array('value' => $arg, 'type' => $type); + $this->types[] = $type; + } + $this->xmlRpcParams = $xmlRpcParams; + } + return; + } + + $this->params = $argv; + $this->types = array(); + $xmlRpcParams = array(); + foreach ($argv as $arg) { + if ($arg instanceof AbstractValue) { + $type = $arg->getType(); + } else { + $xmlRpcValue = AbstractValue::getXmlRpcValue($arg); + $type = $xmlRpcValue->getType(); + } + $xmlRpcParams[] = array('value' => $arg, 'type' => $type); + $this->types[] = $type; + } + $this->xmlRpcParams = $xmlRpcParams; + } + + /** + * Retrieve the array of parameters + * + * @return array + */ + public function getParams() + { + return $this->params; + } + + /** + * Return parameter types + * + * @return array + */ + public function getTypes() + { + return $this->types; + } + + /** + * Load XML and parse into request components + * + * @param string $request + * @throws Exception\ValueException if invalid XML + * @return bool True on success, false if an error occurred. + */ + public function loadXml($request) + { + if (!is_string($request)) { + $this->fault = new Fault(635); + $this->fault->setEncoding($this->getEncoding()); + return false; + } + + // @see ZF-12293 - disable external entities for security purposes + $loadEntities = libxml_disable_entity_loader(true); + $xmlErrorsFlag = libxml_use_internal_errors(true); + try { + $dom = new DOMDocument; + $dom->loadXML($request); + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + throw new Exception\ValueException( + 'Invalid XML: Detected use of illegal DOCTYPE' + ); + } + } + ErrorHandler::start(); + $xml = simplexml_import_dom($dom); + $error = ErrorHandler::stop(); + libxml_disable_entity_loader($loadEntities); + libxml_use_internal_errors($xmlErrorsFlag); + } catch (\Exception $e) { + // Not valid XML + $this->fault = new Fault(631); + $this->fault->setEncoding($this->getEncoding()); + libxml_disable_entity_loader($loadEntities); + libxml_use_internal_errors($xmlErrorsFlag); + return false; + } + if (!$xml instanceof SimpleXMLElement || $error) { + // Not valid XML + $this->fault = new Fault(631); + $this->fault->setEncoding($this->getEncoding()); + libxml_use_internal_errors($xmlErrorsFlag); + return false; + } + + // Check for method name + if (empty($xml->methodName)) { + // Missing method name + $this->fault = new Fault(632); + $this->fault->setEncoding($this->getEncoding()); + return false; + } + + $this->method = (string) $xml->methodName; + + // Check for parameters + if (!empty($xml->params)) { + $types = array(); + $argv = array(); + foreach ($xml->params->children() as $param) { + if (!isset($param->value)) { + $this->fault = new Fault(633); + $this->fault->setEncoding($this->getEncoding()); + return false; + } + + try { + $param = AbstractValue::getXmlRpcValue($param->value, AbstractValue::XML_STRING); + $types[] = $param->getType(); + $argv[] = $param->getValue(); + } catch (\Exception $e) { + $this->fault = new Fault(636); + $this->fault->setEncoding($this->getEncoding()); + return false; + } + } + + $this->types = $types; + $this->params = $argv; + } + + $this->xml = $request; + + return true; + } + + /** + * Does the current request contain errors and should it return a fault + * response? + * + * @return bool + */ + public function isFault() + { + return $this->fault instanceof Fault; + } + + /** + * Retrieve the fault response, if any + * + * @return null|\Zend\XmlRpc\Fault + */ + public function getFault() + { + return $this->fault; + } + + /** + * Retrieve method parameters as XMLRPC values + * + * @return array + */ + protected function _getXmlRpcParams() + { + $params = array(); + if (is_array($this->xmlRpcParams)) { + foreach ($this->xmlRpcParams as $param) { + $value = $param['value']; + $type = $param['type'] ?: AbstractValue::AUTO_DETECT_TYPE; + + if (!$value instanceof AbstractValue) { + $value = AbstractValue::getXmlRpcValue($value, $type); + } + $params[] = $value; + } + } + + return $params; + } + + /** + * Create XML request + * + * @return string + */ + public function saveXml() + { + $args = $this->_getXmlRpcParams(); + $method = $this->getMethod(); + + $generator = AbstractValue::getGenerator(); + $generator->openElement('methodCall') + ->openElement('methodName', $method) + ->closeElement('methodName'); + + if (is_array($args) && count($args)) { + $generator->openElement('params'); + + foreach ($args as $arg) { + $generator->openElement('param'); + $arg->generateXml(); + $generator->closeElement('param'); + } + $generator->closeElement('params'); + } + $generator->closeElement('methodCall'); + + return $generator->flush(); + } + + /** + * Return XML request + * + * @return string + */ + public function __toString() + { + return $this->saveXML(); + } +} diff --git a/library/Zend/XmlRpc/Request/Http.php b/library/Zend/XmlRpc/Request/Http.php new file mode 100755 index 000000000..d42a8331d --- /dev/null +++ b/library/Zend/XmlRpc/Request/Http.php @@ -0,0 +1,108 @@ +fault = new Fault(630); + return; + } + + $this->xml = $xml; + + $this->loadXml($xml); + } + + /** + * Retrieve the raw XML request + * + * @return string + */ + public function getRawRequest() + { + return $this->xml; + } + + /** + * Get headers + * + * Gets all headers as key => value pairs and returns them. + * + * @return array + */ + public function getHeaders() + { + if (null === $this->headers) { + $this->headers = array(); + foreach ($_SERVER as $key => $value) { + if ('HTTP_' == substr($key, 0, 5)) { + $header = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5))))); + $this->headers[$header] = $value; + } + } + } + + return $this->headers; + } + + /** + * Retrieve the full HTTP request, including headers and XML + * + * @return string + */ + public function getFullRequest() + { + $request = ''; + foreach ($this->getHeaders() as $key => $value) { + $request .= $key . ': ' . $value . "\n"; + } + + $request .= $this->xml; + + return $request; + } +} diff --git a/library/Zend/XmlRpc/Request/Stdin.php b/library/Zend/XmlRpc/Request/Stdin.php new file mode 100755 index 000000000..bcf748e95 --- /dev/null +++ b/library/Zend/XmlRpc/Request/Stdin.php @@ -0,0 +1,66 @@ +fault = new Fault(630); + return; + } + + $xml = ''; + while (!feof($fh)) { + $xml .= fgets($fh); + } + fclose($fh); + + $this->xml = $xml; + + $this->loadXml($xml); + } + + /** + * Retrieve the raw XML request + * + * @return string + */ + public function getRawRequest() + { + return $this->xml; + } +} diff --git a/library/Zend/XmlRpc/Response.php b/library/Zend/XmlRpc/Response.php new file mode 100755 index 000000000..f8537584e --- /dev/null +++ b/library/Zend/XmlRpc/Response.php @@ -0,0 +1,224 @@ +setReturnValue($return, $type); + } + + /** + * Set encoding to use in response + * + * @param string $encoding + * @return \Zend\XmlRpc\Response + */ + public function setEncoding($encoding) + { + $this->encoding = $encoding; + AbstractValue::setEncoding($encoding); + return $this; + } + + /** + * Retrieve current response encoding + * + * @return string + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * Set the return value + * + * Sets the return value, with optional type hinting if provided. + * + * @param mixed $value + * @param string $type + * @return void + */ + public function setReturnValue($value, $type = null) + { + $this->return = $value; + $this->type = (string) $type; + } + + /** + * Retrieve the return value + * + * @return mixed + */ + public function getReturnValue() + { + return $this->return; + } + + /** + * Retrieve the XMLRPC value for the return value + * + * @return \Zend\XmlRpc\AbstractValue + */ + protected function _getXmlRpcReturn() + { + return AbstractValue::getXmlRpcValue($this->return); + } + + /** + * Is the response a fault response? + * + * @return bool + */ + public function isFault() + { + return $this->fault instanceof Fault; + } + + /** + * Returns the fault, if any. + * + * @return null|\Zend\XmlRpc\Fault + */ + public function getFault() + { + return $this->fault; + } + + /** + * Load a response from an XML response + * + * Attempts to load a response from an XMLRPC response, autodetecting if it + * is a fault response. + * + * @param string $response + * @throws Exception\ValueException if invalid XML + * @return bool True if a valid XMLRPC response, false if a fault + * response or invalid input + */ + public function loadXml($response) + { + if (!is_string($response)) { + $this->fault = new Fault(650); + $this->fault->setEncoding($this->getEncoding()); + return false; + } + + try { + $xml = XmlSecurity::scan($response); + } catch (\ZendXml\Exception\RuntimeException $e) { + $this->fault = new Fault(651); + $this->fault->setEncoding($this->getEncoding()); + return false; + } + + if (!empty($xml->fault)) { + // fault response + $this->fault = new Fault(); + $this->fault->setEncoding($this->getEncoding()); + $this->fault->loadXml($response); + return false; + } + + if (empty($xml->params)) { + // Invalid response + $this->fault = new Fault(652); + $this->fault->setEncoding($this->getEncoding()); + return false; + } + + try { + if (!isset($xml->params) || !isset($xml->params->param) || !isset($xml->params->param->value)) { + throw new Exception\ValueException('Missing XML-RPC value in XML'); + } + $valueXml = $xml->params->param->value->asXML(); + $value = AbstractValue::getXmlRpcValue($valueXml, AbstractValue::XML_STRING); + } catch (Exception\ValueException $e) { + $this->fault = new Fault(653); + $this->fault->setEncoding($this->getEncoding()); + return false; + } + + $this->setReturnValue($value->getValue()); + return true; + } + + /** + * Return response as XML + * + * @return string + */ + public function saveXml() + { + $value = $this->_getXmlRpcReturn(); + $generator = AbstractValue::getGenerator(); + $generator->openElement('methodResponse') + ->openElement('params') + ->openElement('param'); + $value->generateXml(); + $generator->closeElement('param') + ->closeElement('params') + ->closeElement('methodResponse'); + + return $generator->flush(); + } + + /** + * Return XML response + * + * @return string + */ + public function __toString() + { + return $this->saveXML(); + } +} diff --git a/library/Zend/XmlRpc/Response/Http.php b/library/Zend/XmlRpc/Response/Http.php new file mode 100755 index 000000000..00ae07cc9 --- /dev/null +++ b/library/Zend/XmlRpc/Response/Http.php @@ -0,0 +1,32 @@ +getEncoding())); + } + + return parent::__toString(); + } +} diff --git a/library/Zend/XmlRpc/Server.php b/library/Zend/XmlRpc/Server.php new file mode 100755 index 000000000..e2cfcea6b --- /dev/null +++ b/library/Zend/XmlRpc/Server.php @@ -0,0 +1,609 @@ + + * use Zend\XmlRpc; + * + * // Instantiate server + * $server = new XmlRpc\Server(); + * + * // Allow some exceptions to report as fault responses: + * XmlRpc\Server\Fault::attachFaultException('My\\Exception'); + * XmlRpc\Server\Fault::attachObserver('My\\Fault\\Observer'); + * + * // Get or build dispatch table: + * if (!XmlRpc\Server\Cache::get($filename, $server)) { + * + * // Attach Some_Service_Class in 'some' namespace + * $server->setClass('Some\\Service\\Class', 'some'); + * + * // Attach Another_Service_Class in 'another' namespace + * $server->setClass('Another\\Service\\Class', 'another'); + * + * // Create dispatch table cache file + * XmlRpc\Server\Cache::save($filename, $server); + * } + * + * $response = $server->handle(); + * echo $response; + * + */ +class Server extends AbstractServer +{ + /** + * Character encoding + * @var string + */ + protected $encoding = 'UTF-8'; + + /** + * Request processed + * @var null|Request + */ + protected $request = null; + + /** + * Class to use for responses; defaults to {@link Response\Http} + * @var string + */ + protected $responseClass = 'Zend\XmlRpc\Response\Http'; + + /** + * Dispatch table of name => method pairs + * @var Definition + */ + protected $table; + + /** + * PHP types => XML-RPC types + * @var array + */ + protected $typeMap = array( + 'i4' => 'i4', + 'int' => 'int', + 'integer' => 'int', + 'i8' => 'i8', + 'ex:i8' => 'i8', + 'double' => 'double', + 'float' => 'double', + 'real' => 'double', + 'boolean' => 'boolean', + 'bool' => 'boolean', + 'true' => 'boolean', + 'false' => 'boolean', + 'string' => 'string', + 'str' => 'string', + 'base64' => 'base64', + 'dateTime.iso8601' => 'dateTime.iso8601', + 'date' => 'dateTime.iso8601', + 'time' => 'dateTime.iso8601', + 'DateTime' => 'dateTime.iso8601', + 'array' => 'array', + 'struct' => 'struct', + 'null' => 'nil', + 'nil' => 'nil', + 'ex:nil' => 'nil', + 'void' => 'void', + 'mixed' => 'struct', + ); + + /** + * Send arguments to all methods or just constructor? + * + * @var bool + */ + protected $sendArgumentsToAllMethods = true; + + /** + * Flag: whether or not {@link handle()} should return a response instead + * of automatically emitting it. + * @var bool + */ + protected $returnResponse = false; + + /** + * Last response results. + * @var Response + */ + protected $response; + + /** + * Constructor + * + * Creates system.* methods. + * + */ + public function __construct() + { + $this->table = new Definition(); + $this->registerSystemMethods(); + } + + /** + * Proxy calls to system object + * + * @param string $method + * @param array $params + * @return mixed + * @throws Server\Exception\BadMethodCallException + */ + public function __call($method, $params) + { + $system = $this->getSystem(); + if (!method_exists($system, $method)) { + throw new Server\Exception\BadMethodCallException('Unknown instance method called on server: ' . $method); + } + return call_user_func_array(array($system, $method), $params); + } + + /** + * Attach a callback as an XMLRPC method + * + * Attaches a callback as an XMLRPC method, prefixing the XMLRPC method name + * with $namespace, if provided. Reflection is done on the callback's + * docblock to create the methodHelp for the XMLRPC method. + * + * Additional arguments to pass to the function at dispatch may be passed; + * any arguments following the namespace will be aggregated and passed at + * dispatch time. + * + * @param string|array|callable $function Valid callback + * @param string $namespace Optional namespace prefix + * @throws Server\Exception\InvalidArgumentException + * @return void + */ + public function addFunction($function, $namespace = '') + { + if (!is_string($function) && !is_array($function)) { + throw new Server\Exception\InvalidArgumentException('Unable to attach function; invalid', 611); + } + + $argv = null; + if (2 < func_num_args()) { + $argv = func_get_args(); + $argv = array_slice($argv, 2); + } + + $function = (array) $function; + foreach ($function as $func) { + if (!is_string($func) || !function_exists($func)) { + throw new Server\Exception\InvalidArgumentException('Unable to attach function; invalid', 611); + } + $reflection = Reflection::reflectFunction($func, $argv, $namespace); + $this->_buildSignature($reflection); + } + } + + /** + * Attach class methods as XMLRPC method handlers + * + * $class may be either a class name or an object. Reflection is done on the + * class or object to determine the available public methods, and each is + * attached to the server as an available method; if a $namespace has been + * provided, that namespace is used to prefix the XMLRPC method names. + * + * Any additional arguments beyond $namespace will be passed to a method at + * invocation. + * + * @param string|object $class + * @param string $namespace Optional + * @param mixed $argv Optional arguments to pass to methods + * @return void + * @throws Server\Exception\InvalidArgumentException on invalid input + */ + public function setClass($class, $namespace = '', $argv = null) + { + if (is_string($class) && !class_exists($class)) { + throw new Server\Exception\InvalidArgumentException('Invalid method class', 610); + } + + if (2 < func_num_args()) { + $argv = func_get_args(); + $argv = array_slice($argv, 2); + } + + $dispatchable = Reflection::reflectClass($class, $argv, $namespace); + foreach ($dispatchable->getMethods() as $reflection) { + $this->_buildSignature($reflection, $class); + } + } + + /** + * Raise an xmlrpc server fault + * + * @param string|\Exception $fault + * @param int $code + * @return Server\Fault + */ + public function fault($fault = null, $code = 404) + { + if (!$fault instanceof \Exception) { + $fault = (string) $fault; + if (empty($fault)) { + $fault = 'Unknown Error'; + } + $fault = new Server\Exception\RuntimeException($fault, $code); + } + + return Server\Fault::getInstance($fault); + } + + /** + * Set return response flag + * + * If true, {@link handle()} will return the response instead of + * automatically sending it back to the requesting client. + * + * The response is always available via {@link getResponse()}. + * + * @param bool $flag + * @return Server + */ + public function setReturnResponse($flag = true) + { + $this->returnResponse = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve return response flag + * + * @return bool + */ + public function getReturnResponse() + { + return $this->returnResponse; + } + + /** + * Handle an xmlrpc call + * + * @param Request $request Optional + * @return Response|Fault + */ + public function handle($request = false) + { + // Get request + if ((!$request || !$request instanceof Request) + && (null === ($request = $this->getRequest())) + ) { + $request = new Request\Http(); + $request->setEncoding($this->getEncoding()); + } + + $this->setRequest($request); + + if ($request->isFault()) { + $response = $request->getFault(); + } else { + try { + $response = $this->handleRequest($request); + } catch (\Exception $e) { + $response = $this->fault($e); + } + } + + // Set output encoding + $response->setEncoding($this->getEncoding()); + $this->response = $response; + + if (!$this->returnResponse) { + echo $response; + return; + } + + return $response; + } + + /** + * Load methods as returned from {@link getFunctions} + * + * Typically, you will not use this method; it will be called using the + * results pulled from {@link Zend\XmlRpc\Server\Cache::get()}. + * + * @param array|Definition $definition + * @return void + * @throws Server\Exception\InvalidArgumentException on invalid input + */ + public function loadFunctions($definition) + { + if (!is_array($definition) && (!$definition instanceof Definition)) { + if (is_object($definition)) { + $type = get_class($definition); + } else { + $type = gettype($definition); + } + throw new Server\Exception\InvalidArgumentException('Unable to load server definition; must be an array or Zend\Server\Definition, received ' . $type, 612); + } + + $this->table->clearMethods(); + $this->registerSystemMethods(); + + if ($definition instanceof Definition) { + $definition = $definition->getMethods(); + } + + foreach ($definition as $key => $method) { + if ('system.' == substr($key, 0, 7)) { + continue; + } + $this->table->addMethod($method, $key); + } + } + + /** + * Set encoding + * + * @param string $encoding + * @return Server + */ + public function setEncoding($encoding) + { + $this->encoding = $encoding; + AbstractValue::setEncoding($encoding); + return $this; + } + + /** + * Retrieve current encoding + * + * @return string + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * Do nothing; persistence is handled via {@link Zend\XmlRpc\Server\Cache} + * + * @param mixed $mode + * @return void + */ + public function setPersistence($mode) + { + } + + /** + * Set the request object + * + * @param string|Request $request + * @return Server + * @throws Server\Exception\InvalidArgumentException on invalid request class or object + */ + public function setRequest($request) + { + if (is_string($request) && class_exists($request)) { + $request = new $request(); + if (!$request instanceof Request) { + throw new Server\Exception\InvalidArgumentException('Invalid request class'); + } + $request->setEncoding($this->getEncoding()); + } elseif (!$request instanceof Request) { + throw new Server\Exception\InvalidArgumentException('Invalid request object'); + } + + $this->request = $request; + return $this; + } + + /** + * Return currently registered request object + * + * @return null|Request + */ + public function getRequest() + { + return $this->request; + } + + /** + * Last response. + * + * @return Response + */ + public function getResponse() + { + return $this->response; + } + + /** + * Set the class to use for the response + * + * @param string $class + * @throws Server\Exception\InvalidArgumentException if invalid response class + * @return bool True if class was set, false if not + */ + public function setResponseClass($class) + { + if (!class_exists($class) || !static::isSubclassOf($class, 'Zend\XmlRpc\Response')) { + throw new Server\Exception\InvalidArgumentException('Invalid response class'); + } + $this->responseClass = $class; + return true; + } + + /** + * Retrieve current response class + * + * @return string + */ + public function getResponseClass() + { + return $this->responseClass; + } + + /** + * Retrieve dispatch table + * + * @return array + */ + public function getDispatchTable() + { + return $this->table; + } + + /** + * Returns a list of registered methods + * + * Returns an array of dispatchables (Zend\Server\Reflection\ReflectionFunction, + * ReflectionMethod, and ReflectionClass items). + * + * @return array + */ + public function getFunctions() + { + return $this->table->toArray(); + } + + /** + * Retrieve system object + * + * @return Server\System + */ + public function getSystem() + { + return $this->system; + } + + /** + * Send arguments to all methods? + * + * If setClass() is used to add classes to the server, this flag defined + * how to handle arguments. If set to true, all methods including constructor + * will receive the arguments. If set to false, only constructor will receive the + * arguments + */ + public function sendArgumentsToAllMethods($flag = null) + { + if ($flag === null) { + return $this->sendArgumentsToAllMethods; + } + + $this->sendArgumentsToAllMethods = (bool) $flag; + return $this; + } + + /** + * Map PHP type to XML-RPC type + * + * @param string $type + * @return string + */ + protected function _fixType($type) + { + if (isset($this->typeMap[$type])) { + return $this->typeMap[$type]; + } + return 'void'; + } + + /** + * Handle an xmlrpc call (actual work) + * + * @param Request $request + * @return Response + * @throws Server\Exception\RuntimeException + * Zend\XmlRpc\Server\Exceptions are thrown for internal errors; otherwise, + * any other exception may be thrown by the callback + */ + protected function handleRequest(Request $request) + { + $method = $request->getMethod(); + + // Check for valid method + if (!$this->table->hasMethod($method)) { + throw new Server\Exception\RuntimeException('Method "' . $method . '" does not exist', 620); + } + + $info = $this->table->getMethod($method); + $params = $request->getParams(); + $argv = $info->getInvokeArguments(); + if (0 < count($argv) and $this->sendArgumentsToAllMethods()) { + $params = array_merge($params, $argv); + } + + // Check calling parameters against signatures + $matched = false; + $sigCalled = $request->getTypes(); + + $sigLength = count($sigCalled); + $paramsLen = count($params); + if ($sigLength < $paramsLen) { + for ($i = $sigLength; $i < $paramsLen; ++$i) { + $xmlRpcValue = AbstractValue::getXmlRpcValue($params[$i]); + $sigCalled[] = $xmlRpcValue->getType(); + } + } + + $signatures = $info->getPrototypes(); + foreach ($signatures as $signature) { + $sigParams = $signature->getParameters(); + if ($sigCalled === $sigParams) { + $matched = true; + break; + } + } + if (!$matched) { + throw new Server\Exception\RuntimeException('Calling parameters do not match signature', 623); + } + + $return = $this->_dispatch($info, $params); + $responseClass = $this->getResponseClass(); + return new $responseClass($return); + } + + /** + * Register system methods with the server + * + * @return void + */ + protected function registerSystemMethods() + { + $system = new Server\System($this); + $this->system = $system; + $this->setClass($system, 'system'); + } + + /** + * Checks if the object has this class as one of its parents + * + * @see https://bugs.php.net/bug.php?id=53727 + * @see https://github.com/zendframework/zf2/pull/1807 + * + * @param string $className + * @param string $type + * @return bool + */ + protected static function isSubclassOf($className, $type) + { + if (is_subclass_of($className, $type)) { + return true; + } + if (PHP_VERSION_ID >= 50307) { + return false; + } + if (!interface_exists($type)) { + return false; + } + $r = new ReflectionClass($className); + return $r->implementsInterface($type); + } +} diff --git a/library/Zend/XmlRpc/Server/Cache.php b/library/Zend/XmlRpc/Server/Cache.php new file mode 100755 index 000000000..f4e643ea6 --- /dev/null +++ b/library/Zend/XmlRpc/Server/Cache.php @@ -0,0 +1,26 @@ + true); + + /** + * @var array Array of fault observers + */ + protected static $observers = array(); + + /** + * Constructor + * + * @param \Exception $e + * @return Fault + */ + public function __construct(\Exception $e) + { + $this->exception = $e; + $code = 404; + $message = 'Unknown error'; + + foreach (array_keys(static::$faultExceptionClasses) as $class) { + if ($e instanceof $class) { + $code = $e->getCode(); + $message = $e->getMessage(); + break; + } + } + + parent::__construct($code, $message); + + // Notify exception observers, if present + if (!empty(static::$observers)) { + foreach (array_keys(static::$observers) as $observer) { + $observer::observe($this); + } + } + } + + /** + * Return Zend\XmlRpc\Server\Fault instance + * + * @param \Exception $e + * @return Fault + */ + public static function getInstance(\Exception $e) + { + return new static($e); + } + + /** + * Attach valid exceptions that can be used to define xmlrpc faults + * + * @param string|array $classes Class name or array of class names + * @return void + */ + public static function attachFaultException($classes) + { + if (!is_array($classes)) { + $classes = (array) $classes; + } + + foreach ($classes as $class) { + if (is_string($class) && class_exists($class)) { + static::$faultExceptionClasses[$class] = true; + } + } + } + + /** + * Detach fault exception classes + * + * @param string|array $classes Class name or array of class names + * @return void + */ + public static function detachFaultException($classes) + { + if (!is_array($classes)) { + $classes = (array) $classes; + } + + foreach ($classes as $class) { + if (is_string($class) && isset(static::$faultExceptionClasses[$class])) { + unset(static::$faultExceptionClasses[$class]); + } + } + } + + /** + * Attach an observer class + * + * Allows observation of xmlrpc server faults, thus allowing logging or mail + * notification of fault responses on the xmlrpc server. + * + * Expects a valid class name; that class must have a public static method + * 'observe' that accepts an exception as its sole argument. + * + * @param string $class + * @return bool + */ + public static function attachObserver($class) + { + if (!is_string($class) + || !class_exists($class) + || !is_callable(array($class, 'observe')) + ) { + return false; + } + + if (!isset(static::$observers[$class])) { + static::$observers[$class] = true; + } + + return true; + } + + /** + * Detach an observer + * + * @param string $class + * @return bool + */ + public static function detachObserver($class) + { + if (!isset(static::$observers[$class])) { + return false; + } + + unset(static::$observers[$class]); + return true; + } + + /** + * Retrieve the exception + * + * @access public + * @return \Exception + */ + public function getException() + { + return $this->exception; + } +} diff --git a/library/Zend/XmlRpc/Server/System.php b/library/Zend/XmlRpc/Server/System.php new file mode 100755 index 000000000..8a57838b1 --- /dev/null +++ b/library/Zend/XmlRpc/Server/System.php @@ -0,0 +1,144 @@ +server = $server; + } + + /** + * List all available XMLRPC methods + * + * Returns an array of methods. + * + * @return array + */ + public function listMethods() + { + $table = $this->server->getDispatchTable()->getMethods(); + return array_keys($table); + } + + /** + * Display help message for an XMLRPC method + * + * @param string $method + * @throws Exception\InvalidArgumentException + * @return string + */ + public function methodHelp($method) + { + $table = $this->server->getDispatchTable(); + if (!$table->hasMethod($method)) { + throw new Exception\InvalidArgumentException('Method "' . $method . '" does not exist', 640); + } + + return $table->getMethod($method)->getMethodHelp(); + } + + /** + * Return a method signature + * + * @param string $method + * @throws Exception\InvalidArgumentException + * @return array + */ + public function methodSignature($method) + { + $table = $this->server->getDispatchTable(); + if (!$table->hasMethod($method)) { + throw new Exception\InvalidArgumentException('Method "' . $method . '" does not exist', 640); + } + $method = $table->getMethod($method)->toArray(); + return $method['prototypes']; + } + + /** + * Multicall - boxcar feature of XML-RPC for calling multiple methods + * in a single request. + * + * Expects an array of structs representing method calls, each element + * having the keys: + * - methodName + * - params + * + * Returns an array of responses, one for each method called, with the value + * returned by the method. If an error occurs for a given method, returns a + * struct with a fault response. + * + * @see http://www.xmlrpc.com/discuss/msgReader$1208 + * @param array $methods + * @return array + */ + public function multicall($methods) + { + $responses = array(); + foreach ($methods as $method) { + $fault = false; + if (!is_array($method)) { + $fault = $this->server->fault('system.multicall expects each method to be a struct', 601); + } elseif (!isset($method['methodName'])) { + $fault = $this->server->fault('Missing methodName: ' . var_export($methods, 1), 602); + } elseif (!isset($method['params'])) { + $fault = $this->server->fault('Missing params', 603); + } elseif (!is_array($method['params'])) { + $fault = $this->server->fault('Params must be an array', 604); + } else { + if ('system.multicall' == $method['methodName']) { + // don't allow recursive calls to multicall + $fault = $this->server->fault('Recursive system.multicall forbidden', 605); + } + } + + if (!$fault) { + try { + $request = new \Zend\XmlRpc\Request(); + $request->setMethod($method['methodName']); + $request->setParams($method['params']); + $response = $this->server->handle($request); + if ($response instanceof \Zend\XmlRpc\Fault + || $response->isFault() + ) { + $fault = $response; + } else { + $responses[] = $response->getReturnValue(); + } + } catch (\Exception $e) { + $fault = $this->server->fault($e); + } + } + + if ($fault) { + $responses[] = array( + 'faultCode' => $fault->getCode(), + 'faultString' => $fault->getMessage() + ); + } + } + + return $responses; + } +} diff --git a/library/Zend/XmlRpc/Value/AbstractCollection.php b/library/Zend/XmlRpc/Value/AbstractCollection.php new file mode 100755 index 000000000..ed4f8193f --- /dev/null +++ b/library/Zend/XmlRpc/Value/AbstractCollection.php @@ -0,0 +1,48 @@ + $value) { + // If the elements of the given array are not Zend\XmlRpc\Value objects, + // we need to convert them as such (using auto-detection from PHP value) + if (!$value instanceof parent) { + $value = static::getXmlRpcValue($value, self::AUTO_DETECT_TYPE); + } + $this->value[$key] = $value; + } + } + + + /** + * Return the value of this object, convert the XML-RPC native collection values into a PHP array + * + * @return array + */ + public function getValue() + { + $values = (array) $this->value; + foreach ($values as $key => $value) { + $values[$key] = $value->getValue(); + } + return $values; + } +} diff --git a/library/Zend/XmlRpc/Value/AbstractScalar.php b/library/Zend/XmlRpc/Value/AbstractScalar.php new file mode 100755 index 000000000..3e7b8eacb --- /dev/null +++ b/library/Zend/XmlRpc/Value/AbstractScalar.php @@ -0,0 +1,30 @@ +getGenerator(); + + $generator->openElement('value') + ->openElement($this->type, $this->value) + ->closeElement($this->type) + ->closeElement('value'); + } +} diff --git a/library/Zend/XmlRpc/Value/ArrayValue.php b/library/Zend/XmlRpc/Value/ArrayValue.php new file mode 100755 index 000000000..99d77437b --- /dev/null +++ b/library/Zend/XmlRpc/Value/ArrayValue.php @@ -0,0 +1,47 @@ +type = self::XMLRPC_TYPE_ARRAY; + parent::__construct($value); + } + + + /** + * Generate the XML code that represent an array native MXL-RPC value + * + * @return void + */ + protected function _generateXml() + { + $generator = $this->getGenerator(); + $generator->openElement('value') + ->openElement('array') + ->openElement('data'); + + if (is_array($this->value)) { + foreach ($this->value as $val) { + $val->generateXml(); + } + } + $generator->closeElement('data') + ->closeElement('array') + ->closeElement('value'); + } +} diff --git a/library/Zend/XmlRpc/Value/Base64.php b/library/Zend/XmlRpc/Value/Base64.php new file mode 100755 index 000000000..9ba44acea --- /dev/null +++ b/library/Zend/XmlRpc/Value/Base64.php @@ -0,0 +1,42 @@ +type = self::XMLRPC_TYPE_BASE64; + + $value = (string) $value; // Make sure this value is string + if (!$alreadyEncoded) { + $value = base64_encode($value); // We encode it in base64 + } + $this->value = $value; + } + + /** + * Return the value of this object, convert the XML-RPC native base64 value into a PHP string + * We return this value decoded (a normal string) + * + * @return string + */ + public function getValue() + { + return base64_decode($this->value); + } +} diff --git a/library/Zend/XmlRpc/Value/BigInteger.php b/library/Zend/XmlRpc/Value/BigInteger.php new file mode 100755 index 000000000..e85ef9537 --- /dev/null +++ b/library/Zend/XmlRpc/Value/BigInteger.php @@ -0,0 +1,34 @@ +value = BigIntegerMath::factory()->init($value, 10); + $this->type = self::XMLRPC_TYPE_I8; + } + + /** + * Return bigint value object + * + * @return string + */ + public function getValue() + { + return $this->value; + } +} diff --git a/library/Zend/XmlRpc/Value/Boolean.php b/library/Zend/XmlRpc/Value/Boolean.php new file mode 100755 index 000000000..5ec6b7932 --- /dev/null +++ b/library/Zend/XmlRpc/Value/Boolean.php @@ -0,0 +1,37 @@ +type = self::XMLRPC_TYPE_BOOLEAN; + // Make sure the value is boolean and then convert it into an integer + // The double conversion is because a bug in the ZendOptimizer in PHP version 5.0.4 + $this->value = (int)(bool) $value; + } + + /** + * Return the value of this object, convert the XML-RPC native boolean value into a PHP boolean + * + * @return bool + */ + public function getValue() + { + return (bool) $this->value; + } +} diff --git a/library/Zend/XmlRpc/Value/DateTime.php b/library/Zend/XmlRpc/Value/DateTime.php new file mode 100755 index 000000000..9ec7253e6 --- /dev/null +++ b/library/Zend/XmlRpc/Value/DateTime.php @@ -0,0 +1,67 @@ +type = self::XMLRPC_TYPE_DATETIME; + + if ($value instanceof \DateTime) { + $this->value = $value->format($this->phpFormatString); + } elseif (is_numeric($value)) { // The value is numeric, we make sure it is an integer + $this->value = date($this->phpFormatString, (int) $value); + } else { + try { + $dateTime = new \DateTime($value); + } catch (\Exception $e) { + throw new Exception\ValueException($e->getMessage(), $e->getCode(), $e); + } + + $this->value = $dateTime->format($this->phpFormatString); // Convert the DateTime to iso8601 format + } + } + + /** + * Return the value of this object as iso8601 dateTime value + * + * @return int As a Unix timestamp + */ + public function getValue() + { + return $this->value; + } +} diff --git a/library/Zend/XmlRpc/Value/Double.php b/library/Zend/XmlRpc/Value/Double.php new file mode 100755 index 000000000..722012000 --- /dev/null +++ b/library/Zend/XmlRpc/Value/Double.php @@ -0,0 +1,36 @@ +type = self::XMLRPC_TYPE_DOUBLE; + $precision = (int) ini_get('precision'); + $formatString = '%1.' . $precision . 'F'; + $this->value = rtrim(sprintf($formatString, (float) $value), '0'); + } + + /** + * Return the value of this object, convert the XML-RPC native double value into a PHP float + * + * @return float + */ + public function getValue() + { + return (float) $this->value; + } +} diff --git a/library/Zend/XmlRpc/Value/Integer.php b/library/Zend/XmlRpc/Value/Integer.php new file mode 100755 index 000000000..40d938664 --- /dev/null +++ b/library/Zend/XmlRpc/Value/Integer.php @@ -0,0 +1,41 @@ + PHP_INT_MAX) { + throw new Exception\ValueException('Overlong integer given'); + } + + $this->type = self::XMLRPC_TYPE_INTEGER; + $this->value = (int) $value; // Make sure this value is integer + } + + /** + * Return the value of this object, convert the XML-RPC native integer value into a PHP integer + * + * @return int + */ + public function getValue() + { + return $this->value; + } +} diff --git a/library/Zend/XmlRpc/Value/Nil.php b/library/Zend/XmlRpc/Value/Nil.php new file mode 100755 index 000000000..49f3c7511 --- /dev/null +++ b/library/Zend/XmlRpc/Value/Nil.php @@ -0,0 +1,33 @@ +type = self::XMLRPC_TYPE_NIL; + $this->value = null; + } + + /** + * Return the value of this object, convert the XML-RPC native nill value into a PHP NULL + * + * @return null + */ + public function getValue() + { + return null; + } +} diff --git a/library/Zend/XmlRpc/Value/String.php b/library/Zend/XmlRpc/Value/String.php new file mode 100755 index 000000000..66fa441b0 --- /dev/null +++ b/library/Zend/XmlRpc/Value/String.php @@ -0,0 +1,36 @@ +type = self::XMLRPC_TYPE_STRING; + + // Make sure this value is string and all XML characters are encoded + $this->value = (string) $value; + } + + /** + * Return the value of this object, convert the XML-RPC native string value into a PHP string + * + * @return string + */ + public function getValue() + { + return (string) $this->value; + } +} diff --git a/library/Zend/XmlRpc/Value/Struct.php b/library/Zend/XmlRpc/Value/Struct.php new file mode 100755 index 000000000..99d55bb84 --- /dev/null +++ b/library/Zend/XmlRpc/Value/Struct.php @@ -0,0 +1,49 @@ +type = self::XMLRPC_TYPE_STRUCT; + parent::__construct($value); + } + + + /** + * Generate the XML code that represent struct native MXL-RPC value + * + * @return void + */ + protected function _generateXML() + { + $generator = $this->getGenerator(); + $generator->openElement('value') + ->openElement('struct'); + + if (is_array($this->value)) { + foreach ($this->value as $name => $val) { + $generator->openElement('member') + ->openElement('name', $name) + ->closeElement('name'); + $val->generateXml(); + $generator->closeElement('member'); + } + } + $generator->closeElement('struct') + ->closeElement('value'); + } +} diff --git a/library/Zend/XmlRpc/composer.json b/library/Zend/XmlRpc/composer.json new file mode 100755 index 000000000..1520a41e4 --- /dev/null +++ b/library/Zend/XmlRpc/composer.json @@ -0,0 +1,30 @@ +{ + "name": "zendframework/zend-xmlrpc", + "description": " ", + "license": "BSD-3-Clause", + "keywords": [ + "zf2", + "xmlrpc" + ], + "homepage": "https://github.com/zendframework/zf2", + "autoload": { + "psr-0": { + "Zend\\XmlRpc\\": "" + } + }, + "target-dir": "Zend/XmlRpc", + "require": { + "php": ">=5.3.23", + "zendframework/zend-http": "self.version", + "zendframework/zend-math": "self.version", + "zendframework/zend-server": "self.version", + "zendframework/zend-stdlib": "self.version", + "zendframework/zendxml": "1.*" + }, + "extra": { + "branch-alias": { + "dev-master": "2.3-dev", + "dev-develop": "2.4-dev" + } + } +} From 0387f38d7fe746bb0edaafafa37ba0ca94cdef1a Mon Sep 17 00:00:00 2001 From: Exile Date: Mon, 24 Nov 2014 20:18:22 +0300 Subject: [PATCH 30/32] =?UTF-8?q?=D0=98=D0=BD=D1=82=D0=B5=D0=B3=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D1=81=20Zend=20Framework?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Класс интеграции + вывод версии ZF в админку (для своевременного обновления). --- common.php | 4 + library/config.php | 1 + library/includes/classes/zendLoader.php | 97 +++++++++++++++++++++++++ library/language/en/main.php | 1 + library/language/ru/main.php | 1 + library/language/uk/main.php | 1 + styles/templates/admin/index.tpl | 8 +- 7 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 library/includes/classes/zendLoader.php diff --git a/common.php b/common.php index 6fbd66384..4177c0fec 100644 --- a/common.php +++ b/common.php @@ -19,6 +19,10 @@ header('X-Frame-Options: SAMEORIGIN'); // Get initial config require(BB_ROOT . 'library/config.php'); +// Load Zend Framework +require(CLASS_DIR . 'zendLoader.php'); +ZendLoader::getInstance()->setupAutoloader(BB_ROOT . '/library'); + $server_protocol = ($bb_cfg['cookie_secure']) ? 'https://' : 'http://'; $server_port = (in_array($bb_cfg['server_port'], array(80, 443))) ? '' : ':' . $bb_cfg['server_port']; define('FORUM_PATH', $bb_cfg['script_path']); diff --git a/library/config.php b/library/config.php index 7bb896f88..a12591131 100644 --- a/library/config.php +++ b/library/config.php @@ -75,6 +75,7 @@ $domain_name = (!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : $do $bb_cfg['tp_version'] = '2.1.4'; $bb_cfg['tp_release_date'] = '**-11-2014'; $bb_cfg['tp_release_state'] = 'ALPHA'; +$bb_cfg['tp_zf_version'] = '2.3.3'; // Database $charset = 'utf8'; diff --git a/library/includes/classes/zendLoader.php b/library/includes/classes/zendLoader.php new file mode 100644 index 000000000..dd4621957 --- /dev/null +++ b/library/includes/classes/zendLoader.php @@ -0,0 +1,97 @@ +_setup) + { + return; + } + + $this->_rootDir = $rootDir; + $this->_setupAutoloader(); + + $this->_setup = true; + } + + protected function _setupAutoloader() + { + if (@ini_get('open_basedir')) + { + set_include_path($this->_rootDir . PATH_SEPARATOR . '.'); + } + else + { + set_include_path($this->_rootDir . PATH_SEPARATOR . '.' . PATH_SEPARATOR . get_include_path()); + } + + spl_autoload_register(array($this, 'autoload')); + } + + public function autoload($class) + { + if (class_exists($class, false) || interface_exists($class, false)) + { + return true; + } + + if ($class == 'utf8_entity_decoder') + { + return true; + } + + $filename = $this->autoloaderClassToFile($class); + if (!$filename) + { + return false; + } + + if (file_exists($filename)) + { + include($filename); + return (class_exists($class, false) || interface_exists($class, false)); + } + + return false; + } + + public function autoloaderClassToFile($class) + { + if (preg_match('#[^a-zA-Z0-9_\\\\]#', $class)) + { + return false; + } + + return $this->_rootDir . '/' . str_replace(array('_', '\\'), '/', $class) . '.php'; + } + + public function getRootDir() + { + return $this->_rootDir; + } + + public static final function getInstance() + { + if (!self::$_instance) + { + self::$_instance = new self(); + } + + return self::$_instance; + } + + public static function setInstance(ZendLoader $loader = null) + { + self::$_instance = $loader; + } +} \ No newline at end of file diff --git a/library/language/en/main.php b/library/language/en/main.php index c4bf20e7e..cb9583d3f 100644 --- a/library/language/en/main.php +++ b/library/language/en/main.php @@ -1620,6 +1620,7 @@ $lang['CREATE_PROFILE'] = 'Create profile'; $lang['TP_VERSION'] = 'TorrentPier version'; $lang['TP_RELEASE_DATE'] = 'Release date'; +$lang['ZF_VERSION'] = 'Zend Framework version'; $lang['PHP_INFO'] = 'Information about PHP'; $lang['CLICK_RETURN_ADMIN_INDEX'] = 'Click %sHere%s to return to the Admin Index'; diff --git a/library/language/ru/main.php b/library/language/ru/main.php index a45dacbb1..6977eeba7 100644 --- a/library/language/ru/main.php +++ b/library/language/ru/main.php @@ -1620,6 +1620,7 @@ $lang['CREATE_PROFILE'] = 'Создать аккаунт'; $lang['TP_VERSION'] = 'Версия TorrentPier II'; $lang['TP_RELEASE_DATE'] = 'Дата выпуска'; +$lang['ZF_VERSION'] = 'Версия Zend Framework'; $lang['PHP_INFO'] = 'Информация о PHP'; $lang['CLICK_RETURN_ADMIN_INDEX'] = '%sВернуться на главную страницу администраторского раздела%s'; diff --git a/library/language/uk/main.php b/library/language/uk/main.php index 6abd28883..90202f122 100644 --- a/library/language/uk/main.php +++ b/library/language/uk/main.php @@ -1620,6 +1620,7 @@ $lang['CREATE_PROFILE'] = 'Створити акаунт'; $lang['TP_VERSION'] = 'Версія TorrentPier II'; $lang['TP_RELEASE_DATE'] = 'Дата випуску'; +$lang['ZF_VERSION'] = 'Версія Zend Framework'; $lang['PHP_INFO'] = 'Інформація про PHP'; $lang['CLICK_RETURN_ADMIN_INDEX'] = '%sВернуться на головну сторінку адміністраторського розділу%s'; diff --git a/styles/templates/admin/index.tpl b/styles/templates/admin/index.tpl index 0e1fd7f25..ab6721255 100644 --- a/styles/templates/admin/index.tpl +++ b/styles/templates/admin/index.tpl @@ -135,13 +135,17 @@ ajax.callback.manage_admin = function(data) { {L_VERSION_INFORMATION} - {L_TP_VERSION}: + {L_TP_VERSION}: {$bb_cfg['tp_version']} [{$bb_cfg['tp_release_state']}] - {L_TP_RELEASE_DATE}: + {L_TP_RELEASE_DATE}: {$bb_cfg['tp_release_date']} + + {L_ZF_VERSION}: + {$bb_cfg['tp_zf_version']} +
    From 449b519f72c9dc3dd8f69d3a150f677b68a7a50e Mon Sep 17 00:00:00 2001 From: Exile Date: Tue, 25 Nov 2014 00:47:30 +0300 Subject: [PATCH 31/32] =?UTF-8?q?=D0=9F=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=82=20ZF1=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BC=D0=B5=D0=BD=D1=8F=D0=B5=D0=BC=20=D0=BD=D0=B0=20ZF2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Исправление несоответствия подключения от ZF1 и самого ZF2. --- .gitignore | 1 + common.php | 4 +- library/includes/classes/zendLoader.php | 97 ------------------------- 3 files changed, 3 insertions(+), 99 deletions(-) delete mode 100644 library/includes/classes/zendLoader.php diff --git a/.gitignore b/.gitignore index c9080af50..d430f2cc7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ internal_data/captcha/**/ internal_data/log/ internal_data/sitemap/*.xml internal_data/triggers/ +library/config.local.php ### Archives ### *.log diff --git a/common.php b/common.php index 4177c0fec..cf0bfb2ab 100644 --- a/common.php +++ b/common.php @@ -20,8 +20,8 @@ header('X-Frame-Options: SAMEORIGIN'); require(BB_ROOT . 'library/config.php'); // Load Zend Framework -require(CLASS_DIR . 'zendLoader.php'); -ZendLoader::getInstance()->setupAutoloader(BB_ROOT . '/library'); +require_once(BB_ROOT . 'library/Zend/Loader/AutoloaderFactory.php'); +Zend\Loader\AutoloaderFactory::factory(array()); $server_protocol = ($bb_cfg['cookie_secure']) ? 'https://' : 'http://'; $server_port = (in_array($bb_cfg['server_port'], array(80, 443))) ? '' : ':' . $bb_cfg['server_port']; diff --git a/library/includes/classes/zendLoader.php b/library/includes/classes/zendLoader.php deleted file mode 100644 index dd4621957..000000000 --- a/library/includes/classes/zendLoader.php +++ /dev/null @@ -1,97 +0,0 @@ -_setup) - { - return; - } - - $this->_rootDir = $rootDir; - $this->_setupAutoloader(); - - $this->_setup = true; - } - - protected function _setupAutoloader() - { - if (@ini_get('open_basedir')) - { - set_include_path($this->_rootDir . PATH_SEPARATOR . '.'); - } - else - { - set_include_path($this->_rootDir . PATH_SEPARATOR . '.' . PATH_SEPARATOR . get_include_path()); - } - - spl_autoload_register(array($this, 'autoload')); - } - - public function autoload($class) - { - if (class_exists($class, false) || interface_exists($class, false)) - { - return true; - } - - if ($class == 'utf8_entity_decoder') - { - return true; - } - - $filename = $this->autoloaderClassToFile($class); - if (!$filename) - { - return false; - } - - if (file_exists($filename)) - { - include($filename); - return (class_exists($class, false) || interface_exists($class, false)); - } - - return false; - } - - public function autoloaderClassToFile($class) - { - if (preg_match('#[^a-zA-Z0-9_\\\\]#', $class)) - { - return false; - } - - return $this->_rootDir . '/' . str_replace(array('_', '\\'), '/', $class) . '.php'; - } - - public function getRootDir() - { - return $this->_rootDir; - } - - public static final function getInstance() - { - if (!self::$_instance) - { - self::$_instance = new self(); - } - - return self::$_instance; - } - - public static function setInstance(ZendLoader $loader = null) - { - self::$_instance = $loader; - } -} \ No newline at end of file From c69eec1b41f2d7bb66d0f16518df2c99dcdc2869 Mon Sep 17 00:00:00 2001 From: Exile Date: Wed, 26 Nov 2014 02:33:25 +0300 Subject: [PATCH 32/32] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE?= =?UTF-8?q?=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Окончательное подключение ZF2, ошибки с редиректом, редирект если нет такой темы, проблемы старого аттач-мода. Нужно выложить 4 ALPHA-билд. --- common.php | 6 ++++-- library/attach_mod/posting_attachments.php | 2 +- library/config.php | 2 +- library/includes/ucp/topic_watch.php | 2 +- viewtopic.php | 1 + 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/common.php b/common.php index cf0bfb2ab..0bf328a70 100644 --- a/common.php +++ b/common.php @@ -20,8 +20,10 @@ header('X-Frame-Options: SAMEORIGIN'); require(BB_ROOT . 'library/config.php'); // Load Zend Framework -require_once(BB_ROOT . 'library/Zend/Loader/AutoloaderFactory.php'); -Zend\Loader\AutoloaderFactory::factory(array()); +use Zend\Loader\StandardAutoloader; +require(BB_ROOT . 'library/Zend/Loader/StandardAutoloader.php'); +$loader = new StandardAutoloader(array('autoregister_zf' => true)); +$loader->register(); $server_protocol = ($bb_cfg['cookie_secure']) ? 'https://' : 'http://'; $server_port = (in_array($bb_cfg['server_port'], array(80, 443))) ? '' : ':' . $bb_cfg['server_port']; diff --git a/library/attach_mod/posting_attachments.php b/library/attach_mod/posting_attachments.php index df5091e0d..368706b3a 100644 --- a/library/attach_mod/posting_attachments.php +++ b/library/attach_mod/posting_attachments.php @@ -972,7 +972,7 @@ class attach_parent $this->attach_filename = str_replace(array(',', '.', '!', '?', 'ь', 'Ь', 'ц', 'Ц', 'д', 'Д', ';', ':', '@', "'", '"', '&'), array('', '', '', '', 'ue', 'ue', 'oe', 'oe', 'ae', 'ae', '', '', '', '', '', 'and'), $this->attach_filename); $this->attach_filename = str_replace(array('$', 'Я', '>','<','§','%','=','/','(',')','#','*','+',"\\",'{','}','[',']'), array('dollar', 'ss','greater','lower','paragraph','percent','equal','','','','','','','','','','',''), $this->attach_filename); // Remove non-latin characters - $this->attach_filename = preg_replace("/([\xC2\xC3])([\x80-\xBF])/e", "chr(ord('\\1')<<6&0xC0|ord('\\2')&0x3F)", $this->attach_filename); + $this->attach_filename = preg_replace('#([\xC2\xC3])([\x80-\xBF])#', 'chr(ord(\'$1\')<<6&0xC0|ord(\'$2\')&0x3F)', $this->attach_filename); $this->attach_filename = rawurlencode($this->attach_filename); $this->attach_filename = preg_replace("/(%[0-9A-F]{1,2})/i", '', $this->attach_filename); $this->attach_filename = trim($this->attach_filename); diff --git a/library/config.php b/library/config.php index a12591131..2e7d35932 100644 --- a/library/config.php +++ b/library/config.php @@ -73,7 +73,7 @@ $domain_name = (!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : $do // Version info $bb_cfg['tp_version'] = '2.1.4'; -$bb_cfg['tp_release_date'] = '**-11-2014'; +$bb_cfg['tp_release_date'] = '26-11-2014'; $bb_cfg['tp_release_state'] = 'ALPHA'; $bb_cfg['tp_zf_version'] = '2.3.3'; diff --git a/library/includes/ucp/topic_watch.php b/library/includes/ucp/topic_watch.php index 593f27bee..4fad6c02b 100644 --- a/library/includes/ucp/topic_watch.php +++ b/library/includes/ucp/topic_watch.php @@ -93,7 +93,7 @@ if ($watch_count > 0) } else { - meta_refresh(BB_ROOT, '3'); + meta_refresh('index.php', 3); bb_die($lang['NO_WATCHED_TOPICS']); } diff --git a/viewtopic.php b/viewtopic.php index 2799cecc2..e33d91124 100644 --- a/viewtopic.php +++ b/viewtopic.php @@ -114,6 +114,7 @@ else if (!$t_data = DB()->fetch_row($sql)) { + meta_refresh('index.php' , 10); bb_die($lang['TOPIC_POST_NOT_EXIST']); }