diff --git a/.cache/templates/.htaccess b/.cache/templates/.htaccess new file mode 100644 index 0000000..e67301e --- /dev/null +++ b/.cache/templates/.htaccess @@ -0,0 +1,4 @@ + +Order Allow,Deny +Deny from All + diff --git a/.cache/templates/wowhead/.htaccess b/.cache/templates/wowhead/.htaccess new file mode 100644 index 0000000..e67301e --- /dev/null +++ b/.cache/templates/wowhead/.htaccess @@ -0,0 +1,4 @@ + +Order Allow,Deny +Deny from All + diff --git a/.cache/world/.htaccess b/.cache/world/.htaccess new file mode 100644 index 0000000..e67301e --- /dev/null +++ b/.cache/world/.htaccess @@ -0,0 +1,4 @@ + +Order Allow,Deny +Deny from All + diff --git a/.gitignore b/.gitignore index 447728f..3eabc70 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,9 @@ # List of files and directories not to include in the repository. + +# Application configuration +configs/config.php + +# Cache +.cache/world/*.aww +.cache/templates/wowhead/%%*.php +/.cache/ \ No newline at end of file diff --git a/LICENSE.mdown b/LICENSE.mdown new file mode 100644 index 0000000..399c9d7 --- /dev/null +++ b/LICENSE.mdown @@ -0,0 +1,31 @@ +LEGAL NOTICE +------------ + +**mangos-zero-database** is released under the GPL v3. + +The terms and conditions of this license are described below: + + Copyright (C) 2011 mangos foundation + + mangos-zero-database is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +This file (`LICENSE.mdown`) **must** be apart of any redistributable packages +made from this software. No licenses should be removed from this software if +you are making redistributable copies. + + +CONTENT COPYRIGHT +----------------- +Game content is Copyright © 2004-2011 Blizzard Entertainment. Other works in +this repository is of authorship © 2005-2011 *mangos foundation*. diff --git a/account.php b/account.php new file mode 100644 index 0000000..1e66e2d --- /dev/null +++ b/account.php @@ -0,0 +1,108 @@ +config_load($conf_file, 'account'); + +// Создание аккаунта +if (($_REQUEST['account'] == 'signup') and (isset($_POST['username'])) and (isset($_POST['password'])) and (isset($_POST['c_password'])) and ($UDWBaseconf['register'] == true)) { + // Совпадают ли введенные пароли? + if ($_POST['password'] != $_POST['c_password']) { + $smarty->assign('signup_error', $smarty->get_config_vars('Different_passwords')); + } else { + // Существует ли уже такой пользователь? + if ($rDB->selectCell('SELECT Count(id) FROM ?_account WHERE username=? LIMIT 1', $_POST['username']) == 1) { + $smarty->assign('signup_error', $smarty->get_config_vars('Such_user_exists')); + } else { + // Вроде все нормально, создаем аккаунт + $success = $rDB->selectCell('INSERT INTO ?_account(`username`, `sha_pass_hash`, `email`, `joindate`, `expansion`, `last_ip`) + VALUES (?, ?, ?, NOW(), ?, ?)', $_POST['username'], create_usersend_pass($_POST['username'], $_POST['password']), (isset($_POST['email'])) ? $_POST['email'] : '', $UDWBaseconf['expansion'], (isset($_SERVER["REMOTE_ADDR"])) ? $_SERVER["REMOTE_ADDR"] : '' + ); + if ($success > 0) { + // Все отлично, авторизуем + $_REQUEST['account'] = 'signin'; + } else { + // Неизвестная ошибка + $smarty->assign('signup_error', $smarty->get_config_vars('Unknow_error_on_account_create')); + } + } + } +} + +if (($_REQUEST['account'] == 'signin') and (isset($_POST['username'])) and (isset($_POST['password']))) { + //$usersend_pass = create_usersend_pass($_POST['username'], $_POST['password']); + $shapass = $_POST['password']; + $user = CheckPwd($_POST['username'], $shapass); + if ($user == -1) { + del_user_cookie(); + if (isset($_SESSION['username'])) + UnSet($_SESSION['username']); + $smarty->assign('signin_error', $smarty->get_config_vars('Such_user_doesnt_exists')); + } elseif ($user == 0) { + del_user_cookie(); + if (isset($_SESSION['username'])) + UnSet($_SESSION['username']); + $smarty->assign('signin_error', $smarty->get_config_vars('Wrong_password')); + } else { + // Имя пользователя и пароль совпадают + $_SESSION['username'] = $user['name']; + $_SESSION['shapass'] = $shapass; + $_REQUEST['account'] = 'signin_true'; + $_POST['remember_me'] = (IsSet($_POST['remember_me'])) ? $_POST['remember_me'] : 'no'; + if ($_POST['remember_me'] == 'yes') { + // Запоминаем пользователя + $remember_time = time() + 3000000; + SetCookie('remember_me', $_POST['username'] . $shapass, $remember_time); + } else { + del_user_cookie(); + } + } +} + + +switch ($_REQUEST['account']): + case '': + // TODO: Настройки аккаунта (Account Settings) + break; + case 'signin_false': + case 'signin': + // Вход в систему + $smarty->assign('register', $UDWBaseconf['register']); + $smarty->display('signin.tpl'); + break; + case 'signup_false': + case 'signup': + // You can change to your realm page + //header( 'Location: http://your_realm_regpage' ); + $smarty->display('signup.tpl'); + break; + break; + case 'signout': + // Выход из пользователя + UnSet($user); + session_unset(); + session_destroy(); + $_SESSION = array(); + del_user_cookie(); + case 'signin_true': + default: + // На предыдущую страницу + // Срабатывает при: + // 1. $_REQUEST['account'] = 'signout' (выход) + // 2. $_REQUEST['account'] = 'signok' (успешная авторизация) + // 3. Неизвестное значение $_REQUEST['account'] + $_REQUEST['next'] = (IsSet($_REQUEST['next'])) ? $_REQUEST['next'] : ''; + if (($_REQUEST['next'] == '?account=signin') or ($_REQUEST['next'] == '?account=signup')) + $_REQUEST['next'] = ''; + header('Location: ?' . $_REQUEST['next']); + break; +endswitch; \ No newline at end of file diff --git a/ajax.php b/ajax.php new file mode 100644 index 0000000..83cf365 --- /dev/null +++ b/ajax.php @@ -0,0 +1,94 @@ + '\\\\', "'" => "\\'", '"' => '\\"', "\r" => '\\r', "\n" => '\\n', ' '<\/')); +} + +// Параметры передаваемые скрипту +@list($what, $id) = explode("=", $_SERVER['QUERY_STRING']); +$id = intval($id); + +$x = ''; + +switch ($what) { + case 'item': + if (!$item = load_cache(6, $id)) { + require_once('includes/allitems.php'); + $item = allitemsinfo($id, 1); + save_cache(6, $id, $item); + } + $x .= '$WowheadPower.registerItem(' . $id . ', 0, {'; + if ($item['name']) + $x .= 'name: \'' . str_normalize($item['name']) . '\','; + if ($item['quality']) + $x .= 'quality: ' . $item['quality'] . ','; + if ($item['icon']) + $x .= 'icon: \'' . str_normalize($item['icon']) . '\','; + if ($item['info']) + $x .= 'tooltip: \'' . str_normalize($item['info']) . '\''; + $x .= '});'; + break; + case 'spell': + if (!$spell = load_cache(14, $id)) { + require_once('includes/allspells.php'); + $spell = allspellsinfo($id, 1); + save_cache(14, $id, $spell); + } + $x .= '$WowheadPower.registerSpell(' . $id . ', 0,{'; + if ($spell['name']) + $x .= 'name: \'' . str_normalize($spell['name']) . '\','; + if ($spell['icon']) + $x .= 'icon: \'' . str_normalize($spell['icon']) . '\','; + if ($spell['info']) + $x .= 'tooltip: \'' . str_normalize($spell['info']) . '\''; + $x .= '});'; + break; + case 'quest': + if (!$quest = load_cache(11, $id)) { + require_once('includes/allquests.php'); + $quest = GetDBQuestInfo($id, QUEST_DATAFLAG_AJAXTOOLTIP); + $quest['tooltip'] = GetQuestTooltip($quest); + save_cache(11, $id, $quest); + } + $x .= '$WowheadPower.registerQuest(' . $id . ', 0,{'; + if ($quest['name']) + $x .= 'name: \'' . str_normalize($quest['name']) . '\','; + if ($quest['tooltip']) + $x .= 'tooltip: \'' . str_normalize($quest['tooltip']) . '\''; + $x .= '});'; + break; + default: + break; +} + +echo $x; \ No newline at end of file diff --git a/comment.php b/comment.php new file mode 100644 index 0000000..bff9b0b --- /dev/null +++ b/comment.php @@ -0,0 +1,73 @@ +query('INSERT + INTO ?_aowow_comments(`type`, `typeid`, `userid`, `commentbody`, `post_date`{, ?#}) + VALUES (?d, ?d, ?d, ?, NOW(){, ?d})', (empty($_POST['replyto']) ? DBSIMPLE_SKIP : 'replyto'), $_GET["type"], $_GET["typeid"], (empty($_SESSION['userid']) ? 0 : $_SESSION['userid']), stripslashes($_POST['commentbody']), (empty($_POST['replyto']) ? DBSIMPLE_SKIP : $_POST['replyto']) + ); + if (empty($_POST['replyto'])) + $DB->query('UPDATE ?_aowow_comments SET `replyto`=?d WHERE `id`=?d LIMIT 1', $newid, $newid); + echo ''; + echo ''; + break; + case 'delete': + // Удаление комментарий (Ajax) + // Номер комментария: $_GET['id'] + // Имя пользователя, удаляющего комментарий: $_GET['username'] + $DB->query('DELETE FROM ?_aowow_comments WHERE `id`=?d {AND `userid`=?d} LIMIT 1', $_GET['id'], ($_SESSION['roles'] > 1) ? DBSIMPLE_SKIP : $_SESSION['userid'] + ); + break; + case 'edit': + // Редактирование комментария + // Номер комментария: $_GET['id'] + // Новое содержание комментария: $_POST['body'] + // Номер пользователя: $_SESSION['userid'] + if (IsSet($_POST['body'])) + $DB->query('UPDATE ?_aowow_comments SET `commentbody`=?, `edit_userid`=?, `edit_date`=NOW() WHERE `id`=?d {AND `userid`=?d} LIMIT 1', stripslashes($_POST['body']), $_SESSION['userid'], $_GET['id'], ($_SESSION['roles'] > 1) ? DBSIMPLE_SKIP : $_SESSION['userid'] + ); + echo $_POST['body']; + break; + case 'rate': + /* + * Установка собственоого рейтинга (модераторы и т.п.) + * Номер комментария: $_GET['id'] + * Новое значение рейтинга: $_GET['rating'] + * Номер пользователя: $_SESSION['userid'] + */ + // Проверка на хоть какое то значение рейтинга, и на то, что пользователь за этот коммент не голосовал + if (IsSet($_GET['rating']) and !($DB->selectCell('SELECT `commentid` FROM ?_aowow_comments_rates WHERE `userid`=?d AND `commentid`=?d LIMIT 1', $_SESSION['userid'], $_GET['id']))) + $DB->query('INSERT INTO ?_aowow_comments_rates(`commentid`, `userid`, `rate`) VALUES (?d, ?d, ?d)', $_GET['id'], $_SESSION['userid'], $_GET['rating']); + break; + case 'undelete': + // Восстановление комментария + // Номер комментария: $_GET['id'] + // Имя пользователя, удаляющего комментарий: $_GET['username'] + default: + break; +endswitch; \ No newline at end of file diff --git a/configs/.htaccess b/configs/.htaccess new file mode 100644 index 0000000..e67301e --- /dev/null +++ b/configs/.htaccess @@ -0,0 +1,4 @@ + +Order Allow,Deny +Deny from All + diff --git a/configs/config.php.in b/configs/config.php.in new file mode 100644 index 0000000..bd1da0b --- /dev/null +++ b/configs/config.php.in @@ -0,0 +1,34 @@ +config_load($conf_file, 'faction'); + +// Номер фракции +$id = $podrazdel; + +if (!$faction = load_cache(18, intval($id))) { + unset($faction); + + // Подключаемся к ДБ: + global $DB; + + $row = $DB->selectRow(' + SELECT factionID, name_loc' . $_SESSION['locale'] . ', description1_loc' . $_SESSION['locale'] . ', description2_loc' . $_SESSION['locale'] . ', team, side + FROM ?_aowow_factions + WHERE factionID=?d + LIMIT 1 + ', $id + ); + if ($row) { + $faction = array(); + // Номер фракции + $faction['entry'] = $row['factionID']; + // Название фракции + $faction['name'] = $row['name_loc' . $_SESSION['locale']]; + // Описание фракции, из клиента: + $faction['description1'] = $row['description1_loc' . $_SESSION['locale']]; + // Описание фракции, c wowwiki.com, находится в таблице factions.sql: + $faction['description2'] = $row['description2_loc' . $_SESSION['locale']]; + // Команда/Группа фракции + if ($row['team'] != 0) + $faction['group'] = $DB->selectCell('SELECT name_loc' . $_SESSION['locale'] . ' FROM ?_aowow_factions WHERE factionID=?d LIMIT 1', $row['team']); + // Альянс(1)/Орда(2) + if ($row['side'] != 0) + $faction['side'] = $row['side']; + + // Итемы с requiredreputationfaction + $item_rows = $DB->select(' + SELECT ?#, entry + FROM ?_item_template i, ?_aowow_icons a + WHERE + i.RequiredReputationFaction=?d + AND a.id=i.displayid + ', $item_cols[2], $id + ); + if ($item_rows) { + $faction['items'] = array(); + foreach ($item_rows as $i => $row) + $faction['items'][] = iteminfo2($row, 0); + unset($faction['items']); + } + + // Персонажи, состоящие во фракции + $creature_rows = $DB->select(' + SELECT ?#, entry + FROM ?_creature_template, ?_aowow_factiontemplate + WHERE + faction_A IN (SELECT factiontemplateID FROM ?_aowow_factiontemplate WHERE factionID=?d) + AND factiontemplateID=faction_A + ', $npc_cols[0], $id + ); + if ($creature_rows) { + $faction['creatures'] = array(); + foreach ($creature_rows as $i => $row) + $faction['creatures'][] = creatureinfo2($row); + unset($creature_rows); + } + + // Квесты для этой фракции + $quests_rows = $DB->select(' + SELECT ?# + FROM ?_quest_template + WHERE + RewRepFaction1=?d + OR RewRepFaction2=?d + OR RewRepFaction3=?d + OR RewRepFaction4=?d + ', $quest_cols[2], $id, $id, $id, $id + ); + if ($quests_rows) { + $faction['quests'] = array(); + foreach ($quests_rows as $i => $row) + $faction['quests'][] = GetQuestInfo($row, 0xFFFFFF); + unset($quests_rows); + } + + // Faction cache + save_cache(18, $faction['entry'], $faction); + } +} + +$page = array( + 'Mapper' => false, + 'Book' => false, + 'Title' => $faction['name'] . ' - ' . $smarty->get_config_vars('Factions'), + 'tab' => 0, + 'type' => 8, + 'typeid' => $faction['entry'], + 'path' => '[0, 7, 0]' +); +$smarty->assign('page', $page); + +// Комментарии +$smarty->assign('comments', getcomments($page['type'], $page['typeid'])); + +// Данные о квесте +$smarty->assign('faction', $faction); +// Если хоть одна информация о вещи найдена - передаём массив с информацией о вещях шаблонизатору +if (isset($allitems)) + $smarty->assign('allitems', $allitems); +/* + if (isset($npcs)) + $smarty->assign('npcs',$npcs); + if (isset($quests)) + $smarty->assign('quests',$quests); + if (isset($items)) + $smarty->assign('items',$items); + */ +// Количество MySQL запросов +$smarty->assign('mysql', $DB->getStatistics()); +// Загружаем страницу +$smarty->display('faction.tpl'); \ No newline at end of file diff --git a/factions.php b/factions.php new file mode 100644 index 0000000..067b679 --- /dev/null +++ b/factions.php @@ -0,0 +1,56 @@ +config_load($conf_file, 'factions'); + +global $DB; + +$rows = $DB->select(' + SELECT factionID, team, name_loc' . $_SESSION['locale'] . ' as name, side + FROM ?_aowow_factions + WHERE + reputationListID!=-1 + ' +); +if (!$factions = load_cache(19, 'x')) { + unset($factions); + + $factions = array(); + foreach ($rows as $numRow => $row) { + $factions[$numRow] = array(); + $factions[$numRow]['entry'] = $row['factionID']; + if ($row['team'] != 0) + $factions[$numRow]['group'] = $DB->selectCell('SELECT name_loc' . $_SESSION['locale'] . ' FROM ?_aowow_factions WHERE factionID=? LIMIT 1', $row['team']); + if ($row['side']) + $factions[$numRow]['side'] = $row['side']; + $factions[$numRow]['name'] = $row['name']; + } + save_cache(19, 'x', $factions); +} + +global $page; +$page = array( + 'Mapper' => false, + 'Book' => false, + 'Title' => $smarty->get_config_vars('Factions'), + 'tab' => 0, + 'type' => 0, + 'typeid' => 0, + 'path' => '[0, 7]' +); +$smarty->assign('page', $page); + +// Статистика выполнения mysql запросов +$smarty->assign('mysql', $DB->getStatistics()); +$smarty->assign('factions', $factions); +// Загружаем страницу +$smarty->display('factions.tpl'); \ No newline at end of file diff --git a/forum.php b/forum.php new file mode 100644 index 0000000..621039a --- /dev/null +++ b/forum.php @@ -0,0 +1,41 @@ +.. diff --git a/images/maps/enus/normal/-1.jpg b/images/maps/enus/normal/-1.jpg new file mode 100644 index 0000000..82eef75 Binary files /dev/null and b/images/maps/enus/normal/-1.jpg differ diff --git a/images/maps/enus/normal/-2.jpg b/images/maps/enus/normal/-2.jpg new file mode 100644 index 0000000..b2e8148 Binary files /dev/null and b/images/maps/enus/normal/-2.jpg differ diff --git a/images/maps/enus/normal/-3.jpg b/images/maps/enus/normal/-3.jpg new file mode 100644 index 0000000..95a0f93 Binary files /dev/null and b/images/maps/enus/normal/-3.jpg differ diff --git a/images/maps/enus/normal/-4.jpg b/images/maps/enus/normal/-4.jpg new file mode 100644 index 0000000..db52c00 Binary files /dev/null and b/images/maps/enus/normal/-4.jpg differ diff --git a/images/maps/enus/normal/1.jpg b/images/maps/enus/normal/1.jpg new file mode 100644 index 0000000..6d5eff7 Binary files /dev/null and b/images/maps/enus/normal/1.jpg differ diff --git a/images/maps/enus/normal/10.jpg b/images/maps/enus/normal/10.jpg new file mode 100644 index 0000000..dbc2e61 Binary files /dev/null and b/images/maps/enus/normal/10.jpg differ diff --git a/images/maps/enus/normal/11.jpg b/images/maps/enus/normal/11.jpg new file mode 100644 index 0000000..24b5584 Binary files /dev/null and b/images/maps/enus/normal/11.jpg differ diff --git a/images/maps/enus/normal/12.jpg b/images/maps/enus/normal/12.jpg new file mode 100644 index 0000000..b876188 Binary files /dev/null and b/images/maps/enus/normal/12.jpg differ diff --git a/images/maps/enus/normal/130.jpg b/images/maps/enus/normal/130.jpg new file mode 100644 index 0000000..0e4150a Binary files /dev/null and b/images/maps/enus/normal/130.jpg differ diff --git a/images/maps/enus/normal/133.jpg b/images/maps/enus/normal/133.jpg new file mode 100644 index 0000000..afbbcd5 Binary files /dev/null and b/images/maps/enus/normal/133.jpg differ diff --git a/images/maps/enus/normal/1337.jpg b/images/maps/enus/normal/1337.jpg new file mode 100644 index 0000000..04ed789 Binary files /dev/null and b/images/maps/enus/normal/1337.jpg differ diff --git a/images/maps/enus/normal/1377.jpg b/images/maps/enus/normal/1377.jpg new file mode 100644 index 0000000..551fbc8 Binary files /dev/null and b/images/maps/enus/normal/1377.jpg differ diff --git a/images/maps/enus/normal/139.jpg b/images/maps/enus/normal/139.jpg new file mode 100644 index 0000000..74f2229 Binary files /dev/null and b/images/maps/enus/normal/139.jpg differ diff --git a/images/maps/enus/normal/14.jpg b/images/maps/enus/normal/14.jpg new file mode 100644 index 0000000..e7e57da Binary files /dev/null and b/images/maps/enus/normal/14.jpg differ diff --git a/images/maps/enus/normal/141.jpg b/images/maps/enus/normal/141.jpg new file mode 100644 index 0000000..792ea23 Binary files /dev/null and b/images/maps/enus/normal/141.jpg differ diff --git a/images/maps/enus/normal/1417.jpg b/images/maps/enus/normal/1417.jpg new file mode 100644 index 0000000..f98ee9b Binary files /dev/null and b/images/maps/enus/normal/1417.jpg differ diff --git a/images/maps/enus/normal/148.jpg b/images/maps/enus/normal/148.jpg new file mode 100644 index 0000000..fdb2975 Binary files /dev/null and b/images/maps/enus/normal/148.jpg differ diff --git a/images/maps/enus/normal/1497.jpg b/images/maps/enus/normal/1497.jpg new file mode 100644 index 0000000..da4ae2c Binary files /dev/null and b/images/maps/enus/normal/1497.jpg differ diff --git a/images/maps/enus/normal/15.jpg b/images/maps/enus/normal/15.jpg new file mode 100644 index 0000000..50a4581 Binary files /dev/null and b/images/maps/enus/normal/15.jpg differ diff --git a/images/maps/enus/normal/1519.jpg b/images/maps/enus/normal/1519.jpg new file mode 100644 index 0000000..f6d785d Binary files /dev/null and b/images/maps/enus/normal/1519.jpg differ diff --git a/images/maps/enus/normal/1537.jpg b/images/maps/enus/normal/1537.jpg new file mode 100644 index 0000000..84dd6ca Binary files /dev/null and b/images/maps/enus/normal/1537.jpg differ diff --git a/images/maps/enus/normal/1583b.jpg b/images/maps/enus/normal/1583b.jpg new file mode 100644 index 0000000..10fb249 Binary files /dev/null and b/images/maps/enus/normal/1583b.jpg differ diff --git a/images/maps/enus/normal/1584.jpg b/images/maps/enus/normal/1584.jpg new file mode 100644 index 0000000..fb61269 Binary files /dev/null and b/images/maps/enus/normal/1584.jpg differ diff --git a/images/maps/enus/normal/16.jpg b/images/maps/enus/normal/16.jpg new file mode 100644 index 0000000..c304ea2 Binary files /dev/null and b/images/maps/enus/normal/16.jpg differ diff --git a/images/maps/enus/normal/1637.jpg b/images/maps/enus/normal/1637.jpg new file mode 100644 index 0000000..89dcf11 Binary files /dev/null and b/images/maps/enus/normal/1637.jpg differ diff --git a/images/maps/enus/normal/1638.jpg b/images/maps/enus/normal/1638.jpg new file mode 100644 index 0000000..c02a94c Binary files /dev/null and b/images/maps/enus/normal/1638.jpg differ diff --git a/images/maps/enus/normal/1657.jpg b/images/maps/enus/normal/1657.jpg new file mode 100644 index 0000000..49491ae Binary files /dev/null and b/images/maps/enus/normal/1657.jpg differ diff --git a/images/maps/enus/normal/17.jpg b/images/maps/enus/normal/17.jpg new file mode 100644 index 0000000..a31e325 Binary files /dev/null and b/images/maps/enus/normal/17.jpg differ diff --git a/images/maps/enus/normal/19.jpg b/images/maps/enus/normal/19.jpg new file mode 100644 index 0000000..375bc81 Binary files /dev/null and b/images/maps/enus/normal/19.jpg differ diff --git a/images/maps/enus/normal/2017.jpg b/images/maps/enus/normal/2017.jpg new file mode 100644 index 0000000..c21deb4 Binary files /dev/null and b/images/maps/enus/normal/2017.jpg differ diff --git a/images/maps/enus/normal/2057.jpg b/images/maps/enus/normal/2057.jpg new file mode 100644 index 0000000..beeb7f2 Binary files /dev/null and b/images/maps/enus/normal/2057.jpg differ diff --git a/images/maps/enus/normal/2100.jpg b/images/maps/enus/normal/2100.jpg new file mode 100644 index 0000000..8f48d6a Binary files /dev/null and b/images/maps/enus/normal/2100.jpg differ diff --git a/images/maps/enus/normal/215.jpg b/images/maps/enus/normal/215.jpg new file mode 100644 index 0000000..cc8d265 Binary files /dev/null and b/images/maps/enus/normal/215.jpg differ diff --git a/images/maps/enus/normal/2159.jpg b/images/maps/enus/normal/2159.jpg new file mode 100644 index 0000000..03eca32 Binary files /dev/null and b/images/maps/enus/normal/2159.jpg differ diff --git a/images/maps/enus/normal/2366.jpg b/images/maps/enus/normal/2366.jpg new file mode 100644 index 0000000..50acfdd Binary files /dev/null and b/images/maps/enus/normal/2366.jpg differ diff --git a/images/maps/enus/normal/2367.jpg b/images/maps/enus/normal/2367.jpg new file mode 100644 index 0000000..d11eae0 Binary files /dev/null and b/images/maps/enus/normal/2367.jpg differ diff --git a/images/maps/enus/normal/2437.jpg b/images/maps/enus/normal/2437.jpg new file mode 100644 index 0000000..3a38d3b Binary files /dev/null and b/images/maps/enus/normal/2437.jpg differ diff --git a/images/maps/enus/normal/2557.jpg b/images/maps/enus/normal/2557.jpg new file mode 100644 index 0000000..ece4a5a Binary files /dev/null and b/images/maps/enus/normal/2557.jpg differ diff --git a/images/maps/enus/normal/2557e.jpg b/images/maps/enus/normal/2557e.jpg new file mode 100644 index 0000000..9ee279b Binary files /dev/null and b/images/maps/enus/normal/2557e.jpg differ diff --git a/images/maps/enus/normal/2557n.jpg b/images/maps/enus/normal/2557n.jpg new file mode 100644 index 0000000..d2bc397 Binary files /dev/null and b/images/maps/enus/normal/2557n.jpg differ diff --git a/images/maps/enus/normal/2557w.jpg b/images/maps/enus/normal/2557w.jpg new file mode 100644 index 0000000..4b7915f Binary files /dev/null and b/images/maps/enus/normal/2557w.jpg differ diff --git a/images/maps/enus/normal/2597.jpg b/images/maps/enus/normal/2597.jpg new file mode 100644 index 0000000..46bcf61 Binary files /dev/null and b/images/maps/enus/normal/2597.jpg differ diff --git a/images/maps/enus/normal/267.jpg b/images/maps/enus/normal/267.jpg new file mode 100644 index 0000000..a771831 Binary files /dev/null and b/images/maps/enus/normal/267.jpg differ diff --git a/images/maps/enus/normal/2717.jpg b/images/maps/enus/normal/2717.jpg new file mode 100644 index 0000000..a9f335a Binary files /dev/null and b/images/maps/enus/normal/2717.jpg differ diff --git a/images/maps/enus/normal/28.jpg b/images/maps/enus/normal/28.jpg new file mode 100644 index 0000000..9ee41b2 Binary files /dev/null and b/images/maps/enus/normal/28.jpg differ diff --git a/images/maps/enus/normal/3.jpg b/images/maps/enus/normal/3.jpg new file mode 100644 index 0000000..b71e165 Binary files /dev/null and b/images/maps/enus/normal/3.jpg differ diff --git a/images/maps/enus/normal/3277.jpg b/images/maps/enus/normal/3277.jpg new file mode 100644 index 0000000..f047bd1 Binary files /dev/null and b/images/maps/enus/normal/3277.jpg differ diff --git a/images/maps/enus/normal/33.jpg b/images/maps/enus/normal/33.jpg new file mode 100644 index 0000000..7ee1b82 Binary files /dev/null and b/images/maps/enus/normal/33.jpg differ diff --git a/images/maps/enus/normal/331.jpg b/images/maps/enus/normal/331.jpg new file mode 100644 index 0000000..8a11074 Binary files /dev/null and b/images/maps/enus/normal/331.jpg differ diff --git a/images/maps/enus/normal/3358.jpg b/images/maps/enus/normal/3358.jpg new file mode 100644 index 0000000..837ceb4 Binary files /dev/null and b/images/maps/enus/normal/3358.jpg differ diff --git a/images/maps/enus/normal/3428.jpg b/images/maps/enus/normal/3428.jpg new file mode 100644 index 0000000..f3397ce Binary files /dev/null and b/images/maps/enus/normal/3428.jpg differ diff --git a/images/maps/enus/normal/3429.jpg b/images/maps/enus/normal/3429.jpg new file mode 100644 index 0000000..995dee4 Binary files /dev/null and b/images/maps/enus/normal/3429.jpg differ diff --git a/images/maps/enus/normal/3430.jpg b/images/maps/enus/normal/3430.jpg new file mode 100644 index 0000000..69fadd3 Binary files /dev/null and b/images/maps/enus/normal/3430.jpg differ diff --git a/images/maps/enus/normal/3433.jpg b/images/maps/enus/normal/3433.jpg new file mode 100644 index 0000000..104d618 Binary files /dev/null and b/images/maps/enus/normal/3433.jpg differ diff --git a/images/maps/enus/normal/3456.jpg b/images/maps/enus/normal/3456.jpg new file mode 100644 index 0000000..f240ab2 Binary files /dev/null and b/images/maps/enus/normal/3456.jpg differ diff --git a/images/maps/enus/normal/3483.jpg b/images/maps/enus/normal/3483.jpg new file mode 100644 index 0000000..8c1ca48 Binary files /dev/null and b/images/maps/enus/normal/3483.jpg differ diff --git a/images/maps/enus/normal/3487.jpg b/images/maps/enus/normal/3487.jpg new file mode 100644 index 0000000..e1350a5 Binary files /dev/null and b/images/maps/enus/normal/3487.jpg differ diff --git a/images/maps/enus/normal/3518.jpg b/images/maps/enus/normal/3518.jpg new file mode 100644 index 0000000..131eb4c Binary files /dev/null and b/images/maps/enus/normal/3518.jpg differ diff --git a/images/maps/enus/normal/3519.jpg b/images/maps/enus/normal/3519.jpg new file mode 100644 index 0000000..750502c Binary files /dev/null and b/images/maps/enus/normal/3519.jpg differ diff --git a/images/maps/enus/normal/3520.jpg b/images/maps/enus/normal/3520.jpg new file mode 100644 index 0000000..1cf6c55 Binary files /dev/null and b/images/maps/enus/normal/3520.jpg differ diff --git a/images/maps/enus/normal/3521.jpg b/images/maps/enus/normal/3521.jpg new file mode 100644 index 0000000..ae87856 Binary files /dev/null and b/images/maps/enus/normal/3521.jpg differ diff --git a/images/maps/enus/normal/3522.jpg b/images/maps/enus/normal/3522.jpg new file mode 100644 index 0000000..5d1997e Binary files /dev/null and b/images/maps/enus/normal/3522.jpg differ diff --git a/images/maps/enus/normal/3523.jpg b/images/maps/enus/normal/3523.jpg new file mode 100644 index 0000000..e7476d5 Binary files /dev/null and b/images/maps/enus/normal/3523.jpg differ diff --git a/images/maps/enus/normal/3524.jpg b/images/maps/enus/normal/3524.jpg new file mode 100644 index 0000000..63ebc69 Binary files /dev/null and b/images/maps/enus/normal/3524.jpg differ diff --git a/images/maps/enus/normal/3525.jpg b/images/maps/enus/normal/3525.jpg new file mode 100644 index 0000000..cbf12b2 Binary files /dev/null and b/images/maps/enus/normal/3525.jpg differ diff --git a/images/maps/enus/normal/3557.jpg b/images/maps/enus/normal/3557.jpg new file mode 100644 index 0000000..49092c3 Binary files /dev/null and b/images/maps/enus/normal/3557.jpg differ diff --git a/images/maps/enus/normal/3562.jpg b/images/maps/enus/normal/3562.jpg new file mode 100644 index 0000000..8eaf28b Binary files /dev/null and b/images/maps/enus/normal/3562.jpg differ diff --git a/images/maps/enus/normal/357.jpg b/images/maps/enus/normal/357.jpg new file mode 100644 index 0000000..2736b3a Binary files /dev/null and b/images/maps/enus/normal/357.jpg differ diff --git a/images/maps/enus/normal/36.jpg b/images/maps/enus/normal/36.jpg new file mode 100644 index 0000000..1163a0f Binary files /dev/null and b/images/maps/enus/normal/36.jpg differ diff --git a/images/maps/enus/normal/3606.jpg b/images/maps/enus/normal/3606.jpg new file mode 100644 index 0000000..5e370e1 Binary files /dev/null and b/images/maps/enus/normal/3606.jpg differ diff --git a/images/maps/enus/normal/3607.jpg b/images/maps/enus/normal/3607.jpg new file mode 100644 index 0000000..2a4170d Binary files /dev/null and b/images/maps/enus/normal/3607.jpg differ diff --git a/images/maps/enus/normal/361.jpg b/images/maps/enus/normal/361.jpg new file mode 100644 index 0000000..96b773f Binary files /dev/null and b/images/maps/enus/normal/361.jpg differ diff --git a/images/maps/enus/normal/3618.jpg b/images/maps/enus/normal/3618.jpg new file mode 100644 index 0000000..ac6034f Binary files /dev/null and b/images/maps/enus/normal/3618.jpg differ diff --git a/images/maps/enus/normal/3703.jpg b/images/maps/enus/normal/3703.jpg new file mode 100644 index 0000000..afb6f45 Binary files /dev/null and b/images/maps/enus/normal/3703.jpg differ diff --git a/images/maps/enus/normal/3713.jpg b/images/maps/enus/normal/3713.jpg new file mode 100644 index 0000000..9e7233c Binary files /dev/null and b/images/maps/enus/normal/3713.jpg differ diff --git a/images/maps/enus/normal/3714.jpg b/images/maps/enus/normal/3714.jpg new file mode 100644 index 0000000..9daf0be Binary files /dev/null and b/images/maps/enus/normal/3714.jpg differ diff --git a/images/maps/enus/normal/3715.jpg b/images/maps/enus/normal/3715.jpg new file mode 100644 index 0000000..939b6bc Binary files /dev/null and b/images/maps/enus/normal/3715.jpg differ diff --git a/images/maps/enus/normal/3716.jpg b/images/maps/enus/normal/3716.jpg new file mode 100644 index 0000000..5bf7eda Binary files /dev/null and b/images/maps/enus/normal/3716.jpg differ diff --git a/images/maps/enus/normal/3717.jpg b/images/maps/enus/normal/3717.jpg new file mode 100644 index 0000000..16b65ab Binary files /dev/null and b/images/maps/enus/normal/3717.jpg differ diff --git a/images/maps/enus/normal/3789.jpg b/images/maps/enus/normal/3789.jpg new file mode 100644 index 0000000..eb2f8e8 Binary files /dev/null and b/images/maps/enus/normal/3789.jpg differ diff --git a/images/maps/enus/normal/3790.jpg b/images/maps/enus/normal/3790.jpg new file mode 100644 index 0000000..f6461e1 Binary files /dev/null and b/images/maps/enus/normal/3790.jpg differ diff --git a/images/maps/enus/normal/3791.jpg b/images/maps/enus/normal/3791.jpg new file mode 100644 index 0000000..1d6b7e8 Binary files /dev/null and b/images/maps/enus/normal/3791.jpg differ diff --git a/images/maps/enus/normal/3792.jpg b/images/maps/enus/normal/3792.jpg new file mode 100644 index 0000000..6f91a77 Binary files /dev/null and b/images/maps/enus/normal/3792.jpg differ diff --git a/images/maps/enus/normal/38.jpg b/images/maps/enus/normal/38.jpg new file mode 100644 index 0000000..cc940ff Binary files /dev/null and b/images/maps/enus/normal/38.jpg differ diff --git a/images/maps/enus/normal/3805.jpg b/images/maps/enus/normal/3805.jpg new file mode 100644 index 0000000..8852474 Binary files /dev/null and b/images/maps/enus/normal/3805.jpg differ diff --git a/images/maps/enus/normal/3820.jpg b/images/maps/enus/normal/3820.jpg new file mode 100644 index 0000000..21f0827 Binary files /dev/null and b/images/maps/enus/normal/3820.jpg differ diff --git a/images/maps/enus/normal/3836.jpg b/images/maps/enus/normal/3836.jpg new file mode 100644 index 0000000..a927afc Binary files /dev/null and b/images/maps/enus/normal/3836.jpg differ diff --git a/images/maps/enus/normal/3842.jpg b/images/maps/enus/normal/3842.jpg new file mode 100644 index 0000000..4df7364 Binary files /dev/null and b/images/maps/enus/normal/3842.jpg differ diff --git a/images/maps/enus/normal/3846.jpg b/images/maps/enus/normal/3846.jpg new file mode 100644 index 0000000..9791e0a Binary files /dev/null and b/images/maps/enus/normal/3846.jpg differ diff --git a/images/maps/enus/normal/3847.jpg b/images/maps/enus/normal/3847.jpg new file mode 100644 index 0000000..67a90be Binary files /dev/null and b/images/maps/enus/normal/3847.jpg differ diff --git a/images/maps/enus/normal/3849.jpg b/images/maps/enus/normal/3849.jpg new file mode 100644 index 0000000..caf47f1 Binary files /dev/null and b/images/maps/enus/normal/3849.jpg differ diff --git a/images/maps/enus/normal/3959.jpg b/images/maps/enus/normal/3959.jpg new file mode 100644 index 0000000..b48ed99 Binary files /dev/null and b/images/maps/enus/normal/3959.jpg differ diff --git a/images/maps/enus/normal/4.jpg b/images/maps/enus/normal/4.jpg new file mode 100644 index 0000000..0f35b99 Binary files /dev/null and b/images/maps/enus/normal/4.jpg differ diff --git a/images/maps/enus/normal/40.jpg b/images/maps/enus/normal/40.jpg new file mode 100644 index 0000000..1d8baf5 Binary files /dev/null and b/images/maps/enus/normal/40.jpg differ diff --git a/images/maps/enus/normal/400.jpg b/images/maps/enus/normal/400.jpg new file mode 100644 index 0000000..f13261b Binary files /dev/null and b/images/maps/enus/normal/400.jpg differ diff --git a/images/maps/enus/normal/405.jpg b/images/maps/enus/normal/405.jpg new file mode 100644 index 0000000..fa977cf Binary files /dev/null and b/images/maps/enus/normal/405.jpg differ diff --git a/images/maps/enus/normal/406.jpg b/images/maps/enus/normal/406.jpg new file mode 100644 index 0000000..59af91e Binary files /dev/null and b/images/maps/enus/normal/406.jpg differ diff --git a/images/maps/enus/normal/4080.jpg b/images/maps/enus/normal/4080.jpg new file mode 100644 index 0000000..ecaf7f9 Binary files /dev/null and b/images/maps/enus/normal/4080.jpg differ diff --git a/images/maps/enus/normal/4095.jpg b/images/maps/enus/normal/4095.jpg new file mode 100644 index 0000000..08dfd37 Binary files /dev/null and b/images/maps/enus/normal/4095.jpg differ diff --git a/images/maps/enus/normal/41.jpg b/images/maps/enus/normal/41.jpg new file mode 100644 index 0000000..c042f42 Binary files /dev/null and b/images/maps/enus/normal/41.jpg differ diff --git a/images/maps/enus/normal/44.jpg b/images/maps/enus/normal/44.jpg new file mode 100644 index 0000000..d3994bd Binary files /dev/null and b/images/maps/enus/normal/44.jpg differ diff --git a/images/maps/enus/normal/440.jpg b/images/maps/enus/normal/440.jpg new file mode 100644 index 0000000..22c0a70 Binary files /dev/null and b/images/maps/enus/normal/440.jpg differ diff --git a/images/maps/enus/normal/45.jpg b/images/maps/enus/normal/45.jpg new file mode 100644 index 0000000..72e9d9e Binary files /dev/null and b/images/maps/enus/normal/45.jpg differ diff --git a/images/maps/enus/normal/457.jpg b/images/maps/enus/normal/457.jpg new file mode 100644 index 0000000..089eca4 Binary files /dev/null and b/images/maps/enus/normal/457.jpg differ diff --git a/images/maps/enus/normal/46.jpg b/images/maps/enus/normal/46.jpg new file mode 100644 index 0000000..fb9dd83 Binary files /dev/null and b/images/maps/enus/normal/46.jpg differ diff --git a/images/maps/enus/normal/47.jpg b/images/maps/enus/normal/47.jpg new file mode 100644 index 0000000..360885d Binary files /dev/null and b/images/maps/enus/normal/47.jpg differ diff --git a/images/maps/enus/normal/490.jpg b/images/maps/enus/normal/490.jpg new file mode 100644 index 0000000..25bed51 Binary files /dev/null and b/images/maps/enus/normal/490.jpg differ diff --git a/images/maps/enus/normal/491.jpg b/images/maps/enus/normal/491.jpg new file mode 100644 index 0000000..0592d7e Binary files /dev/null and b/images/maps/enus/normal/491.jpg differ diff --git a/images/maps/enus/normal/493.jpg b/images/maps/enus/normal/493.jpg new file mode 100644 index 0000000..8c8f6f9 Binary files /dev/null and b/images/maps/enus/normal/493.jpg differ diff --git a/images/maps/enus/normal/51.jpg b/images/maps/enus/normal/51.jpg new file mode 100644 index 0000000..86798dc Binary files /dev/null and b/images/maps/enus/normal/51.jpg differ diff --git a/images/maps/enus/normal/618.jpg b/images/maps/enus/normal/618.jpg new file mode 100644 index 0000000..19b618d Binary files /dev/null and b/images/maps/enus/normal/618.jpg differ diff --git a/images/maps/enus/normal/717.jpg b/images/maps/enus/normal/717.jpg new file mode 100644 index 0000000..71c284a Binary files /dev/null and b/images/maps/enus/normal/717.jpg differ diff --git a/images/maps/enus/normal/718.jpg b/images/maps/enus/normal/718.jpg new file mode 100644 index 0000000..1e235f3 Binary files /dev/null and b/images/maps/enus/normal/718.jpg differ diff --git a/images/maps/enus/normal/719.jpg b/images/maps/enus/normal/719.jpg new file mode 100644 index 0000000..b59e02f Binary files /dev/null and b/images/maps/enus/normal/719.jpg differ diff --git a/images/maps/enus/normal/722.jpg b/images/maps/enus/normal/722.jpg new file mode 100644 index 0000000..b58fd56 Binary files /dev/null and b/images/maps/enus/normal/722.jpg differ diff --git a/images/maps/enus/normal/796.jpg b/images/maps/enus/normal/796.jpg new file mode 100644 index 0000000..8391991 Binary files /dev/null and b/images/maps/enus/normal/796.jpg differ diff --git a/images/maps/enus/normal/796a.jpg b/images/maps/enus/normal/796a.jpg new file mode 100644 index 0000000..3f5de94 Binary files /dev/null and b/images/maps/enus/normal/796a.jpg differ diff --git a/images/maps/enus/normal/796b.jpg b/images/maps/enus/normal/796b.jpg new file mode 100644 index 0000000..d1bea00 Binary files /dev/null and b/images/maps/enus/normal/796b.jpg differ diff --git a/images/maps/enus/normal/796c.jpg b/images/maps/enus/normal/796c.jpg new file mode 100644 index 0000000..d975c1b Binary files /dev/null and b/images/maps/enus/normal/796c.jpg differ diff --git a/images/maps/enus/normal/796d.jpg b/images/maps/enus/normal/796d.jpg new file mode 100644 index 0000000..608f58d Binary files /dev/null and b/images/maps/enus/normal/796d.jpg differ diff --git a/images/maps/enus/normal/8.jpg b/images/maps/enus/normal/8.jpg new file mode 100644 index 0000000..3f1dd2d Binary files /dev/null and b/images/maps/enus/normal/8.jpg differ diff --git a/images/maps/enus/normal/85.jpg b/images/maps/enus/normal/85.jpg new file mode 100644 index 0000000..ced6f05 Binary files /dev/null and b/images/maps/enus/normal/85.jpg differ diff --git a/images/maps/enus/normal/978.jpg b/images/maps/enus/normal/978.jpg new file mode 100644 index 0000000..61a1eec Binary files /dev/null and b/images/maps/enus/normal/978.jpg differ diff --git a/images/maps/enus/zoom/-1.jpg b/images/maps/enus/zoom/-1.jpg new file mode 100644 index 0000000..b27463b Binary files /dev/null and b/images/maps/enus/zoom/-1.jpg differ diff --git a/images/maps/enus/zoom/-2.jpg b/images/maps/enus/zoom/-2.jpg new file mode 100644 index 0000000..a7f126b Binary files /dev/null and b/images/maps/enus/zoom/-2.jpg differ diff --git a/images/maps/enus/zoom/-3.jpg b/images/maps/enus/zoom/-3.jpg new file mode 100644 index 0000000..44863cc Binary files /dev/null and b/images/maps/enus/zoom/-3.jpg differ diff --git a/images/maps/enus/zoom/-4.jpg b/images/maps/enus/zoom/-4.jpg new file mode 100644 index 0000000..e99f8e6 Binary files /dev/null and b/images/maps/enus/zoom/-4.jpg differ diff --git a/images/maps/enus/zoom/1.jpg b/images/maps/enus/zoom/1.jpg new file mode 100644 index 0000000..d6d03c9 Binary files /dev/null and b/images/maps/enus/zoom/1.jpg differ diff --git a/images/maps/enus/zoom/10.jpg b/images/maps/enus/zoom/10.jpg new file mode 100644 index 0000000..fc99d4f Binary files /dev/null and b/images/maps/enus/zoom/10.jpg differ diff --git a/images/maps/enus/zoom/11.jpg b/images/maps/enus/zoom/11.jpg new file mode 100644 index 0000000..31d0893 Binary files /dev/null and b/images/maps/enus/zoom/11.jpg differ diff --git a/images/maps/enus/zoom/12.jpg b/images/maps/enus/zoom/12.jpg new file mode 100644 index 0000000..e8388fc Binary files /dev/null and b/images/maps/enus/zoom/12.jpg differ diff --git a/images/maps/enus/zoom/130.jpg b/images/maps/enus/zoom/130.jpg new file mode 100644 index 0000000..da93274 Binary files /dev/null and b/images/maps/enus/zoom/130.jpg differ diff --git a/images/maps/enus/zoom/133.jpg b/images/maps/enus/zoom/133.jpg new file mode 100644 index 0000000..7261de5 Binary files /dev/null and b/images/maps/enus/zoom/133.jpg differ diff --git a/images/maps/enus/zoom/1337.jpg b/images/maps/enus/zoom/1337.jpg new file mode 100644 index 0000000..7322941 Binary files /dev/null and b/images/maps/enus/zoom/1337.jpg differ diff --git a/images/maps/enus/zoom/1377.jpg b/images/maps/enus/zoom/1377.jpg new file mode 100644 index 0000000..1b4d88a Binary files /dev/null and b/images/maps/enus/zoom/1377.jpg differ diff --git a/images/maps/enus/zoom/139.jpg b/images/maps/enus/zoom/139.jpg new file mode 100644 index 0000000..f1d8542 Binary files /dev/null and b/images/maps/enus/zoom/139.jpg differ diff --git a/images/maps/enus/zoom/14.jpg b/images/maps/enus/zoom/14.jpg new file mode 100644 index 0000000..9c10228 Binary files /dev/null and b/images/maps/enus/zoom/14.jpg differ diff --git a/images/maps/enus/zoom/141.jpg b/images/maps/enus/zoom/141.jpg new file mode 100644 index 0000000..1536b45 Binary files /dev/null and b/images/maps/enus/zoom/141.jpg differ diff --git a/images/maps/enus/zoom/1417.jpg b/images/maps/enus/zoom/1417.jpg new file mode 100644 index 0000000..c1ea0ec Binary files /dev/null and b/images/maps/enus/zoom/1417.jpg differ diff --git a/images/maps/enus/zoom/148.jpg b/images/maps/enus/zoom/148.jpg new file mode 100644 index 0000000..3a17b39 Binary files /dev/null and b/images/maps/enus/zoom/148.jpg differ diff --git a/images/maps/enus/zoom/1497.jpg b/images/maps/enus/zoom/1497.jpg new file mode 100644 index 0000000..1ac046a Binary files /dev/null and b/images/maps/enus/zoom/1497.jpg differ diff --git a/images/maps/enus/zoom/15.jpg b/images/maps/enus/zoom/15.jpg new file mode 100644 index 0000000..8875899 Binary files /dev/null and b/images/maps/enus/zoom/15.jpg differ diff --git a/images/maps/enus/zoom/1519.jpg b/images/maps/enus/zoom/1519.jpg new file mode 100644 index 0000000..634fa11 Binary files /dev/null and b/images/maps/enus/zoom/1519.jpg differ diff --git a/images/maps/enus/zoom/1537.jpg b/images/maps/enus/zoom/1537.jpg new file mode 100644 index 0000000..6fc14f7 Binary files /dev/null and b/images/maps/enus/zoom/1537.jpg differ diff --git a/images/maps/enus/zoom/1583b.jpg b/images/maps/enus/zoom/1583b.jpg new file mode 100644 index 0000000..217c4ff Binary files /dev/null and b/images/maps/enus/zoom/1583b.jpg differ diff --git a/images/maps/enus/zoom/1584.jpg b/images/maps/enus/zoom/1584.jpg new file mode 100644 index 0000000..7fe57c8 Binary files /dev/null and b/images/maps/enus/zoom/1584.jpg differ diff --git a/images/maps/enus/zoom/16.jpg b/images/maps/enus/zoom/16.jpg new file mode 100644 index 0000000..5192db1 Binary files /dev/null and b/images/maps/enus/zoom/16.jpg differ diff --git a/images/maps/enus/zoom/1637.jpg b/images/maps/enus/zoom/1637.jpg new file mode 100644 index 0000000..0f60d99 Binary files /dev/null and b/images/maps/enus/zoom/1637.jpg differ diff --git a/images/maps/enus/zoom/1638.jpg b/images/maps/enus/zoom/1638.jpg new file mode 100644 index 0000000..63ee34f Binary files /dev/null and b/images/maps/enus/zoom/1638.jpg differ diff --git a/images/maps/enus/zoom/1657.jpg b/images/maps/enus/zoom/1657.jpg new file mode 100644 index 0000000..a796c2c Binary files /dev/null and b/images/maps/enus/zoom/1657.jpg differ diff --git a/images/maps/enus/zoom/17.jpg b/images/maps/enus/zoom/17.jpg new file mode 100644 index 0000000..cd1ce6d Binary files /dev/null and b/images/maps/enus/zoom/17.jpg differ diff --git a/images/maps/enus/zoom/19.jpg b/images/maps/enus/zoom/19.jpg new file mode 100644 index 0000000..8d399c0 Binary files /dev/null and b/images/maps/enus/zoom/19.jpg differ diff --git a/images/maps/enus/zoom/2017.jpg b/images/maps/enus/zoom/2017.jpg new file mode 100644 index 0000000..cfca35c Binary files /dev/null and b/images/maps/enus/zoom/2017.jpg differ diff --git a/images/maps/enus/zoom/2057.jpg b/images/maps/enus/zoom/2057.jpg new file mode 100644 index 0000000..cd81ec8 Binary files /dev/null and b/images/maps/enus/zoom/2057.jpg differ diff --git a/images/maps/enus/zoom/2100.jpg b/images/maps/enus/zoom/2100.jpg new file mode 100644 index 0000000..4e17fd1 Binary files /dev/null and b/images/maps/enus/zoom/2100.jpg differ diff --git a/images/maps/enus/zoom/215.jpg b/images/maps/enus/zoom/215.jpg new file mode 100644 index 0000000..e04a1de Binary files /dev/null and b/images/maps/enus/zoom/215.jpg differ diff --git a/images/maps/enus/zoom/2159.jpg b/images/maps/enus/zoom/2159.jpg new file mode 100644 index 0000000..c6760e3 Binary files /dev/null and b/images/maps/enus/zoom/2159.jpg differ diff --git a/images/maps/enus/zoom/2366.jpg b/images/maps/enus/zoom/2366.jpg new file mode 100644 index 0000000..ef4d46f Binary files /dev/null and b/images/maps/enus/zoom/2366.jpg differ diff --git a/images/maps/enus/zoom/2367.jpg b/images/maps/enus/zoom/2367.jpg new file mode 100644 index 0000000..e582610 Binary files /dev/null and b/images/maps/enus/zoom/2367.jpg differ diff --git a/images/maps/enus/zoom/2437.jpg b/images/maps/enus/zoom/2437.jpg new file mode 100644 index 0000000..a2f4c5f Binary files /dev/null and b/images/maps/enus/zoom/2437.jpg differ diff --git a/images/maps/enus/zoom/2557.jpg b/images/maps/enus/zoom/2557.jpg new file mode 100644 index 0000000..3ab8794 Binary files /dev/null and b/images/maps/enus/zoom/2557.jpg differ diff --git a/images/maps/enus/zoom/2557e.jpg b/images/maps/enus/zoom/2557e.jpg new file mode 100644 index 0000000..bd7eef0 Binary files /dev/null and b/images/maps/enus/zoom/2557e.jpg differ diff --git a/images/maps/enus/zoom/2557n.jpg b/images/maps/enus/zoom/2557n.jpg new file mode 100644 index 0000000..93b845e Binary files /dev/null and b/images/maps/enus/zoom/2557n.jpg differ diff --git a/images/maps/enus/zoom/2557w.jpg b/images/maps/enus/zoom/2557w.jpg new file mode 100644 index 0000000..a3fa8f5 Binary files /dev/null and b/images/maps/enus/zoom/2557w.jpg differ diff --git a/images/maps/enus/zoom/2597.jpg b/images/maps/enus/zoom/2597.jpg new file mode 100644 index 0000000..aa1e045 Binary files /dev/null and b/images/maps/enus/zoom/2597.jpg differ diff --git a/images/maps/enus/zoom/267.jpg b/images/maps/enus/zoom/267.jpg new file mode 100644 index 0000000..3489b79 Binary files /dev/null and b/images/maps/enus/zoom/267.jpg differ diff --git a/images/maps/enus/zoom/2717.jpg b/images/maps/enus/zoom/2717.jpg new file mode 100644 index 0000000..fe97268 Binary files /dev/null and b/images/maps/enus/zoom/2717.jpg differ diff --git a/images/maps/enus/zoom/28.jpg b/images/maps/enus/zoom/28.jpg new file mode 100644 index 0000000..e578a68 Binary files /dev/null and b/images/maps/enus/zoom/28.jpg differ diff --git a/images/maps/enus/zoom/3.jpg b/images/maps/enus/zoom/3.jpg new file mode 100644 index 0000000..195ce50 Binary files /dev/null and b/images/maps/enus/zoom/3.jpg differ diff --git a/images/maps/enus/zoom/3277.jpg b/images/maps/enus/zoom/3277.jpg new file mode 100644 index 0000000..ea91d10 Binary files /dev/null and b/images/maps/enus/zoom/3277.jpg differ diff --git a/images/maps/enus/zoom/33.jpg b/images/maps/enus/zoom/33.jpg new file mode 100644 index 0000000..73fdc58 Binary files /dev/null and b/images/maps/enus/zoom/33.jpg differ diff --git a/images/maps/enus/zoom/331.jpg b/images/maps/enus/zoom/331.jpg new file mode 100644 index 0000000..b27e3a4 Binary files /dev/null and b/images/maps/enus/zoom/331.jpg differ diff --git a/images/maps/enus/zoom/3358.jpg b/images/maps/enus/zoom/3358.jpg new file mode 100644 index 0000000..260b41c Binary files /dev/null and b/images/maps/enus/zoom/3358.jpg differ diff --git a/images/maps/enus/zoom/3428.jpg b/images/maps/enus/zoom/3428.jpg new file mode 100644 index 0000000..677dc23 Binary files /dev/null and b/images/maps/enus/zoom/3428.jpg differ diff --git a/images/maps/enus/zoom/3429.jpg b/images/maps/enus/zoom/3429.jpg new file mode 100644 index 0000000..2553d81 Binary files /dev/null and b/images/maps/enus/zoom/3429.jpg differ diff --git a/images/maps/enus/zoom/3430.jpg b/images/maps/enus/zoom/3430.jpg new file mode 100644 index 0000000..fc34db4 Binary files /dev/null and b/images/maps/enus/zoom/3430.jpg differ diff --git a/images/maps/enus/zoom/3433.jpg b/images/maps/enus/zoom/3433.jpg new file mode 100644 index 0000000..18bf703 Binary files /dev/null and b/images/maps/enus/zoom/3433.jpg differ diff --git a/images/maps/enus/zoom/3456.jpg b/images/maps/enus/zoom/3456.jpg new file mode 100644 index 0000000..84ad1e2 Binary files /dev/null and b/images/maps/enus/zoom/3456.jpg differ diff --git a/images/maps/enus/zoom/3483.jpg b/images/maps/enus/zoom/3483.jpg new file mode 100644 index 0000000..2e0a686 Binary files /dev/null and b/images/maps/enus/zoom/3483.jpg differ diff --git a/images/maps/enus/zoom/3487.jpg b/images/maps/enus/zoom/3487.jpg new file mode 100644 index 0000000..1b89dea Binary files /dev/null and b/images/maps/enus/zoom/3487.jpg differ diff --git a/images/maps/enus/zoom/3518.jpg b/images/maps/enus/zoom/3518.jpg new file mode 100644 index 0000000..35a35f9 Binary files /dev/null and b/images/maps/enus/zoom/3518.jpg differ diff --git a/images/maps/enus/zoom/3519.jpg b/images/maps/enus/zoom/3519.jpg new file mode 100644 index 0000000..7876cfa Binary files /dev/null and b/images/maps/enus/zoom/3519.jpg differ diff --git a/images/maps/enus/zoom/3520.jpg b/images/maps/enus/zoom/3520.jpg new file mode 100644 index 0000000..f37b277 Binary files /dev/null and b/images/maps/enus/zoom/3520.jpg differ diff --git a/images/maps/enus/zoom/3521.jpg b/images/maps/enus/zoom/3521.jpg new file mode 100644 index 0000000..84ae1cd Binary files /dev/null and b/images/maps/enus/zoom/3521.jpg differ diff --git a/images/maps/enus/zoom/3522.jpg b/images/maps/enus/zoom/3522.jpg new file mode 100644 index 0000000..887f32c Binary files /dev/null and b/images/maps/enus/zoom/3522.jpg differ diff --git a/images/maps/enus/zoom/3523.jpg b/images/maps/enus/zoom/3523.jpg new file mode 100644 index 0000000..3a8e2cd Binary files /dev/null and b/images/maps/enus/zoom/3523.jpg differ diff --git a/images/maps/enus/zoom/3524.jpg b/images/maps/enus/zoom/3524.jpg new file mode 100644 index 0000000..755b806 Binary files /dev/null and b/images/maps/enus/zoom/3524.jpg differ diff --git a/images/maps/enus/zoom/3525.jpg b/images/maps/enus/zoom/3525.jpg new file mode 100644 index 0000000..c80b9c7 Binary files /dev/null and b/images/maps/enus/zoom/3525.jpg differ diff --git a/images/maps/enus/zoom/3557.jpg b/images/maps/enus/zoom/3557.jpg new file mode 100644 index 0000000..f32dbc3 Binary files /dev/null and b/images/maps/enus/zoom/3557.jpg differ diff --git a/images/maps/enus/zoom/3562.jpg b/images/maps/enus/zoom/3562.jpg new file mode 100644 index 0000000..94906c2 Binary files /dev/null and b/images/maps/enus/zoom/3562.jpg differ diff --git a/images/maps/enus/zoom/357.jpg b/images/maps/enus/zoom/357.jpg new file mode 100644 index 0000000..d5f3ff9 Binary files /dev/null and b/images/maps/enus/zoom/357.jpg differ diff --git a/images/maps/enus/zoom/36.jpg b/images/maps/enus/zoom/36.jpg new file mode 100644 index 0000000..e4bffa8 Binary files /dev/null and b/images/maps/enus/zoom/36.jpg differ diff --git a/images/maps/enus/zoom/3606.jpg b/images/maps/enus/zoom/3606.jpg new file mode 100644 index 0000000..e3c8e1d Binary files /dev/null and b/images/maps/enus/zoom/3606.jpg differ diff --git a/images/maps/enus/zoom/3607.jpg b/images/maps/enus/zoom/3607.jpg new file mode 100644 index 0000000..8f9fdd7 Binary files /dev/null and b/images/maps/enus/zoom/3607.jpg differ diff --git a/images/maps/enus/zoom/361.jpg b/images/maps/enus/zoom/361.jpg new file mode 100644 index 0000000..6c8c6ca Binary files /dev/null and b/images/maps/enus/zoom/361.jpg differ diff --git a/images/maps/enus/zoom/3618.jpg b/images/maps/enus/zoom/3618.jpg new file mode 100644 index 0000000..6dd1f42 Binary files /dev/null and b/images/maps/enus/zoom/3618.jpg differ diff --git a/images/maps/enus/zoom/3703.jpg b/images/maps/enus/zoom/3703.jpg new file mode 100644 index 0000000..94451af Binary files /dev/null and b/images/maps/enus/zoom/3703.jpg differ diff --git a/images/maps/enus/zoom/3713.jpg b/images/maps/enus/zoom/3713.jpg new file mode 100644 index 0000000..eb24075 Binary files /dev/null and b/images/maps/enus/zoom/3713.jpg differ diff --git a/images/maps/enus/zoom/3714.jpg b/images/maps/enus/zoom/3714.jpg new file mode 100644 index 0000000..dacdd80 Binary files /dev/null and b/images/maps/enus/zoom/3714.jpg differ diff --git a/images/maps/enus/zoom/3715.jpg b/images/maps/enus/zoom/3715.jpg new file mode 100644 index 0000000..0d1e031 Binary files /dev/null and b/images/maps/enus/zoom/3715.jpg differ diff --git a/images/maps/enus/zoom/3716.jpg b/images/maps/enus/zoom/3716.jpg new file mode 100644 index 0000000..954b0f0 Binary files /dev/null and b/images/maps/enus/zoom/3716.jpg differ diff --git a/images/maps/enus/zoom/3717.jpg b/images/maps/enus/zoom/3717.jpg new file mode 100644 index 0000000..3dc1a93 Binary files /dev/null and b/images/maps/enus/zoom/3717.jpg differ diff --git a/images/maps/enus/zoom/3789.jpg b/images/maps/enus/zoom/3789.jpg new file mode 100644 index 0000000..d9d5e19 Binary files /dev/null and b/images/maps/enus/zoom/3789.jpg differ diff --git a/images/maps/enus/zoom/3790.jpg b/images/maps/enus/zoom/3790.jpg new file mode 100644 index 0000000..3f3d67f Binary files /dev/null and b/images/maps/enus/zoom/3790.jpg differ diff --git a/images/maps/enus/zoom/3791.jpg b/images/maps/enus/zoom/3791.jpg new file mode 100644 index 0000000..f711613 Binary files /dev/null and b/images/maps/enus/zoom/3791.jpg differ diff --git a/images/maps/enus/zoom/3792.jpg b/images/maps/enus/zoom/3792.jpg new file mode 100644 index 0000000..b3ba342 Binary files /dev/null and b/images/maps/enus/zoom/3792.jpg differ diff --git a/images/maps/enus/zoom/38.jpg b/images/maps/enus/zoom/38.jpg new file mode 100644 index 0000000..757b208 Binary files /dev/null and b/images/maps/enus/zoom/38.jpg differ diff --git a/images/maps/enus/zoom/3805.jpg b/images/maps/enus/zoom/3805.jpg new file mode 100644 index 0000000..baf4595 Binary files /dev/null and b/images/maps/enus/zoom/3805.jpg differ diff --git a/images/maps/enus/zoom/3820.jpg b/images/maps/enus/zoom/3820.jpg new file mode 100644 index 0000000..26277c9 Binary files /dev/null and b/images/maps/enus/zoom/3820.jpg differ diff --git a/images/maps/enus/zoom/3836.jpg b/images/maps/enus/zoom/3836.jpg new file mode 100644 index 0000000..49d6538 Binary files /dev/null and b/images/maps/enus/zoom/3836.jpg differ diff --git a/images/maps/enus/zoom/3842.jpg b/images/maps/enus/zoom/3842.jpg new file mode 100644 index 0000000..f020019 Binary files /dev/null and b/images/maps/enus/zoom/3842.jpg differ diff --git a/images/maps/enus/zoom/3846.jpg b/images/maps/enus/zoom/3846.jpg new file mode 100644 index 0000000..d3a29db Binary files /dev/null and b/images/maps/enus/zoom/3846.jpg differ diff --git a/images/maps/enus/zoom/3847.jpg b/images/maps/enus/zoom/3847.jpg new file mode 100644 index 0000000..dd394e3 Binary files /dev/null and b/images/maps/enus/zoom/3847.jpg differ diff --git a/images/maps/enus/zoom/3849.jpg b/images/maps/enus/zoom/3849.jpg new file mode 100644 index 0000000..9ed2055 Binary files /dev/null and b/images/maps/enus/zoom/3849.jpg differ diff --git a/images/maps/enus/zoom/3959.jpg b/images/maps/enus/zoom/3959.jpg new file mode 100644 index 0000000..26d2810 Binary files /dev/null and b/images/maps/enus/zoom/3959.jpg differ diff --git a/images/maps/enus/zoom/4.jpg b/images/maps/enus/zoom/4.jpg new file mode 100644 index 0000000..d6c20a3 Binary files /dev/null and b/images/maps/enus/zoom/4.jpg differ diff --git a/images/maps/enus/zoom/40.jpg b/images/maps/enus/zoom/40.jpg new file mode 100644 index 0000000..e18dadf Binary files /dev/null and b/images/maps/enus/zoom/40.jpg differ diff --git a/images/maps/enus/zoom/400.jpg b/images/maps/enus/zoom/400.jpg new file mode 100644 index 0000000..923253e Binary files /dev/null and b/images/maps/enus/zoom/400.jpg differ diff --git a/images/maps/enus/zoom/405.jpg b/images/maps/enus/zoom/405.jpg new file mode 100644 index 0000000..aabbff2 Binary files /dev/null and b/images/maps/enus/zoom/405.jpg differ diff --git a/images/maps/enus/zoom/406.jpg b/images/maps/enus/zoom/406.jpg new file mode 100644 index 0000000..46ff3ed Binary files /dev/null and b/images/maps/enus/zoom/406.jpg differ diff --git a/images/maps/enus/zoom/4080.jpg b/images/maps/enus/zoom/4080.jpg new file mode 100644 index 0000000..f4f9ce2 Binary files /dev/null and b/images/maps/enus/zoom/4080.jpg differ diff --git a/images/maps/enus/zoom/4095.jpg b/images/maps/enus/zoom/4095.jpg new file mode 100644 index 0000000..d27a0fa Binary files /dev/null and b/images/maps/enus/zoom/4095.jpg differ diff --git a/images/maps/enus/zoom/41.jpg b/images/maps/enus/zoom/41.jpg new file mode 100644 index 0000000..a9c518f Binary files /dev/null and b/images/maps/enus/zoom/41.jpg differ diff --git a/images/maps/enus/zoom/44.jpg b/images/maps/enus/zoom/44.jpg new file mode 100644 index 0000000..6267bf4 Binary files /dev/null and b/images/maps/enus/zoom/44.jpg differ diff --git a/images/maps/enus/zoom/440.jpg b/images/maps/enus/zoom/440.jpg new file mode 100644 index 0000000..5326c89 Binary files /dev/null and b/images/maps/enus/zoom/440.jpg differ diff --git a/images/maps/enus/zoom/45.jpg b/images/maps/enus/zoom/45.jpg new file mode 100644 index 0000000..154da83 Binary files /dev/null and b/images/maps/enus/zoom/45.jpg differ diff --git a/images/maps/enus/zoom/457.jpg b/images/maps/enus/zoom/457.jpg new file mode 100644 index 0000000..9adefbe Binary files /dev/null and b/images/maps/enus/zoom/457.jpg differ diff --git a/images/maps/enus/zoom/46.jpg b/images/maps/enus/zoom/46.jpg new file mode 100644 index 0000000..70c4a0d Binary files /dev/null and b/images/maps/enus/zoom/46.jpg differ diff --git a/images/maps/enus/zoom/47.jpg b/images/maps/enus/zoom/47.jpg new file mode 100644 index 0000000..a0063a2 Binary files /dev/null and b/images/maps/enus/zoom/47.jpg differ diff --git a/images/maps/enus/zoom/490.jpg b/images/maps/enus/zoom/490.jpg new file mode 100644 index 0000000..25ae870 Binary files /dev/null and b/images/maps/enus/zoom/490.jpg differ diff --git a/images/maps/enus/zoom/491.jpg b/images/maps/enus/zoom/491.jpg new file mode 100644 index 0000000..14e5227 Binary files /dev/null and b/images/maps/enus/zoom/491.jpg differ diff --git a/images/maps/enus/zoom/493.jpg b/images/maps/enus/zoom/493.jpg new file mode 100644 index 0000000..1299e7c Binary files /dev/null and b/images/maps/enus/zoom/493.jpg differ diff --git a/images/maps/enus/zoom/51.jpg b/images/maps/enus/zoom/51.jpg new file mode 100644 index 0000000..e6b9759 Binary files /dev/null and b/images/maps/enus/zoom/51.jpg differ diff --git a/images/maps/enus/zoom/618.jpg b/images/maps/enus/zoom/618.jpg new file mode 100644 index 0000000..750210f Binary files /dev/null and b/images/maps/enus/zoom/618.jpg differ diff --git a/images/maps/enus/zoom/717.jpg b/images/maps/enus/zoom/717.jpg new file mode 100644 index 0000000..3b24840 Binary files /dev/null and b/images/maps/enus/zoom/717.jpg differ diff --git a/images/maps/enus/zoom/718.jpg b/images/maps/enus/zoom/718.jpg new file mode 100644 index 0000000..034d63a Binary files /dev/null and b/images/maps/enus/zoom/718.jpg differ diff --git a/images/maps/enus/zoom/719.jpg b/images/maps/enus/zoom/719.jpg new file mode 100644 index 0000000..e998e6b Binary files /dev/null and b/images/maps/enus/zoom/719.jpg differ diff --git a/images/maps/enus/zoom/722.jpg b/images/maps/enus/zoom/722.jpg new file mode 100644 index 0000000..ca281b9 Binary files /dev/null and b/images/maps/enus/zoom/722.jpg differ diff --git a/images/maps/enus/zoom/796.jpg b/images/maps/enus/zoom/796.jpg new file mode 100644 index 0000000..7bf89e1 Binary files /dev/null and b/images/maps/enus/zoom/796.jpg differ diff --git a/images/maps/enus/zoom/796a.jpg b/images/maps/enus/zoom/796a.jpg new file mode 100644 index 0000000..b6e3605 Binary files /dev/null and b/images/maps/enus/zoom/796a.jpg differ diff --git a/images/maps/enus/zoom/796b.jpg b/images/maps/enus/zoom/796b.jpg new file mode 100644 index 0000000..10688c6 Binary files /dev/null and b/images/maps/enus/zoom/796b.jpg differ diff --git a/images/maps/enus/zoom/796c.jpg b/images/maps/enus/zoom/796c.jpg new file mode 100644 index 0000000..ae65ff2 Binary files /dev/null and b/images/maps/enus/zoom/796c.jpg differ diff --git a/images/maps/enus/zoom/796d.jpg b/images/maps/enus/zoom/796d.jpg new file mode 100644 index 0000000..dc40364 Binary files /dev/null and b/images/maps/enus/zoom/796d.jpg differ diff --git a/images/maps/enus/zoom/8.jpg b/images/maps/enus/zoom/8.jpg new file mode 100644 index 0000000..2fe0fe2 Binary files /dev/null and b/images/maps/enus/zoom/8.jpg differ diff --git a/images/maps/enus/zoom/85.jpg b/images/maps/enus/zoom/85.jpg new file mode 100644 index 0000000..7a0eeee Binary files /dev/null and b/images/maps/enus/zoom/85.jpg differ diff --git a/images/maps/enus/zoom/978.jpg b/images/maps/enus/zoom/978.jpg new file mode 100644 index 0000000..058d526 Binary files /dev/null and b/images/maps/enus/zoom/978.jpg differ diff --git a/images/tmp/0.png b/images/tmp/0.png new file mode 100644 index 0000000..2eadf3b Binary files /dev/null and b/images/tmp/0.png differ diff --git a/images/tmp/1.png b/images/tmp/1.png new file mode 100644 index 0000000..0211d0f Binary files /dev/null and b/images/tmp/1.png differ diff --git a/images/tmp/10.png b/images/tmp/10.png new file mode 100644 index 0000000..9321fc6 Binary files /dev/null and b/images/tmp/10.png differ diff --git a/images/tmp/11.png b/images/tmp/11.png new file mode 100644 index 0000000..f87023e Binary files /dev/null and b/images/tmp/11.png differ diff --git a/images/tmp/12.png b/images/tmp/12.png new file mode 100644 index 0000000..45c4c9d Binary files /dev/null and b/images/tmp/12.png differ diff --git a/images/tmp/130.png b/images/tmp/130.png new file mode 100644 index 0000000..9ea5ed8 Binary files /dev/null and b/images/tmp/130.png differ diff --git a/images/tmp/1377.png b/images/tmp/1377.png new file mode 100644 index 0000000..b3c9de4 Binary files /dev/null and b/images/tmp/1377.png differ diff --git a/images/tmp/139.png b/images/tmp/139.png new file mode 100644 index 0000000..8019c5e Binary files /dev/null and b/images/tmp/139.png differ diff --git a/images/tmp/14.png b/images/tmp/14.png new file mode 100644 index 0000000..247a4e1 Binary files /dev/null and b/images/tmp/14.png differ diff --git a/images/tmp/141.png b/images/tmp/141.png new file mode 100644 index 0000000..e7019fa Binary files /dev/null and b/images/tmp/141.png differ diff --git a/images/tmp/148.png b/images/tmp/148.png new file mode 100644 index 0000000..b47e5a6 Binary files /dev/null and b/images/tmp/148.png differ diff --git a/images/tmp/1497.png b/images/tmp/1497.png new file mode 100644 index 0000000..5e3cb56 Binary files /dev/null and b/images/tmp/1497.png differ diff --git a/images/tmp/15.png b/images/tmp/15.png new file mode 100644 index 0000000..50c6743 Binary files /dev/null and b/images/tmp/15.png differ diff --git a/images/tmp/1519.png b/images/tmp/1519.png new file mode 100644 index 0000000..fdda923 Binary files /dev/null and b/images/tmp/1519.png differ diff --git a/images/tmp/1537.png b/images/tmp/1537.png new file mode 100644 index 0000000..fc1ec45 Binary files /dev/null and b/images/tmp/1537.png differ diff --git a/images/tmp/16.png b/images/tmp/16.png new file mode 100644 index 0000000..8fadbcf Binary files /dev/null and b/images/tmp/16.png differ diff --git a/images/tmp/1637.png b/images/tmp/1637.png new file mode 100644 index 0000000..fa1e7de Binary files /dev/null and b/images/tmp/1637.png differ diff --git a/images/tmp/17.png b/images/tmp/17.png new file mode 100644 index 0000000..31f6c83 Binary files /dev/null and b/images/tmp/17.png differ diff --git a/images/tmp/210.png b/images/tmp/210.png new file mode 100644 index 0000000..1eb57fc Binary files /dev/null and b/images/tmp/210.png differ diff --git a/images/tmp/215.png b/images/tmp/215.png new file mode 100644 index 0000000..2e586f5 Binary files /dev/null and b/images/tmp/215.png differ diff --git a/images/tmp/2597.png b/images/tmp/2597.png new file mode 100644 index 0000000..3712ca3 Binary files /dev/null and b/images/tmp/2597.png differ diff --git a/images/tmp/267.png b/images/tmp/267.png new file mode 100644 index 0000000..c90fb75 Binary files /dev/null and b/images/tmp/267.png differ diff --git a/images/tmp/28.png b/images/tmp/28.png new file mode 100644 index 0000000..f27b1bd Binary files /dev/null and b/images/tmp/28.png differ diff --git a/images/tmp/2817.png b/images/tmp/2817.png new file mode 100644 index 0000000..dc8b3e0 Binary files /dev/null and b/images/tmp/2817.png differ diff --git a/images/tmp/3.png b/images/tmp/3.png new file mode 100644 index 0000000..d38c2cd Binary files /dev/null and b/images/tmp/3.png differ diff --git a/images/tmp/33.png b/images/tmp/33.png new file mode 100644 index 0000000..1f6ae5d Binary files /dev/null and b/images/tmp/33.png differ diff --git a/images/tmp/331.png b/images/tmp/331.png new file mode 100644 index 0000000..b2e4573 Binary files /dev/null and b/images/tmp/331.png differ diff --git a/images/tmp/3430.png b/images/tmp/3430.png new file mode 100644 index 0000000..591dcd4 Binary files /dev/null and b/images/tmp/3430.png differ diff --git a/images/tmp/3433.png b/images/tmp/3433.png new file mode 100644 index 0000000..345a44e Binary files /dev/null and b/images/tmp/3433.png differ diff --git a/images/tmp/3483.png b/images/tmp/3483.png new file mode 100644 index 0000000..e8899be Binary files /dev/null and b/images/tmp/3483.png differ diff --git a/images/tmp/3518.png b/images/tmp/3518.png new file mode 100644 index 0000000..b299688 Binary files /dev/null and b/images/tmp/3518.png differ diff --git a/images/tmp/3519.png b/images/tmp/3519.png new file mode 100644 index 0000000..d3cc3e0 Binary files /dev/null and b/images/tmp/3519.png differ diff --git a/images/tmp/3520.png b/images/tmp/3520.png new file mode 100644 index 0000000..e38684a Binary files /dev/null and b/images/tmp/3520.png differ diff --git a/images/tmp/3521.png b/images/tmp/3521.png new file mode 100644 index 0000000..fa3236a Binary files /dev/null and b/images/tmp/3521.png differ diff --git a/images/tmp/3522.png b/images/tmp/3522.png new file mode 100644 index 0000000..1e47448 Binary files /dev/null and b/images/tmp/3522.png differ diff --git a/images/tmp/3523.png b/images/tmp/3523.png new file mode 100644 index 0000000..dc80251 Binary files /dev/null and b/images/tmp/3523.png differ diff --git a/images/tmp/3524.png b/images/tmp/3524.png new file mode 100644 index 0000000..9afae78 Binary files /dev/null and b/images/tmp/3524.png differ diff --git a/images/tmp/3525.png b/images/tmp/3525.png new file mode 100644 index 0000000..e7019fa Binary files /dev/null and b/images/tmp/3525.png differ diff --git a/images/tmp/3537.png b/images/tmp/3537.png new file mode 100644 index 0000000..bd1f372 Binary files /dev/null and b/images/tmp/3537.png differ diff --git a/images/tmp/3557.png b/images/tmp/3557.png new file mode 100644 index 0000000..70cf3d3 Binary files /dev/null and b/images/tmp/3557.png differ diff --git a/images/tmp/357.png b/images/tmp/357.png new file mode 100644 index 0000000..19beae8 Binary files /dev/null and b/images/tmp/357.png differ diff --git a/images/tmp/36.png b/images/tmp/36.png new file mode 100644 index 0000000..697e0e0 Binary files /dev/null and b/images/tmp/36.png differ diff --git a/images/tmp/361.png b/images/tmp/361.png new file mode 100644 index 0000000..ac76ef4 Binary files /dev/null and b/images/tmp/361.png differ diff --git a/images/tmp/3703.png b/images/tmp/3703.png new file mode 100644 index 0000000..938bc2c Binary files /dev/null and b/images/tmp/3703.png differ diff --git a/images/tmp/3711.png b/images/tmp/3711.png new file mode 100644 index 0000000..597319a Binary files /dev/null and b/images/tmp/3711.png differ diff --git a/images/tmp/38.png b/images/tmp/38.png new file mode 100644 index 0000000..42d735c Binary files /dev/null and b/images/tmp/38.png differ diff --git a/images/tmp/394.png b/images/tmp/394.png new file mode 100644 index 0000000..e0d0825 Binary files /dev/null and b/images/tmp/394.png differ diff --git a/images/tmp/4.png b/images/tmp/4.png new file mode 100644 index 0000000..a1a5309 Binary files /dev/null and b/images/tmp/4.png differ diff --git a/images/tmp/40.png b/images/tmp/40.png new file mode 100644 index 0000000..7d702a7 Binary files /dev/null and b/images/tmp/40.png differ diff --git a/images/tmp/400.png b/images/tmp/400.png new file mode 100644 index 0000000..17279a7 Binary files /dev/null and b/images/tmp/400.png differ diff --git a/images/tmp/405.png b/images/tmp/405.png new file mode 100644 index 0000000..6bd6b09 Binary files /dev/null and b/images/tmp/405.png differ diff --git a/images/tmp/406.png b/images/tmp/406.png new file mode 100644 index 0000000..21d772e Binary files /dev/null and b/images/tmp/406.png differ diff --git a/images/tmp/4080.png b/images/tmp/4080.png new file mode 100644 index 0000000..e7019fa Binary files /dev/null and b/images/tmp/4080.png differ diff --git a/images/tmp/41.png b/images/tmp/41.png new file mode 100644 index 0000000..1460bf6 Binary files /dev/null and b/images/tmp/41.png differ diff --git a/images/tmp/4197.png b/images/tmp/4197.png new file mode 100644 index 0000000..4dab8d6 Binary files /dev/null and b/images/tmp/4197.png differ diff --git a/images/tmp/4265.png b/images/tmp/4265.png new file mode 100644 index 0000000..e7019fa Binary files /dev/null and b/images/tmp/4265.png differ diff --git a/images/tmp/4298.png b/images/tmp/4298.png new file mode 100644 index 0000000..e7019fa Binary files /dev/null and b/images/tmp/4298.png differ diff --git a/images/tmp/4384.png b/images/tmp/4384.png new file mode 100644 index 0000000..e7019fa Binary files /dev/null and b/images/tmp/4384.png differ diff --git a/images/tmp/4395.png b/images/tmp/4395.png new file mode 100644 index 0000000..e7019fa Binary files /dev/null and b/images/tmp/4395.png differ diff --git a/images/tmp/44.png b/images/tmp/44.png new file mode 100644 index 0000000..ac689cc Binary files /dev/null and b/images/tmp/44.png differ diff --git a/images/tmp/440.png b/images/tmp/440.png new file mode 100644 index 0000000..1c6cfa1 Binary files /dev/null and b/images/tmp/440.png differ diff --git a/images/tmp/45.png b/images/tmp/45.png new file mode 100644 index 0000000..4ca11d8 Binary files /dev/null and b/images/tmp/45.png differ diff --git a/images/tmp/457.png b/images/tmp/457.png new file mode 100644 index 0000000..2eadf3b Binary files /dev/null and b/images/tmp/457.png differ diff --git a/images/tmp/46.png b/images/tmp/46.png new file mode 100644 index 0000000..5f1a206 Binary files /dev/null and b/images/tmp/46.png differ diff --git a/images/tmp/47.png b/images/tmp/47.png new file mode 100644 index 0000000..74b5d0e Binary files /dev/null and b/images/tmp/47.png differ diff --git a/images/tmp/490.png b/images/tmp/490.png new file mode 100644 index 0000000..8c9cfa6 Binary files /dev/null and b/images/tmp/490.png differ diff --git a/images/tmp/493.png b/images/tmp/493.png new file mode 100644 index 0000000..1704b01 Binary files /dev/null and b/images/tmp/493.png differ diff --git a/images/tmp/495.png b/images/tmp/495.png new file mode 100644 index 0000000..ca9d13b Binary files /dev/null and b/images/tmp/495.png differ diff --git a/images/tmp/51.png b/images/tmp/51.png new file mode 100644 index 0000000..6aba15e Binary files /dev/null and b/images/tmp/51.png differ diff --git a/images/tmp/618.png b/images/tmp/618.png new file mode 100644 index 0000000..8404ec2 Binary files /dev/null and b/images/tmp/618.png differ diff --git a/images/tmp/65.png b/images/tmp/65.png new file mode 100644 index 0000000..721f5ab Binary files /dev/null and b/images/tmp/65.png differ diff --git a/images/tmp/66.png b/images/tmp/66.png new file mode 100644 index 0000000..cbbe646 Binary files /dev/null and b/images/tmp/66.png differ diff --git a/images/tmp/67.png b/images/tmp/67.png new file mode 100644 index 0000000..a3d2f2b Binary files /dev/null and b/images/tmp/67.png differ diff --git a/images/tmp/8.png b/images/tmp/8.png new file mode 100644 index 0000000..5f3e60d Binary files /dev/null and b/images/tmp/8.png differ diff --git a/images/tmp/85.png b/images/tmp/85.png new file mode 100644 index 0000000..ffd0cda Binary files /dev/null and b/images/tmp/85.png differ diff --git a/includes/.htaccess b/includes/.htaccess new file mode 100644 index 0000000..e67301e --- /dev/null +++ b/includes/.htaccess @@ -0,0 +1,4 @@ + +Order Allow,Deny +Deny from All + diff --git a/includes/DbSimple/Generic.php b/includes/DbSimple/Generic.php new file mode 100644 index 0000000..3bff3cc --- /dev/null +++ b/includes/DbSimple/Generic.php @@ -0,0 +1,1361 @@ +. + * + * Contains 3 classes: + * - DbSimple_Generic: database factory class + * - DbSimple_Generic_Database: common database methods + * - DbSimple_Generic_Blob: common BLOB support + * - DbSimple_Generic_LastError: error reporting and tracking + * + * Special result-set fields: + * - ARRAY_KEY* ("*" means "anything") + * - PARENT_KEY + * + * Transforms: + * - GET_ATTRIBUTES + * - CALC_TOTAL + * - GET_TOTAL + * - UNIQ_KEY + * + * Query attributes: + * - BLOB_OBJ + * - CACHE + * + * @author Dmitry Koterov, http://forum.dklab.ru/users/DmitryKoterov/ + * @author Konstantin Zhinko, http://forum.dklab.ru/users/KonstantinGinkoTit/ + * + * @version 2.x $Id$ + */ + +/** + * Use this constant as placeholder value to skip optional SQL block [...]. + */ +define('DBSIMPLE_SKIP', log(0)); + +/** + * Names of special columns in result-set which is used + * as array key (or karent key in forest-based resultsets) in + * resulting hash. + */ +define('DBSIMPLE_ARRAY_KEY', 'ARRAY_KEY'); // hash-based resultset support +define('DBSIMPLE_PARENT_KEY', 'PARENT_KEY'); // forrest-based resultset support + + +/** + * DbSimple factory. + */ +class DbSimple_Generic +{ + /** + * DbSimple_Generic connect(mixed $dsn) + * + * Universal static function to connect ANY database using DSN syntax. + * Choose database driver according to DSN. Return new instance + * of this driver. + */ + function& connect($dsn) + { + // Load database driver and create its instance. + $parsed = DbSimple_Generic::parseDSN($dsn); + if (!$parsed) { + $dummy = null; + return $dummy; + } + $class = 'DbSimple_'.ucfirst($parsed['scheme']); + if (!class_exists($class)) { + $file = str_replace('_', '/', $class) . ".php"; + // Try to load library file from standard include_path. + if ($f = @fopen($file, "r", true)) { + fclose($f); + require_once($file); + } else { + // Wrong include_path; try to load from current directory. + $base = basename($file); + $dir = dirname(__FILE__); + if (@is_file($path = "$dir/$base")) { + require_once($path); + } else { + trigger_error("Error loading database driver: no file $file in include_path; no file $base in $dir", E_USER_ERROR); + return null; + } + } + } + $object =& new $class($parsed); + if (isset($parsed['ident_prefix'])) { + $object->setIdentPrefix($parsed['ident_prefix']); + } + $object->setCachePrefix(md5(serialize($parsed['dsn']))); + if (@fopen('Cache/Lite.php', 'r', true)) { + $tmp_dirs = array( + ini_get('session.save_path'), + getenv("TEMP"), + getenv("TMP"), + getenv("TMPDIR"), + '/tmp' + ); + foreach ($tmp_dirs as $dir) { + if (!$dir) continue; + $fp = @fopen($testFile = $dir . '/DbSimple_' . md5(getmypid() . microtime()), 'w'); + if ($fp) { + fclose($fp); + unlink($testFile); + require_once 'Cache' . '/Lite.php'; // "." -> no phpEclipse notice + $t =& new Cache_Lite(array('cacheDir' => $dir.'/', 'lifeTime' => null, 'automaticSerialization' => true)); + $object->_cacher =& $t; + break; + } + + } + } + return $object; + } + + + /** + * array parseDSN(mixed $dsn) + * Parse a data source name. + * See parse_url() for details. + */ + function parseDSN($dsn) + { + if (is_array($dsn)) return $dsn; + $parsed = @parse_url($dsn); + if (!$parsed) return null; + $params = null; + if (!empty($parsed['query'])) { + parse_str($parsed['query'], $params); + $parsed += $params; + } + $parsed['dsn'] = $dsn; + return $parsed; + } +} + + +/** + * Base class for all databases. + * Can create transactions and new BLOBs, parse DSNs. + * + * Logger is COMMON for multiple transactions. + * Error handler is private for each transaction and database. + */ +class DbSimple_Generic_Database extends DbSimple_Generic_LastError +{ + /** + * Public methods. + */ + + /** + * object blob($blob_id) + * Create new blob + */ + function blob($blob_id = null) + { + $this->_resetLastError(); + return $this->_performNewBlob($blob_id); + } + + /** + * void transaction($mode) + * Create new transaction. + */ + function transaction($mode=null) + { + $this->_resetLastError(); + $this->_logQuery('-- START TRANSACTION '.$mode); + return $this->_performTransaction($mode); + } + + /** + * mixed commit() + * Commit the transaction. + */ + function commit() + { + $this->_resetLastError(); + $this->_logQuery('-- COMMIT'); + return $this->_performCommit(); + } + + /** + * mixed rollback() + * Rollback the transaction. + */ + function rollback() + { + $this->_resetLastError(); + $this->_logQuery('-- ROLLBACK'); + return $this->_performRollback(); + } + + /** + * mixed select(string $query [, $arg1] [,$arg2] ...) + * Execute query and return the result. + */ + function select($query) + { + $args = func_get_args(); + $total = false; + return $this->_query($args, $total); + } + + /** + * mixed selectPage(int &$total, string $query [, $arg1] [,$arg2] ...) + * Execute query and return the result. + * Total number of found rows (independent to LIMIT) is returned in $total + * (in most cases second query is performed to calculate $total). + */ + function selectPage(&$total, $query) + { + $args = func_get_args(); + array_shift($args); + $total = true; + return $this->_query($args, $total); + } + + /** + * hash selectRow(string $query [, $arg1] [,$arg2] ...) + * Return the first row of query result. + * On errors return null and set last error. + * If no one row found, return array()! It is useful while debugging, + * because PHP DOES NOT generates notice on $row['abc'] if $row === null + * or $row === false (but, if $row is empty array, notice is generated). + */ + function selectRow() + { + $args = func_get_args(); + $total = false; + $rows = $this->_query($args, $total); + if (!is_array($rows)) return $rows; + if (!count($rows)) return array(); + reset($rows); + return current($rows); + } + + /** + * array selectCol(string $query [, $arg1] [,$arg2] ...) + * Return the first column of query result as array. + */ + function selectCol() + { + $args = func_get_args(); + $total = false; + $rows = $this->_query($args, $total); + if (!is_array($rows)) return $rows; + $this->_shrinkLastArrayDimensionCallback($rows); + return $rows; + } + + /** + * scalar selectCell(string $query [, $arg1] [,$arg2] ...) + * Return the first cell of the first column of query result. + * If no one row selected, return null. + */ + function selectCell() + { + $args = func_get_args(); + $total = false; + $rows = $this->_query($args, $total); + if (!is_array($rows)) return $rows; + if (!count($rows)) return null; + reset($rows); + $row = current($rows); + if (!is_array($row)) return $row; + reset($row); + return current($row); + } + + /** + * mixed query(string $query [, $arg1] [,$arg2] ...) + * Alias for select(). May be used for INSERT or UPDATE queries. + */ + function query() + { + $args = func_get_args(); + $total = false; + return $this->_query($args, $total); + } + + /** + * string escape(mixed $s, bool $isIdent=false) + * Enclose the string into database quotes correctly escaping + * special characters. If $isIdent is true, value quoted as identifier + * (e.g.: `value` in MySQL, "value" in Firebird, [value] in MSSQL). + */ + function escape($s, $isIdent=false) + { + return $this->_performEscape($s, $isIdent); + } + + + /** + * callback setLogger(callback $logger) + * Set query logger called before each query is executed. + * Returns previous logger. + */ + function setLogger($logger) + { + $prev = $this->_logger; + $this->_logger = $logger; + return $prev; + } + + /** + * callback setCacher(callback $cacher) + * Set cache mechanism called during each query if specified. + * Returns previous handler. + */ + function setCacher($cacher) + { + $prev = $this->_cacher; + $this->_cacher = $cacher; + return $prev; + } + + /** + * string setIdentPrefix($prx) + * Set identifier prefix used for $_ placeholder. + */ + function setIdentPrefix($prx) + { + $old = $this->_identPrefix; + if ($prx !== null) $this->_identPrefix = $prx; + return $old; + } + + /** + * string setIdentPrefix($prx) + * Set cache prefix used in key caclulation. + */ + function setCachePrefix($prx) + { + $old = $this->_cachePrefix; + if ($prx !== null) $this->_cachePrefix = $prx; + return $old; + } + + /** + * array getStatistics() + * Returns various statistical information. + */ + function getStatistics() + { + return $this->_statistics; + } + + + /** + * Virtual protected methods + */ + function ____________PROTECTED() {} // for phpEclipse outline + + + /** + * string _performEscape(mixed $s, bool $isIdent=false) + */ + function _performEscape($s, $isIdent) + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + /** + * object _performNewBlob($id) + * + * Returns new blob object. + */ + function& _performNewBlob($id) + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + /** + * list _performGetBlobFieldNames($resultResource) + * Get list of all BLOB field names in result-set. + */ + function _performGetBlobFieldNames($result) + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + /** + * mixed _performTransformQuery(array &$query, string $how) + * + * Transform query different way specified by $how. + * May return some information about performed transform. + */ + function _performTransformQuery(&$queryMain, $how) + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + + /** + * resource _performQuery($arrayQuery) + * Must return: + * - For SELECT queries: ID of result-set (PHP resource). + * - For other queries: query status (scalar). + * - For error queries: null (and call _setLastError()). + */ + function _performQuery($arrayQuery) + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + /** + * mixed _performFetch($resultResource) + * Fetch ONE NEXT row from result-set. + * Must return: + * - For SELECT queries: all the rows of the query (2d arrray). + * - For INSERT queries: ID of inserted row. + * - For UPDATE queries: number of updated rows. + * - For other queries: query status (scalar). + * - For error queries: null (and call _setLastError()). + */ + function _performFetch($result) + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + /** + * array _performTotal($arrayQuery) + */ + function _performTotal($arrayQuery) + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + /** + * mixed _performTransaction($mode) + * Start new transaction. + */ + function _performTransaction($mode=null) + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + /** + * mixed _performCommit() + * Commit the transaction. + */ + function _performCommit() + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + /** + * mixed _performRollback() + * Rollback the transaction. + */ + function _performRollback() + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + /** + * string _performGetPlaceholderIgnoreRe() + * Return regular expression which matches ignored query parts. + * This is needed to skip placeholder replacement inside comments, constants etc. + */ + function _performGetPlaceholderIgnoreRe() + { + return ''; + } + + /** + * Returns marker for native database placeholder. E.g. in FireBird it is '?', + * in PostgreSQL - '$1', '$2' etc. + * + * @param int $n Number of native placeholder from the beginning of the query (begins from 0!). + * @return string String representation of native placeholder marker (by default - '?'). + */ + function _performGetNativePlaceholderMarker($n) + { + return '?'; + } + + + /** + * Private methods. + */ + function ____________PRIVATE() {} // for phpEclipse outline + + + /** + * array _query($query, &$total) + * See _performQuery(). + */ + function _query($query, &$total) + { + $this->_resetLastError(); + + // Fetch query attributes. + $this->attributes = $this->_transformQuery($query, 'GET_ATTRIBUTES'); + + // Modify query if needed for total counting. + if ($total) { + $this->_transformQuery($query, 'CALC_TOTAL'); + } + $is_cacher_callable = (is_callable($this->_cacher) || (method_exists($this->_cacher, 'get') && method_exists($this->_cacher, 'save'))); + $rows = null; + $cache_it = false; + if (!empty($this->attributes['CACHE']) && $is_cacher_callable) { + + $hash = $this->_cachePrefix . md5(serialize($query)); + // Getting data from cache if possible + $fetchTime = $firstFetchTime = 0; + $qStart = $this->_microtime(); + $cacheData = $this->_cache($hash); + $queryTime = $this->_microtime() - $qStart; + + $storeTime = isset($cacheData['storeTime']) ? $cacheData['storeTime'] : null; + $invalCache = isset($cacheData['invalCache']) ? $cacheData['invalCache'] : null; + $result = isset($cacheData['result']) ? $cacheData['result'] : null; + $rows = isset($cacheData['rows']) ? $cacheData['rows'] : null; + + + $cache_params = $this->attributes['CACHE']; + + // Calculating cache time to live + $re = '/ + ( + ([0-9]+) #2 - hours + h)? [ \t]* + ( + ([0-9]+) #4 - minutes + m)? [ \t]* + ( + ([0-9]+) #6 - seconds + s?)? (,)? + /sx'; + $m = null; + preg_match($re, $cache_params, $m); + $ttl = @$m[6] + @$m[4] * 60 + @$m[2] * 3600; + // Cutting out time param - now there are just fields for uniqKey or nothing + $cache_params = trim(preg_replace($re, '', $cache_params, 1)); + + $uniq_key = null; + + // UNIQ_KEY calculation + if (!empty($cache_params)) { + $dummy = null; + // There is no need in query, cos' needle in $this->attributes['CACHE'] + $this->_transformQuery($dummy, 'UNIQ_KEY'); + $uniq_key = call_user_func_array(array(&$this, 'select'), $dummy); + $uniq_key = md5(serialize($uniq_key)); + } + // Check TTL? + $ttl = empty($ttl) ? true : (int)$storeTime > (time() - $ttl); + + // Invalidate cache? + if ($ttl && $uniq_key == $invalCache) { + $this->_logQuery($query); + $this->_logQueryStat($queryTime, $fetchTime, $firstFetchTime, $rows); + + } + else $cache_it = true; + } + + if (null === $rows || true === $cache_it) { + $this->_logQuery($query); + + // Run the query (counting time). + $qStart = $this->_microtime(); + $result = $this->_performQuery($query); + $fetchTime = $firstFetchTime = 0; + + if (is_resource($result)) { + $rows = array(); + // Fetch result row by row. + $fStart = $this->_microtime(); + $row = $this->_performFetch($result); + $firstFetchTime = $this->_microtime() - $fStart; + if ($row !== null) { + $rows[] = $row; + while ($row=$this->_performFetch($result)) { + $rows[] = $row; + } + } + $fetchTime = $this->_microtime() - $fStart; + } else { + $rows = $result; + } + $queryTime = $this->_microtime() - $qStart; + + // Log query statistics. + $this->_logQueryStat($queryTime, $fetchTime, $firstFetchTime, $rows); + + // Prepare BLOB objects if needed. + if (is_array($rows) && !empty($this->attributes['BLOB_OBJ'])) { + $blobFieldNames = $this->_performGetBlobFieldNames($result); + foreach ($blobFieldNames as $name) { + for ($r = count($rows)-1; $r>=0; $r--) { + $rows[$r][$name] =& $this->_performNewBlob($rows[$r][$name]); + } + } + } + + // Transform resulting rows. + $result = $this->_transformResult($rows); + + // Storing data in cache + if ($cache_it && $is_cacher_callable) { + $this->_cache( + $hash, + array( + 'storeTime' => time(), + 'invalCache' => $uniq_key, + 'result' => $result, + 'rows' => $rows + ) + ); + } + + } + // Count total number of rows if needed. + if (is_array($result) && $total) { + $this->_transformQuery($query, 'GET_TOTAL'); + $total = call_user_func_array(array(&$this, 'selectCell'), $query); + } + + return $result; + } + + + /** + * mixed _transformQuery(array &$query, string $how) + * + * Transform query different way specified by $how. + * May return some information about performed transform. + */ + function _transformQuery(&$query, $how) + { + // Do overriden transformation. + $result = $this->_performTransformQuery($query, $how); + if ($result === true) return $result; + // Common transformations. + switch ($how) { + case 'GET_ATTRIBUTES': + // Extract query attributes. + $options = array(); + $q = $query[0]; + $m = null; + while (preg_match('/^ \s* -- [ \t]+ (\w+): ([^\r\n]+) [\r\n]* /sx', $q, $m)) { + $options[$m[1]] = trim($m[2]); + $q = substr($q, strlen($m[0])); + } + return $options; + case 'UNIQ_KEY': + $q = $this->attributes['CACHE']; + $i = 0; + $query = " -- UNIQ_KEY\n"; + while(preg_match('/(\w+)\.\w+/sx', $q, $m)) { + if($i > 0)$query .= "\nUNION\n"; + $query .= 'SELECT MAX('.$m[0].') AS M, COUNT(*) AS C FROM '.$m[1]; + $q = substr($q, strlen($m[0])); + $i++; + } + return true; + } + // No such transform. + $this->_setLastError(-1, "No such transform type: $how", $query); + } + + + /** + * void _expandPlaceholders(array &$queryAndArgs, bool $useNative=false) + * Replace placeholders by quoted values. + * Modify $queryAndArgs. + */ + function _expandPlaceholders(&$queryAndArgs, $useNative=false) + { + $cacheCode = null; + if ($this->_logger) { + // Serialize is much faster than placeholder expansion. So use caching. + $cacheCode = md5(serialize($queryAndArgs) . '|' . $useNative . '|' . $this->_identPrefix); + if (isset($this->_placeholderCache[$cacheCode])) { + $queryAndArgs = $this->_placeholderCache[$cacheCode]; + return; + } + } + + if (!is_array($queryAndArgs)) { + $queryAndArgs = array($queryAndArgs); + } + + $this->_placeholderNativeArgs = $useNative? array() : null; + $this->_placeholderArgs = array_reverse($queryAndArgs); + + $query = array_pop($this->_placeholderArgs); // array_pop is faster than array_shift + + // Do all the work. + $this->_placeholderNoValueFound = false; + $query = $this->_expandPlaceholdersFlow($query); + + if ($useNative) { + array_unshift($this->_placeholderNativeArgs, $query); + $queryAndArgs = $this->_placeholderNativeArgs; + } else { + $queryAndArgs = array($query); + } + + if ($cacheCode) { + $this->_placeholderCache[$cacheCode] = $queryAndArgs; + } + } + + + /** + * Do real placeholder processing. + * Imply that all interval variables (_placeholder_*) already prepared. + * May be called recurrent! + */ + function _expandPlaceholdersFlow($query) + { + $re = '{ + (?> + # Ignored chunks. + (?> + # Comment. + -- [^\r\n]* + ) + | + (?> + # DB-specifics. + ' . trim($this->_performGetPlaceholderIgnoreRe()) . ' + ) + ) + | + (?> + # Optional blocks + \{ + # Use "+" here, not "*"! Else nested blocks are not processed well. + ( (?> (?>[^{}]+) | (?R) )* ) #1 + \} + ) + | + (?> + # Placeholder + (\?) ( [_dsafn\#]? ) #2 #3 + ) + }sx'; + $query = preg_replace_callback( + $re, + array(&$this, '_expandPlaceholdersCallback'), + $query + ); + return $query; + } + + + /** + * string _expandPlaceholdersCallback(list $m) + * Internal function to replace placeholders (see preg_replace_callback). + */ + function _expandPlaceholdersCallback($m) + { + // Placeholder. + if (!empty($m[2])) { + $type = $m[3]; + + // Idenifier prefix. + if ($type == '_') { + return $this->_identPrefix; + } + + // Value-based placeholder. + if (!$this->_placeholderArgs) return 'DBSIMPLE_ERROR_NO_VALUE'; + $value = array_pop($this->_placeholderArgs); + + // Skip this value? + if ($value === DBSIMPLE_SKIP) { + $this->_placeholderNoValueFound = true; + return ''; + } + + // First process guaranteed non-native placeholders. + switch ($type) { + case 'a': + if (!$value) $this->_placeholderNoValueFound = true; + if (!is_array($value)) return 'DBSIMPLE_ERROR_VALUE_NOT_ARRAY'; + $parts = array(); + foreach ($value as $k=>$v) { + $v = $v === null? 'NULL' : $this->escape($v); + if (!is_int($k)) { + $k = $this->escape($k, true); + $parts[] = "$k=$v"; + } else { + $parts[] = $v; + } + } + return join(', ', $parts); + case "#": + // Identifier. + if (!is_array($value)) return $this->escape($value, true); + $parts = array(); + foreach ($value as $table => $identifier) { + if (!is_string($identifier)) return 'DBSIMPLE_ERROR_ARRAY_VALUE_NOT_STRING'; + $parts[] = (!is_int($table)? $this->escape($table, true) . '.' : '') . $this->escape($identifier, true); + } + return join(', ', $parts); + case 'n': + // NULL-based placeholder. + return empty($value)? 'NULL' : intval($value); + } + + // Native arguments are not processed. + if ($this->_placeholderNativeArgs !== null) { + $this->_placeholderNativeArgs[] = $value; + return $this->_performGetNativePlaceholderMarker(count($this->_placeholderNativeArgs) - 1); + } + + // In non-native mode arguments are quoted. + if ($value === null) return 'NULL'; + switch ($type) { + case '': + if (!is_scalar($value)) return 'DBSIMPLE_ERROR_VALUE_NOT_SCALAR'; + return $this->escape($value); + case 'd': + return intval($value); + case 'f': + return str_replace(',', '.', floatval($value)); + } + // By default - escape as string. + return $this->escape($value); + } + + // Optional block. + if (isset($m[1]) && strlen($block=$m[1])) { + $prev = @$this->_placeholderNoValueFound; + $block = $this->_expandPlaceholdersFlow($block); + $block = $this->_placeholderNoValueFound? '' : ' ' . $block . ' '; + $this->_placeholderNoValueFound = $prev; // recurrent-safe + return $block; + } + + // Default: skipped part of the string. + return $m[0]; + } + + + /** + * void _setLastError($code, $msg, $query) + * Set last database error context. + * Aditionally expand placeholders. + */ + function _setLastError($code, $msg, $query) + { + if (is_array($query)) { + $this->_expandPlaceholders($query, false); + $query = $query[0]; + } + return DbSimple_Generic_LastError::_setLastError($code, $msg, $query); + } + + + /** + * Return microtime as float value. + */ + function _microtime() + { + $t = explode(" ", microtime()); + return $t[0] + $t[1]; + } + + + /** + * Convert SQL field-list to COUNT(...) clause + * (e.g. 'DISTINCT a AS aa, b AS bb' -> 'COUNT(DISTINCT a, b)'). + */ + function _fieldList2Count($fields) + { + $m = null; + if (preg_match('/^\s* DISTINCT \s* (.*)/sx', $fields, $m)) { + $fields = $m[1]; + $fields = preg_replace('/\s+ AS \s+ .*? (?=,|$)/sx', '', $fields); + return "COUNT(DISTINCT $fields)"; + } else { + return 'COUNT(*)'; + } + } + + + /** + * array _transformResult(list $rows) + * Transform resulting rows to various formats. + */ + function _transformResult($rows) + { + // Process ARRAY_KEY feature. + if (is_array($rows) && $rows) { + // Find ARRAY_KEY* AND PARENT_KEY fields in field list. + $pk = null; + $ak = array(); + foreach (current($rows) as $fieldName => $dummy) { + if (0 == strncasecmp($fieldName, DBSIMPLE_ARRAY_KEY, strlen(DBSIMPLE_ARRAY_KEY))) { + $ak[] = $fieldName; + } else if (0 == strncasecmp($fieldName, DBSIMPLE_PARENT_KEY, strlen(DBSIMPLE_PARENT_KEY))) { + $pk = $fieldName; + } + } + natsort($ak); // sort ARRAY_KEY* using natural comparision + + if ($ak) { + // Tree-based array? Fields: ARRAY_KEY, PARENT_KEY + if ($pk !== null) { + return $this->_transformResultToForest($rows, $ak[0], $pk); + } + // Key-based array? Fields: ARRAY_KEY. + return $this->_transformResultToHash($rows, $ak); + } + } + return $rows; + } + + + /** + * Converts rowset to key-based array. + * + * @param array $rows Two-dimensional array of resulting rows. + * @param array $ak List of ARRAY_KEY* field names. + * @return array Transformed array. + */ + function _transformResultToHash($rows, $arrayKeys) + { + $arrayKeys = (array)$arrayKeys; + $result = array(); + foreach ($rows as $row) { + // Iterate over all of ARRAY_KEY* fields and build array dimensions. + $current =& $result; + foreach ($arrayKeys as $ak) { + $key = $row[$ak]; + unset($row[$ak]); // remove ARRAY_KEY* field from result row + if ($key !== null) { + $current =& $current[$key]; + } else { + // IF ARRAY_KEY field === null, use array auto-indices. + $tmp = array(); + $current[] =& $tmp; + $current =& $tmp; + unset($tmp); // we use $tmp, because don't know the value of auto-index + } + } + $current = $row; // save the row in last dimension + } + return $result; + } + + + /** + * Converts rowset to the forest. + * + * @param array $rows Two-dimensional array of resulting rows. + * @param string $idName Name of ID field. + * @param string $pidName Name of PARENT_ID field. + * @return array Transformed array (tree). + */ + function _transformResultToForest($rows, $idName, $pidName) + { + $children = array(); // children of each ID + $ids = array(); + // Collect who are children of whom. + foreach ($rows as $i=>$r) { + $row =& $rows[$i]; + $id = $row[$idName]; + if ($id === null) { + // Rows without an ID are totally invalid and makes the result tree to + // be empty (because PARENT_ID = null means "a root of the tree"). So + // skip them totally. + continue; + } + $pid = $row[$pidName]; + if ($id == $pid) $pid = null; + $children[$pid][$id] =& $row; + if (!isset($children[$id])) $children[$id] = array(); + $row['childNodes'] =& $children[$id]; + $ids[$id] = true; + } + // Root elements are elements with non-found PIDs. + $forest = array(); + foreach ($rows as $i=>$r) { + $row =& $rows[$i]; + $id = $row[$idName]; + $pid = $row[$pidName]; + if ($pid == $id) $pid = null; + if (!isset($ids[$pid])) { + $forest[$row[$idName]] =& $row; + } + unset($row[$idName]); + unset($row[$pidName]); + } + return $forest; + } + + + /** + * Replaces the last array in a multi-dimensional array $V by its first value. + * Used for selectCol(), when we need to transform (N+1)d resulting array + * to Nd array (column). + */ + function _shrinkLastArrayDimensionCallback(&$v) + { + if (!$v) return; + reset($v); + if (!is_array($firstCell = current($v))) { + $v = $firstCell; + } else { + array_walk($v, array(&$this, '_shrinkLastArrayDimensionCallback')); + } + } + + + /** + * void _logQuery($query, $noTrace=false) + * Must be called on each query. + * If $noTrace is true, library caller is not solved (speed improvement). + */ + function _logQuery($query, $noTrace=false) + { + if (!$this->_logger) return; + $this->_expandPlaceholders($query, false); + $args = array(); + $args[] =& $this; + $args[] = $query[0]; + $args[] = $noTrace? null : $this->findLibraryCaller(); + return call_user_func_array($this->_logger, $args); + } + + + /** + * void _logQueryStat($queryTime, $fetchTime, $firstFetchTime, $rows) + * Log information about performed query statistics. + */ + function _logQueryStat($queryTime, $fetchTime, $firstFetchTime, $rows) + { + // Always increment counters. + $this->_statistics['time'] += $queryTime; + $this->_statistics['count']++; + + // If no logger, economize CPU resources and actually log nothing. + if (!$this->_logger) return; + + $dt = round($queryTime * 1000); + $firstFetchTime = round($firstFetchTime*1000); + $tailFetchTime = round($fetchTime * 1000) - $firstFetchTime; + $log = " -- "; + if ($firstFetchTime + $tailFetchTime) { + $log = sprintf(" -- %d ms = %d+%d".($tailFetchTime? "+%d" : ""), $dt, $dt-$firstFetchTime-$tailFetchTime, $firstFetchTime, $tailFetchTime); + } else { + $log = sprintf(" -- %d ms", $dt); + } + $log .= "; returned "; + + if (!is_array($rows)) { + $log .= $this->escape($rows); + } else { + $detailed = null; + if (count($rows) == 1) { + $len = 0; + $values = array(); + foreach ($rows[0] as $k=>$v) { + $len += strlen($v); + if ($len > $this->MAX_LOG_ROW_LEN) { + break; + } + $values[] = $v === null? 'NULL' : $this->escape($v); + } + if ($len <= $this->MAX_LOG_ROW_LEN) { + $detailed = "(" . preg_replace("/\r?\n/", "\\n", join(', ', $values)) . ")"; + } + } + if ($detailed) { + $log .= $detailed; + } else { + $log .= count($rows). " row(s)"; + } + } + + $this->_logQuery($log, true); + } + + /** + * mixed _cache($hash, $result=null) + * Calls cache mechanism if possible. + */ + function _cache($hash, $result=null) + { + if (is_callable($this->_cacher)) { + return call_user_func($this->_cacher, $hash, $result); + } else if (is_object($this->_cacher) && method_exists($this->_cacher, 'get') && method_exists($this->_cacher, 'save')) { + if (null === $result) + return $this->_cacher->get($hash); + else + $this->_cacher->save($result, $hash); + } + else return false; + } + + + /** + * protected constructor(string $dsn) + * + * Prevent from direct creation of this object. + */ + function DbSimple_Generic_Database() + { + die("This is protected constructor! Do not instantiate directly at ".__FILE__." line ".__LINE__); + } + + // Identifiers prefix (used for ?_ placeholder). + var $_identPrefix = ''; + + // Queries statistics. + var $_statistics = array( + 'time' => 0, + 'count' => 0, + ); + + var $_cachePrefix = ''; + + var $_logger = null; + var $_cacher = null; + var $_placeholderArgs, $_placeholderNativeArgs, $_placeholderCache=array(); + var $_placeholderNoValueFound; + + /** + * When string representation of row (in characters) is greater than this, + * row data will not be logged. + */ + var $MAX_LOG_ROW_LEN = 128; +} + + +/** + * Database BLOB. + * Can read blob chunk by chunk, write data to BLOB. + */ +class DbSimple_Generic_Blob extends DbSimple_Generic_LastError +{ + /** + * string read(int $length) + * Returns following $length bytes from the blob. + */ + function read($len) + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + /** + * string write($data) + * Appends data to blob. + */ + function write($data) + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + /** + * int length() + * Returns length of the blob. + */ + function length() + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } + + /** + * blobid close() + * Closes the blob. Return its ID. No other way to obtain this ID! + */ + function close() + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__); + } +} + + +/** + * Support for error tracking. + * Can hold error messages, error queries and build proper stacktraces. + */ +class DbSimple_Generic_LastError +{ + var $error = null; + var $errmsg = null; + var $errorHandler = null; + var $ignoresInTraceRe = 'DbSimple_.*::.* | call_user_func.*'; + + /** + * abstract void _logQuery($query) + * Must be overriden in derived class. + */ + function _logQuery($query) + { + die("Method must be defined in derived class. Abstract function called at ".__FILE__." line ".__LINE__);; + } + + /** + * void _resetLastError() + * Reset the last error. Must be called on correct queries. + */ + function _resetLastError() + { + $this->error = $this->errmsg = null; + } + + /** + * void _setLastError(int $code, string $message, string $query) + * Fill $this->error property with error information. Error context + * (code initiated the query outside DbSimple) is assigned automatically. + */ + function _setLastError($code, $msg, $query) + { + $context = "unknown"; + if ($t = $this->findLibraryCaller()) { + $context = (isset($t['file'])? $t['file'] : '?') . ' line ' . (isset($t['line'])? $t['line'] : '?'); + } + $this->error = array( + 'code' => $code, + 'message' => rtrim($msg), + 'query' => $query, + 'context' => $context, + ); + $this->errmsg = rtrim($msg) . ($context? " at $context" : ""); + + $this->_logQuery(" -- error #".$code.": ".preg_replace('/(\r?\n)+/s', ' ', $this->errmsg)); + + if (is_callable($this->errorHandler)) { + call_user_func($this->errorHandler, $this->errmsg, $this->error); + } + + return null; + } + + + /** + * callback setErrorHandler(callback $handler) + * Set new error handler called on database errors. + * Handler gets 3 arguments: + * - error message + * - full error context information (last query etc.) + */ + function setErrorHandler($handler) + { + $prev = $this->errorHandler; + $this->errorHandler = $handler; + // In case of setting first error handler for already existed + // error - call the handler now (usual after connect()). + if (!$prev && $this->error) { + call_user_func($this->errorHandler, $this->errmsg, $this->error); + } + return $prev; + } + + /** + * void addIgnoreInTrace($reName) + * Add regular expression matching ClassName::functionName or functionName. + * Matched stack frames will be ignored in stack traces passed to query logger. + */ + function addIgnoreInTrace($name) + { + $this->ignoresInTraceRe .= "|" . $name; + } + + /** + * array of array findLibraryCaller() + * Return part of stacktrace before calling first library method. + * Used in debug purposes (query logging etc.). + */ + function findLibraryCaller() + { + $caller = call_user_func( + array(&$this, 'debug_backtrace_smart'), + $this->ignoresInTraceRe, + true + ); + return $caller; + } + + /** + * array debug_backtrace_smart($ignoresRe=null, $returnCaller=false) + * + * Return stacktrace. Correctly work with call_user_func* + * (totally skip them correcting caller references). + * If $returnCaller is true, return only first matched caller, + * not all stacktrace. + * + * @version 2.03 + */ + function debug_backtrace_smart($ignoresRe=null, $returnCaller=false) + { + if (!is_callable($tracer='debug_backtrace')) return array(); + $trace = $tracer(); + + if ($ignoresRe !== null) $ignoresRe = "/^(?>{$ignoresRe})$/six"; + $smart = array(); + $framesSeen = 0; + for ($i=0, $n=count($trace); $i<$n; $i++) { + $t = $trace[$i]; + if (!$t) continue; + + // Next frame. + $next = isset($trace[$i+1])? $trace[$i+1] : null; + + // Dummy frame before call_user_func* frames. + if (!isset($t['file'])) { + $t['over_function'] = $trace[$i+1]['function']; + $t = $t + $trace[$i+1]; + $trace[$i+1] = null; // skip call_user_func on next iteration + } + + // Skip myself frame. + if (++$framesSeen < 2) continue; + + // 'class' and 'function' field of next frame define where + // this frame function situated. Skip frames for functions + // situated in ignored places. + if ($ignoresRe && $next) { + // Name of function "inside which" frame was generated. + $frameCaller = (isset($next['class'])? $next['class'].'::' : '') . (isset($next['function'])? $next['function'] : ''); + if (preg_match($ignoresRe, $frameCaller)) continue; + } + + // On each iteration we consider ability to add PREVIOUS frame + // to $smart stack. + if ($returnCaller) return $t; + $smart[] = $t; + } + return $smart; + } + +} +?> \ No newline at end of file diff --git a/includes/DbSimple/Mysql.php b/includes/DbSimple/Mysql.php new file mode 100644 index 0000000..ddb3248 --- /dev/null +++ b/includes/DbSimple/Mysql.php @@ -0,0 +1,234 @@ +_setLastError("-1", "MySQL extension is not loaded", "mysql_connect"); + } + $ok = $this->link = @mysql_connect( + $str = $p['host'] . (empty($p['port'])? "" : ":" . $p['port']), + $p['user'], + $p['pass'], + true + ); + $this->_resetLastError(); + if (!$ok) return $this->_setDbError('mysql_connect("' . $str . '", "' . $p['user'] . '")'); + $ok = @mysql_select_db(preg_replace('{^/}s', '', $p['path']), $this->link); + if (!$ok) return $this->_setDbError('mysql_select_db()'); + if (isset($p["charset"])) { + $this->query('SET NAMES ?', $p["charset"]); + } + } + + + function _performEscape($s, $isIdent=false) + { + if (!$isIdent) { + return "'" . mysql_real_escape_string($s, $this->link) . "'"; + } else { + return "`" . str_replace('`', '``', $s) . "`"; + } + } + + + function _performTransaction($parameters=null) + { + return $this->query('BEGIN'); + } + + + function& _performNewBlob($blobid=null) + { + $obj =& new DbSimple_Mysql_Blob($this, $blobid); + return $obj; + } + + + function _performGetBlobFieldNames($result) + { + $blobFields = array(); + for ($i=mysql_num_fields($result)-1; $i>=0; $i--) { + $type = mysql_field_type($result, $i); + if (strpos($type, "BLOB") !== false) $blobFields[] = mysql_field_name($result, $i); + } + return $blobFields; + } + + + function _performGetPlaceholderIgnoreRe() + { + return ' + " (?> [^"\\\\]+|\\\\"|\\\\)* " | + \' (?> [^\'\\\\]+|\\\\\'|\\\\)* \' | + ` (?> [^`]+ | ``)* ` | # backticks + /\* .*? \*/ # comments + '; + } + + + function _performCommit() + { + return $this->query('COMMIT'); + } + + + function _performRollback() + { + return $this->query('ROLLBACK'); + } + + + function _performTransformQuery(&$queryMain, $how) + { + // If we also need to calculate total number of found rows... + switch ($how) { + // Prepare total calculation (if possible) + case 'CALC_TOTAL': + $m = null; + if (preg_match('/^(\s* SELECT)(.*)/six', $queryMain[0], $m)) { + if ($this->_calcFoundRowsAvailable()) { + $queryMain[0] = $m[1] . ' SQL_CALC_FOUND_ROWS' . $m[2]; + } + } + return true; + + // Perform total calculation. + case 'GET_TOTAL': + // Built-in calculation available? + if ($this->_calcFoundRowsAvailable()) { + $queryMain = array('SELECT FOUND_ROWS()'); + } + // Else use manual calculation. + // TODO: GROUP BY ... -> COUNT(DISTINCT ...) + $re = '/^ + (?> -- [^\r\n]* | \s+)* + (\s* SELECT \s+) #1 + (.*?) #2 + (\s+ FROM \s+ .*?) #3 + ((?:\s+ ORDER \s+ BY \s+ .*?)?) #4 + ((?:\s+ LIMIT \s+ \S+ \s* (?:, \s* \S+ \s*)? )?) #5 + $/six'; + $m = null; + if (preg_match($re, $queryMain[0], $m)) { + $query[0] = $m[1] . $this->_fieldList2Count($m[2]) . " AS C" . $m[3]; + $skipTail = substr_count($m[4] . $m[5], '?'); + if ($skipTail) array_splice($query, -$skipTail); + } + return true; + } + + return false; + } + + + function _performQuery($queryMain) + { + $this->_lastQuery = $queryMain; + $this->_expandPlaceholders($queryMain, false); + $result = @mysql_query($queryMain[0], $this->link); + if ($result === false) return $this->_setDbError($queryMain[0]); + if (!is_resource($result)) { + if (preg_match('/^\s* INSERT \s+/six', $queryMain[0])) { + // INSERT queries return generated ID. + return @mysql_insert_id($this->link); + } + // Non-SELECT queries return number of affected rows, SELECT - resource. + return @mysql_affected_rows($this->link); + } + return $result; + } + + + function _performFetch($result) + { + $row = @mysql_fetch_assoc($result); + if (mysql_error()) return $this->_setDbError($this->_lastQuery); + if ($row === false) return null; + return $row; + } + + + function _setDbError($query) + { + if ($this->link) { + return $this->_setLastError(mysql_errno($this->link), mysql_error($this->link), $query); + } else { + return $this->_setLastError(mysql_errno(), mysql_error(), $query); + } + } + + + function _calcFoundRowsAvailable() + { + $ok = version_compare(mysql_get_server_info($this->link), '4.0') >= 0; + return $ok; + } +} + + +class DbSimple_Mysql_Blob extends DbSimple_Generic_Blob +{ + // MySQL does not support separate BLOB fetching. + var $blobdata = null; + var $curSeek = 0; + + function DbSimple_Mysql_Blob(&$database, $blobdata=null) + { + $this->blobdata = $blobdata; + $this->curSeek = 0; + } + + function read($len) + { + $p = $this->curSeek; + $this->curSeek = min($this->curSeek + $len, strlen($this->blobdata)); + return substr($this->blobdata, $this->curSeek, $len); + } + + function write($data) + { + $this->blobdata .= $data; + } + + function close() + { + return $this->blobdata; + } + + function length() + { + return strlen($this->blobdata); + } +} +?> \ No newline at end of file diff --git a/includes/FirePHPCore/FirePHP.class.php b/includes/FirePHPCore/FirePHP.class.php new file mode 100644 index 0000000..67ef84f --- /dev/null +++ b/includes/FirePHPCore/FirePHP.class.php @@ -0,0 +1,1784 @@ + + * @license http://www.opensource.org/licenses/bsd-license.php + * @package FirePHPCore + */ + +/** + * @see http://code.google.com/p/firephp/issues/detail?id=112 + */ +if (!defined('E_STRICT')) { + define('E_STRICT', 2048); +} +if (!defined('E_RECOVERABLE_ERROR')) { + define('E_RECOVERABLE_ERROR', 4096); +} +if (!defined('E_DEPRECATED')) { + define('E_DEPRECATED', 8192); +} +if (!defined('E_USER_DEPRECATED')) { + define('E_USER_DEPRECATED', 16384); +} + +/** + * Sends the given data to the FirePHP Firefox Extension. + * The data can be displayed in the Firebug Console or in the + * "Server" request tab. + * + * For more information see: http://www.firephp.org/ + * + * @copyright Copyright (C) 2007-2009 Christoph Dorn + * @author Christoph Dorn + * @license http://www.opensource.org/licenses/bsd-license.php + * @package FirePHPCore + */ +class FirePHP { + + /** + * FirePHP version + * + * @var string + */ + const VERSION = '0.3'; // @pinf replace '0.3' with '%%package.version%%' + + /** + * Firebug LOG level + * + * Logs a message to firebug console. + * + * @var string + */ + const LOG = 'LOG'; + + /** + * Firebug INFO level + * + * Logs a message to firebug console and displays an info icon before the message. + * + * @var string + */ + const INFO = 'INFO'; + + /** + * Firebug WARN level + * + * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise. + * + * @var string + */ + const WARN = 'WARN'; + + /** + * Firebug ERROR level + * + * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count. + * + * @var string + */ + const ERROR = 'ERROR'; + + /** + * Dumps a variable to firebug's server panel + * + * @var string + */ + const DUMP = 'DUMP'; + + /** + * Displays a stack trace in firebug console + * + * @var string + */ + const TRACE = 'TRACE'; + + /** + * Displays an exception in firebug console + * + * Increments the firebug error count. + * + * @var string + */ + const EXCEPTION = 'EXCEPTION'; + + /** + * Displays an table in firebug console + * + * @var string + */ + const TABLE = 'TABLE'; + + /** + * Starts a group in firebug console + * + * @var string + */ + const GROUP_START = 'GROUP_START'; + + /** + * Ends a group in firebug console + * + * @var string + */ + const GROUP_END = 'GROUP_END'; + + /** + * Singleton instance of FirePHP + * + * @var FirePHP + */ + protected static $instance = null; + + /** + * Flag whether we are logging from within the exception handler + * + * @var boolean + */ + protected $inExceptionHandler = false; + + /** + * Flag whether to throw PHP errors that have been converted to ErrorExceptions + * + * @var boolean + */ + protected $throwErrorExceptions = true; + + /** + * Flag whether to convert PHP assertion errors to Exceptions + * + * @var boolean + */ + protected $convertAssertionErrorsToExceptions = true; + + /** + * Flag whether to throw PHP assertion errors that have been converted to Exceptions + * + * @var boolean + */ + protected $throwAssertionExceptions = false; + + /** + * Wildfire protocol message index + * + * @var int + */ + protected $messageIndex = 1; + + /** + * Options for the library + * + * @var array + */ + protected $options = array('maxDepth' => 10, + 'maxObjectDepth' => 5, + 'maxArrayDepth' => 5, + 'useNativeJsonEncode' => true, + 'includeLineNumbers' => true); + + /** + * Filters used to exclude object members when encoding + * + * @var array + */ + protected $objectFilters = array( + 'firephp' => array('objectStack', 'instance', 'json_objectStack'), + 'firephp_test_class' => array('objectStack', 'instance', 'json_objectStack') + ); + + /** + * A stack of objects used to detect recursion during object encoding + * + * @var object + */ + protected $objectStack = array(); + + /** + * Flag to enable/disable logging + * + * @var boolean + */ + protected $enabled = true; + + /** + * The insight console to log to if applicable + * + * @var object + */ + protected $logToInsightConsole = null; + + /** + * When the object gets serialized only include specific object members. + * + * @return array + */ + public function __sleep() + { + return array('options','objectFilters','enabled'); + } + + /** + * Gets singleton instance of FirePHP + * + * @param boolean $AutoCreate + * @return FirePHP + */ + public static function getInstance($AutoCreate = false) + { + if ($AutoCreate===true && !self::$instance) { + self::init(); + } + return self::$instance; + } + + /** + * Creates FirePHP object and stores it for singleton access + * + * @return FirePHP + */ + public static function init() + { + return self::setInstance(new self()); + } + + /** + * Set the instance of the FirePHP singleton + * + * @param FirePHP $instance The FirePHP object instance + * @return FirePHP + */ + public static function setInstance($instance) + { + return self::$instance = $instance; + } + + /** + * Set an Insight console to direct all logging calls to + * + * @param object $console The console object to log to + * @return void + */ + public function setLogToInsightConsole($console) + { + if(is_string($console)) { + if(get_class($this)!='FirePHP_Insight' && !is_subclass_of($this, 'FirePHP_Insight')) { + throw new Exception('FirePHP instance not an instance or subclass of FirePHP_Insight!'); + } + $this->logToInsightConsole = $this->to('request')->console($console); + } else { + $this->logToInsightConsole = $console; + } + } + + /** + * Enable and disable logging to Firebug + * + * @param boolean $Enabled TRUE to enable, FALSE to disable + * @return void + */ + public function setEnabled($Enabled) + { + $this->enabled = $Enabled; + } + + /** + * Check if logging is enabled + * + * @return boolean TRUE if enabled + */ + public function getEnabled() + { + return $this->enabled; + } + + /** + * Specify a filter to be used when encoding an object + * + * Filters are used to exclude object members. + * + * @param string $Class The class name of the object + * @param array $Filter An array of members to exclude + * @return void + */ + public function setObjectFilter($Class, $Filter) + { + $this->objectFilters[strtolower($Class)] = $Filter; + } + + /** + * Set some options for the library + * + * Options: + * - maxDepth: The maximum depth to traverse (default: 10) + * - maxObjectDepth: The maximum depth to traverse objects (default: 5) + * - maxArrayDepth: The maximum depth to traverse arrays (default: 5) + * - useNativeJsonEncode: If true will use json_encode() (default: true) + * - includeLineNumbers: If true will include line numbers and filenames (default: true) + * + * @param array $Options The options to be set + * @return void + */ + public function setOptions($Options) + { + $this->options = array_merge($this->options,$Options); + } + + /** + * Get options from the library + * + * @return array The currently set options + */ + public function getOptions() + { + return $this->options; + } + + /** + * Set an option for the library + * + * @param string $Name + * @param mixed $Value + * @throws Exception + * @return void + */ + public function setOption($Name, $Value) + { + if (!isset($this->options[$Name])) { + throw $this->newException('Unknown option: ' . $Name); + } + $this->options[$Name] = $Value; + } + + /** + * Get an option from the library + * + * @param string $Name + * @throws Exception + * @return mixed + */ + public function getOption($Name) + { + if (!isset($this->options[$Name])) { + throw $this->newException('Unknown option: ' . $Name); + } + return $this->options[$Name]; + } + + /** + * Register FirePHP as your error handler + * + * Will throw exceptions for each php error. + * + * @return mixed Returns a string containing the previously defined error handler (if any) + */ + public function registerErrorHandler($throwErrorExceptions = false) + { + //NOTE: The following errors will not be caught by this error handler: + // E_ERROR, E_PARSE, E_CORE_ERROR, + // E_CORE_WARNING, E_COMPILE_ERROR, + // E_COMPILE_WARNING, E_STRICT + + $this->throwErrorExceptions = $throwErrorExceptions; + + return set_error_handler(array($this,'errorHandler')); + } + + /** + * FirePHP's error handler + * + * Throws exception for each php error that will occur. + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param int $errline + * @param array $errcontext + */ + public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) + { + // Don't throw exception if error reporting is switched off + if (error_reporting() == 0) { + return; + } + // Only throw exceptions for errors we are asking for + if (error_reporting() & $errno) { + + $exception = new ErrorException($errstr, 0, $errno, $errfile, $errline); + if ($this->throwErrorExceptions) { + throw $exception; + } else { + $this->fb($exception); + } + } + } + + /** + * Register FirePHP as your exception handler + * + * @return mixed Returns the name of the previously defined exception handler, + * or NULL on error. + * If no previous handler was defined, NULL is also returned. + */ + public function registerExceptionHandler() + { + return set_exception_handler(array($this,'exceptionHandler')); + } + + /** + * FirePHP's exception handler + * + * Logs all exceptions to your firebug console and then stops the script. + * + * @param Exception $Exception + * @throws Exception + */ + function exceptionHandler($Exception) + { + + $this->inExceptionHandler = true; + + header('HTTP/1.1 500 Internal Server Error'); + + try { + $this->fb($Exception); + } catch (Exception $e) { + echo 'We had an exception: ' . $e; + } + $this->inExceptionHandler = false; + } + + /** + * Register FirePHP driver as your assert callback + * + * @param boolean $convertAssertionErrorsToExceptions + * @param boolean $throwAssertionExceptions + * @return mixed Returns the original setting or FALSE on errors + */ + public function registerAssertionHandler($convertAssertionErrorsToExceptions = true, $throwAssertionExceptions = false) + { + $this->convertAssertionErrorsToExceptions = $convertAssertionErrorsToExceptions; + $this->throwAssertionExceptions = $throwAssertionExceptions; + + if ($throwAssertionExceptions && !$convertAssertionErrorsToExceptions) { + throw $this->newException('Cannot throw assertion exceptions as assertion errors are not being converted to exceptions!'); + } + + return assert_options(ASSERT_CALLBACK, array($this, 'assertionHandler')); + } + + /** + * FirePHP's assertion handler + * + * Logs all assertions to your firebug console and then stops the script. + * + * @param string $file File source of assertion + * @param int $line Line source of assertion + * @param mixed $code Assertion code + */ + public function assertionHandler($file, $line, $code) + { + if ($this->convertAssertionErrorsToExceptions) { + + $exception = new ErrorException('Assertion Failed - Code[ '.$code.' ]', 0, null, $file, $line); + + if ($this->throwAssertionExceptions) { + throw $exception; + } else { + $this->fb($exception); + } + + } else { + $this->fb($code, 'Assertion Failed', FirePHP::ERROR, array('File'=>$file,'Line'=>$line)); + } + } + + /** + * Start a group for following messages. + * + * Options: + * Collapsed: [true|false] + * Color: [#RRGGBB|ColorName] + * + * @param string $Name + * @param array $Options OPTIONAL Instructions on how to log the group + * @return true + * @throws Exception + */ + public function group($Name, $Options = null) + { + + if (!$Name) { + throw $this->newException('You must specify a label for the group!'); + } + + if ($Options) { + if (!is_array($Options)) { + throw $this->newException('Options must be defined as an array!'); + } + if (array_key_exists('Collapsed', $Options)) { + $Options['Collapsed'] = ($Options['Collapsed'])?'true':'false'; + } + } + + return $this->fb(null, $Name, FirePHP::GROUP_START, $Options); + } + + /** + * Ends a group you have started before + * + * @return true + * @throws Exception + */ + public function groupEnd() + { + return $this->fb(null, null, FirePHP::GROUP_END); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::LOG + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function log($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::LOG, $Options); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::INFO + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function info($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::INFO, $Options); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::WARN + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function warn($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::WARN, $Options); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::ERROR + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function error($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::ERROR, $Options); + } + + /** + * Dumps key and variable to firebug server panel + * + * @see FirePHP::DUMP + * @param string $Key + * @param mixed $Variable + * @return true + * @throws Exception + */ + public function dump($Key, $Variable, $Options = array()) + { + if (!is_string($Key)) { + throw $this->newException('Key passed to dump() is not a string'); + } + if (strlen($Key)>100) { + throw $this->newException('Key passed to dump() is longer than 100 characters'); + } + if (!preg_match_all('/^[a-zA-Z0-9-_\.:]*$/', $Key, $m)) { + throw $this->newException('Key passed to dump() contains invalid characters [a-zA-Z0-9-_\.:]'); + } + return $this->fb($Variable, $Key, FirePHP::DUMP, $Options); + } + + /** + * Log a trace in the firebug console + * + * @see FirePHP::TRACE + * @param string $Label + * @return true + * @throws Exception + */ + public function trace($Label) + { + return $this->fb($Label, FirePHP::TRACE); + } + + /** + * Log a table in the firebug console + * + * @see FirePHP::TABLE + * @param string $Label + * @param string $Table + * @return true + * @throws Exception + */ + public function table($Label, $Table, $Options = array()) + { + return $this->fb($Table, $Label, FirePHP::TABLE, $Options); + } + + /** + * Insight API wrapper + * + * @see Insight_Helper::to() + */ + public static function to() + { + $instance = self::getInstance(); + if (!method_exists($instance, "_to")) { + throw new Exception("FirePHP::to() implementation not loaded"); + } + $args = func_get_args(); + return call_user_func_array(array($instance, '_to'), $args); + } + + /** + * Insight API wrapper + * + * @see Insight_Helper::plugin() + */ + public static function plugin() + { + $instance = self::getInstance(); + if (!method_exists($instance, "_plugin")) { + throw new Exception("FirePHP::plugin() implementation not loaded"); + } + $args = func_get_args(); + return call_user_func_array(array($instance, '_plugin'), $args); + } + + /** + * Check if FirePHP is installed on client + * + * @return boolean + */ + public function detectClientExtension() + { + // Check if FirePHP is installed on client via User-Agent header + if (@preg_match_all('/\sFirePHP\/([\.\d]*)\s?/si',$this->getUserAgent(),$m) && + version_compare($m[1][0],'0.0.6','>=')) { + return true; + } else + // Check if FirePHP is installed on client via X-FirePHP-Version header + if (@preg_match_all('/^([\.\d]*)$/si',$this->getRequestHeader("X-FirePHP-Version"),$m) && + version_compare($m[1][0],'0.0.6','>=')) { + return true; + } + return false; + } + + /** + * Log varible to Firebug + * + * @see http://www.firephp.org/Wiki/Reference/Fb + * @param mixed $Object The variable to be logged + * @return true Return TRUE if message was added to headers, FALSE otherwise + * @throws Exception + */ + public function fb($Object) + { + if($this instanceof FirePHP_Insight && method_exists($this, '_logUpgradeClientMessage')) { + if(!FirePHP_Insight::$upgradeClientMessageLogged) { // avoid infinite recursion as _logUpgradeClientMessage() logs a message + $this->_logUpgradeClientMessage(); + } + } + + static $insightGroupStack = array(); + + if (!$this->getEnabled()) { + return false; + } + + if ($this->headersSent($filename, $linenum)) { + // If we are logging from within the exception handler we cannot throw another exception + if ($this->inExceptionHandler) { + // Simply echo the error out to the page + echo '
FirePHP ERROR: Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.
'; + } else { + throw $this->newException('Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.'); + } + } + + $Type = null; + $Label = null; + $Options = array(); + + if (func_num_args()==1) { + } else + if (func_num_args()==2) { + switch(func_get_arg(1)) { + case self::LOG: + case self::INFO: + case self::WARN: + case self::ERROR: + case self::DUMP: + case self::TRACE: + case self::EXCEPTION: + case self::TABLE: + case self::GROUP_START: + case self::GROUP_END: + $Type = func_get_arg(1); + break; + default: + $Label = func_get_arg(1); + break; + } + } else + if (func_num_args()==3) { + $Type = func_get_arg(2); + $Label = func_get_arg(1); + } else + if (func_num_args()==4) { + $Type = func_get_arg(2); + $Label = func_get_arg(1); + $Options = func_get_arg(3); + } else { + throw $this->newException('Wrong number of arguments to fb() function!'); + } + + if($this->logToInsightConsole!==null && (get_class($this)=='FirePHP_Insight' || is_subclass_of($this, 'FirePHP_Insight'))) { + $msg = $this->logToInsightConsole; + if ($Object instanceof Exception) { + $Type = self::EXCEPTION; + } + if($Label && $Type!=self::TABLE && $Type!=self::GROUP_START) { + $msg = $msg->label($Label); + } + switch($Type) { + case self::DUMP: + case self::LOG: + return $msg->log($Object); + case self::INFO: + return $msg->info($Object); + case self::WARN: + return $msg->warn($Object); + case self::ERROR: + return $msg->error($Object); + case self::TRACE: + return $msg->trace($Object); + case self::EXCEPTION: + return $this->plugin('engine')->handleException($Object, $msg); + case self::TABLE: + if (isset($Object[0]) && !is_string($Object[0]) && $Label) { + $Object = array($Label, $Object); + } + return $msg->table($Object[0], array_slice($Object[1],1), $Object[1][0]); + case self::GROUP_START: + $insightGroupStack[] = $msg->group(md5($Label))->open(); + return $msg->log($Label); + case self::GROUP_END: + if(count($insightGroupStack)==0) { + throw new Error('Too many groupEnd() as opposed to group() calls!'); + } + $group = array_pop($insightGroupStack); + return $group->close(); + default: + return $msg->log($Object); + } + } + + if (!$this->detectClientExtension()) { + return false; + } + + $meta = array(); + $skipFinalObjectEncode = false; + + if ($Object instanceof Exception) { + + $meta['file'] = $this->_escapeTraceFile($Object->getFile()); + $meta['line'] = $Object->getLine(); + + $trace = $Object->getTrace(); + if ($Object instanceof ErrorException + && isset($trace[0]['function']) + && $trace[0]['function']=='errorHandler' + && isset($trace[0]['class']) + && $trace[0]['class']=='FirePHP') { + + $severity = false; + switch($Object->getSeverity()) { + case E_WARNING: $severity = 'E_WARNING'; break; + case E_NOTICE: $severity = 'E_NOTICE'; break; + case E_USER_ERROR: $severity = 'E_USER_ERROR'; break; + case E_USER_WARNING: $severity = 'E_USER_WARNING'; break; + case E_USER_NOTICE: $severity = 'E_USER_NOTICE'; break; + case E_STRICT: $severity = 'E_STRICT'; break; + case E_RECOVERABLE_ERROR: $severity = 'E_RECOVERABLE_ERROR'; break; + case E_DEPRECATED: $severity = 'E_DEPRECATED'; break; + case E_USER_DEPRECATED: $severity = 'E_USER_DEPRECATED'; break; + } + + $Object = array('Class'=>get_class($Object), + 'Message'=>$severity.': '.$Object->getMessage(), + 'File'=>$this->_escapeTraceFile($Object->getFile()), + 'Line'=>$Object->getLine(), + 'Type'=>'trigger', + 'Trace'=>$this->_escapeTrace(array_splice($trace,2))); + $skipFinalObjectEncode = true; + } else { + $Object = array('Class'=>get_class($Object), + 'Message'=>$Object->getMessage(), + 'File'=>$this->_escapeTraceFile($Object->getFile()), + 'Line'=>$Object->getLine(), + 'Type'=>'throw', + 'Trace'=>$this->_escapeTrace($trace)); + $skipFinalObjectEncode = true; + } + $Type = self::EXCEPTION; + + } else + if ($Type==self::TRACE) { + + $trace = debug_backtrace(); + if (!$trace) return false; + for( $i=0 ; $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' + || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { + /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ + } else + if (isset($trace[$i]['class']) + && isset($trace[$i+1]['file']) + && $trace[$i]['class']=='FirePHP' + && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip fb() */ + } else + if ($trace[$i]['function']=='fb' + || $trace[$i]['function']=='trace' + || $trace[$i]['function']=='send') { + + $Object = array('Class'=>isset($trace[$i]['class'])?$trace[$i]['class']:'', + 'Type'=>isset($trace[$i]['type'])?$trace[$i]['type']:'', + 'Function'=>isset($trace[$i]['function'])?$trace[$i]['function']:'', + 'Message'=>$trace[$i]['args'][0], + 'File'=>isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'', + 'Line'=>isset($trace[$i]['line'])?$trace[$i]['line']:'', + 'Args'=>isset($trace[$i]['args'])?$this->encodeObject($trace[$i]['args']):'', + 'Trace'=>$this->_escapeTrace(array_splice($trace,$i+1))); + + $skipFinalObjectEncode = true; + $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; + $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; + break; + } + } + + } else + if ($Type==self::TABLE) { + + if (isset($Object[0]) && is_string($Object[0])) { + $Object[1] = $this->encodeTable($Object[1]); + } else { + $Object = $this->encodeTable($Object); + } + + $skipFinalObjectEncode = true; + + } else + if ($Type==self::GROUP_START) { + + if (!$Label) { + throw $this->newException('You must specify a label for the group!'); + } + + } else { + if ($Type===null) { + $Type = self::LOG; + } + } + + if ($this->options['includeLineNumbers']) { + if (!isset($meta['file']) || !isset($meta['line'])) { + + $trace = debug_backtrace(); + for( $i=0 ; $trace && $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' + || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { + /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ + } else + if (isset($trace[$i]['class']) + && isset($trace[$i+1]['file']) + && $trace[$i]['class']=='FirePHP' + && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip fb() */ + } else + if (isset($trace[$i]['file']) + && substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip FB::fb() */ + } else { + $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; + $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; + break; + } + } + } + } else { + unset($meta['file']); + unset($meta['line']); + } + + $this->setHeader('X-Wf-Protocol-1','http://meta.wildfirehq.org/Protocol/JsonStream/0.2'); + $this->setHeader('X-Wf-1-Plugin-1','http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'.self::VERSION); + + $structure_index = 1; + if ($Type==self::DUMP) { + $structure_index = 2; + $this->setHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1'); + } else { + $this->setHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'); + } + + if ($Type==self::DUMP) { + $msg = '{"'.$Label.'":'.$this->jsonEncode($Object, $skipFinalObjectEncode).'}'; + } else { + $msg_meta = $Options; + $msg_meta['Type'] = $Type; + if ($Label!==null) { + $msg_meta['Label'] = $Label; + } + if (isset($meta['file']) && !isset($msg_meta['File'])) { + $msg_meta['File'] = $meta['file']; + } + if (isset($meta['line']) && !isset($msg_meta['Line'])) { + $msg_meta['Line'] = $meta['line']; + } + $msg = '['.$this->jsonEncode($msg_meta).','.$this->jsonEncode($Object, $skipFinalObjectEncode).']'; + } + + $parts = explode("\n",chunk_split($msg, 5000, "\n")); + + for( $i=0 ; $i2) { + // Message needs to be split into multiple parts + $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, + (($i==0)?strlen($msg):'') + . '|' . $part . '|' + . (($isetHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, + strlen($part) . '|' . $part . '|'); + } + + $this->messageIndex++; + + if ($this->messageIndex > 99999) { + throw $this->newException('Maximum number (99,999) of messages reached!'); + } + } + } + + $this->setHeader('X-Wf-1-Index',$this->messageIndex-1); + + return true; + } + + /** + * Standardizes path for windows systems. + * + * @param string $Path + * @return string + */ + protected function _standardizePath($Path) + { + return preg_replace('/\\\\+/','/',$Path); + } + + /** + * Escape trace path for windows systems + * + * @param array $Trace + * @return array + */ + protected function _escapeTrace($Trace) + { + if (!$Trace) return $Trace; + for( $i=0 ; $i_escapeTraceFile($Trace[$i]['file']); + } + if (isset($Trace[$i]['args'])) { + $Trace[$i]['args'] = $this->encodeObject($Trace[$i]['args']); + } + } + return $Trace; + } + + /** + * Escape file information of trace for windows systems + * + * @param string $File + * @return string + */ + protected function _escapeTraceFile($File) + { + /* Check if we have a windows filepath */ + if (strpos($File,'\\')) { + /* First strip down to single \ */ + + $file = preg_replace('/\\\\+/','\\',$File); + + return $file; + } + return $File; + } + + /** + * Check if headers have already been sent + * + * @param string $Filename + * @param integer $Linenum + */ + protected function headersSent(&$Filename, &$Linenum) + { + return headers_sent($Filename, $Linenum); + } + + /** + * Send header + * + * @param string $Name + * @param string $Value + */ + protected function setHeader($Name, $Value) + { + return header($Name.': '.$Value); + } + + /** + * Get user agent + * + * @return string|false + */ + protected function getUserAgent() + { + if (!isset($_SERVER['HTTP_USER_AGENT'])) return false; + return $_SERVER['HTTP_USER_AGENT']; + } + + /** + * Get all request headers + * + * @return array + */ + public static function getAllRequestHeaders() { + static $_cached_headers = false; + if($_cached_headers!==false) { + return $_cached_headers; + } + $headers = array(); + if(function_exists('getallheaders')) { + foreach( getallheaders() as $name => $value ) { + $headers[strtolower($name)] = $value; + } + } else { + foreach($_SERVER as $name => $value) { + if(substr($name, 0, 5) == 'HTTP_') { + $headers[strtolower(str_replace(' ', '-', str_replace('_', ' ', substr($name, 5))))] = $value; + } + } + } + return $_cached_headers = $headers; + } + + /** + * Get a request header + * + * @return string|false + */ + protected function getRequestHeader($Name) + { + $headers = self::getAllRequestHeaders(); + if (isset($headers[strtolower($Name)])) { + return $headers[strtolower($Name)]; + } + return false; + } + + /** + * Returns a new exception + * + * @param string $Message + * @return Exception + */ + protected function newException($Message) + { + return new Exception($Message); + } + + /** + * Encode an object into a JSON string + * + * Uses PHP's jeson_encode() if available + * + * @param object $Object The object to be encoded + * @return string The JSON string + */ + public function jsonEncode($Object, $skipObjectEncode = false) + { + if (!$skipObjectEncode) { + $Object = $this->encodeObject($Object); + } + + if (function_exists('json_encode') + && $this->options['useNativeJsonEncode']!=false) { + + return json_encode($Object); + } else { + return $this->json_encode($Object); + } + } + + /** + * Encodes a table by encoding each row and column with encodeObject() + * + * @param array $Table The table to be encoded + * @return array + */ + protected function encodeTable($Table) + { + + if (!$Table) return $Table; + + $new_table = array(); + foreach($Table as $row) { + + if (is_array($row)) { + $new_row = array(); + + foreach($row as $item) { + $new_row[] = $this->encodeObject($item); + } + + $new_table[] = $new_row; + } + } + + return $new_table; + } + + /** + * Encodes an object including members with + * protected and private visibility + * + * @param Object $Object The object to be encoded + * @param int $Depth The current traversal depth + * @return array All members of the object + */ + protected function encodeObject($Object, $ObjectDepth = 1, $ArrayDepth = 1, $MaxDepth = 1) + { + if ($MaxDepth > $this->options['maxDepth']) { + return '** Max Depth ('.$this->options['maxDepth'].') **'; + } + + $return = array(); + + if (is_resource($Object)) { + + return '** '.(string)$Object.' **'; + + } else + if (is_object($Object)) { + + if ($ObjectDepth > $this->options['maxObjectDepth']) { + return '** Max Object Depth ('.$this->options['maxObjectDepth'].') **'; + } + + foreach ($this->objectStack as $refVal) { + if ($refVal === $Object) { + return '** Recursion ('.get_class($Object).') **'; + } + } + array_push($this->objectStack, $Object); + + $return['__className'] = $class = get_class($Object); + $class_lower = strtolower($class); + + $reflectionClass = new ReflectionClass($class); + $properties = array(); + foreach( $reflectionClass->getProperties() as $property) { + $properties[$property->getName()] = $property; + } + + $members = (array)$Object; + + foreach( $properties as $plain_name => $property ) { + + $name = $raw_name = $plain_name; + if ($property->isStatic()) { + $name = 'static:'.$name; + } + if ($property->isPublic()) { + $name = 'public:'.$name; + } else + if ($property->isPrivate()) { + $name = 'private:'.$name; + $raw_name = "\0".$class."\0".$raw_name; + } else + if ($property->isProtected()) { + $name = 'protected:'.$name; + $raw_name = "\0".'*'."\0".$raw_name; + } + + if (!(isset($this->objectFilters[$class_lower]) + && is_array($this->objectFilters[$class_lower]) + && in_array($plain_name,$this->objectFilters[$class_lower]))) { + + if (array_key_exists($raw_name,$members) + && !$property->isStatic()) { + + $return[$name] = $this->encodeObject($members[$raw_name], $ObjectDepth + 1, 1, $MaxDepth + 1); + + } else { + if (method_exists($property,'setAccessible')) { + $property->setAccessible(true); + $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1); + } else + if ($property->isPublic()) { + $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1); + } else { + $return[$name] = '** Need PHP 5.3 to get value **'; + } + } + } else { + $return[$name] = '** Excluded by Filter **'; + } + } + + // Include all members that are not defined in the class + // but exist in the object + foreach( $members as $raw_name => $value ) { + + $name = $raw_name; + + if ($name{0} == "\0") { + $parts = explode("\0", $name); + $name = $parts[2]; + } + + $plain_name = $name; + + if (!isset($properties[$name])) { + $name = 'undeclared:'.$name; + + if (!(isset($this->objectFilters[$class_lower]) + && is_array($this->objectFilters[$class_lower]) + && in_array($plain_name,$this->objectFilters[$class_lower]))) { + + $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1, $MaxDepth + 1); + } else { + $return[$name] = '** Excluded by Filter **'; + } + } + } + + array_pop($this->objectStack); + + } elseif (is_array($Object)) { + + if ($ArrayDepth > $this->options['maxArrayDepth']) { + return '** Max Array Depth ('.$this->options['maxArrayDepth'].') **'; + } + + foreach ($Object as $key => $val) { + + // Encoding the $GLOBALS PHP array causes an infinite loop + // if the recursion is not reset here as it contains + // a reference to itself. This is the only way I have come up + // with to stop infinite recursion in this case. + if ($key=='GLOBALS' + && is_array($val) + && array_key_exists('GLOBALS',$val)) { + $val['GLOBALS'] = '** Recursion (GLOBALS) **'; + } + + $return[$key] = $this->encodeObject($val, 1, $ArrayDepth + 1, $MaxDepth + 1); + } + } else { + if (self::is_utf8($Object)) { + return $Object; + } else { + return utf8_encode($Object); + } + } + return $return; + } + + /** + * Returns true if $string is valid UTF-8 and false otherwise. + * + * @param mixed $str String to be tested + * @return boolean + */ + protected static function is_utf8($str) + { + if(function_exists('mb_detect_encoding')) { + return (mb_detect_encoding($str) == 'UTF-8'); + } + $c=0; $b=0; + $bits=0; + $len=strlen($str); + for($i=0; $i<$len; $i++){ + $c=ord($str[$i]); + if ($c > 128){ + if (($c >= 254)) return false; + elseif ($c >= 252) $bits=6; + elseif ($c >= 248) $bits=5; + elseif ($c >= 240) $bits=4; + elseif ($c >= 224) $bits=3; + elseif ($c >= 192) $bits=2; + else return false; + if (($i+$bits) > $len) return false; + while($bits > 1){ + $i++; + $b=ord($str[$i]); + if ($b < 128 || $b > 191) return false; + $bits--; + } + } + } + return true; + } + + /** + * Converts to and from JSON format. + * + * JSON (JavaScript Object Notation) is a lightweight data-interchange + * format. It is easy for humans to read and write. It is easy for machines + * to parse and generate. It is based on a subset of the JavaScript + * Programming Language, Standard ECMA-262 3rd Edition - December 1999. + * This feature can also be found in Python. JSON is a text format that is + * completely language independent but uses conventions that are familiar + * to programmers of the C-family of languages, including C, C++, C#, Java, + * JavaScript, Perl, TCL, and many others. These properties make JSON an + * ideal data-interchange language. + * + * This package provides a simple encoder and decoder for JSON notation. It + * is intended for use with client-side Javascript applications that make + * use of HTTPRequest to perform server communication functions - data can + * be encoded into JSON notation for use in a client-side javascript, or + * decoded from incoming Javascript requests. JSON format is native to + * Javascript, and can be directly eval()'ed with no further parsing + * overhead + * + * All strings should be in ASCII or UTF-8 format! + * + * LICENSE: Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: Redistributions of source code must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * @category + * @package Services_JSON + * @author Michal Migurski + * @author Matt Knapp + * @author Brett Stimmerman + * @author Christoph Dorn + * @copyright 2005 Michal Migurski + * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + + + /** + * Keep a list of objects as we descend into the array so we can detect recursion. + */ + private $json_objectStack = array(); + + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + private function json_utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if (function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + private function json_encode($var) + { + + if (is_object($var)) { + if (in_array($var,$this->json_objectStack)) { + return '"** Recursion **"'; + } + } + + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + + $this->json_objectStack[] = $var; + + $properties = array_map(array($this, 'json_name_value'), + array_keys($var), + array_values($var)); + + array_pop($this->json_objectStack); + + foreach($properties as $property) { + if ($property instanceof Exception) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + $this->json_objectStack[] = $var; + + // treat it like a regular array + $elements = array_map(array($this, 'json_encode'), $var); + + array_pop($this->json_objectStack); + + foreach($elements as $element) { + if ($element instanceof Exception) { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = self::encodeObject($var); + + $this->json_objectStack[] = $var; + + $properties = array_map(array($this, 'json_name_value'), + array_keys($vars), + array_values($vars)); + + array_pop($this->json_objectStack); + + foreach($properties as $property) { + if ($property instanceof Exception) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return null; + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + private function json_name_value($name, $value) + { + // Encoding the $GLOBALS PHP array causes an infinite loop + // if the recursion is not reset here as it contains + // a reference to itself. This is the only way I have come up + // with to stop infinite recursion in this case. + if ($name=='GLOBALS' + && is_array($value) + && array_key_exists('GLOBALS',$value)) { + $value['GLOBALS'] = '** Recursion **'; + } + + $encoded_value = $this->json_encode($value); + + if ($encoded_value instanceof Exception) { + return $encoded_value; + } + + return $this->json_encode(strval($name)) . ':' . $encoded_value; + } + + /** + * @deprecated + */ + public function setProcessorUrl($URL) + { + trigger_error("The FirePHP::setProcessorUrl() method is no longer supported", E_USER_DEPRECATED); + } + + /** + * @deprecated + */ + public function setRendererUrl($URL) + { + trigger_error("The FirePHP::setRendererUrl() method is no longer supported", E_USER_DEPRECATED); + } +} diff --git a/includes/FirePHPCore/LICENSE b/includes/FirePHPCore/LICENSE new file mode 100644 index 0000000..3e390f9 --- /dev/null +++ b/includes/FirePHPCore/LICENSE @@ -0,0 +1,29 @@ +Software License Agreement (New BSD License) + +Copyright (c) 2006-2009, Christoph Dorn +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Christoph Dorn nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/includes/FirePHPCore/fb.php b/includes/FirePHPCore/fb.php new file mode 100644 index 0000000..9ed9c42 --- /dev/null +++ b/includes/FirePHPCore/fb.php @@ -0,0 +1,276 @@ + + * @license http://www.opensource.org/licenses/bsd-license.php + * @package FirePHPCore + */ + +if(!class_exists('FirePHP')) { + require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'FirePHP.class.php'; +} + +/** + * Sends the given data to the FirePHP Firefox Extension. + * The data can be displayed in the Firebug Console or in the + * "Server" request tab. + * + * @see http://www.firephp.org/Wiki/Reference/Fb + * @param mixed $Object + * @return true + * @throws Exception + */ +function fb() +{ + $instance = FirePHP::getInstance(true); + + $args = func_get_args(); + return call_user_func_array(array($instance,'fb'),$args); +} + + +class FB +{ + /** + * Enable and disable logging to Firebug + * + * @see FirePHP->setEnabled() + * @param boolean $Enabled TRUE to enable, FALSE to disable + * @return void + */ + public static function setEnabled($Enabled) + { + $instance = FirePHP::getInstance(true); + $instance->setEnabled($Enabled); + } + + /** + * Check if logging is enabled + * + * @see FirePHP->getEnabled() + * @return boolean TRUE if enabled + */ + public static function getEnabled() + { + $instance = FirePHP::getInstance(true); + return $instance->getEnabled(); + } + + /** + * Specify a filter to be used when encoding an object + * + * Filters are used to exclude object members. + * + * @see FirePHP->setObjectFilter() + * @param string $Class The class name of the object + * @param array $Filter An array or members to exclude + * @return void + */ + public static function setObjectFilter($Class, $Filter) + { + $instance = FirePHP::getInstance(true); + $instance->setObjectFilter($Class, $Filter); + } + + /** + * Set some options for the library + * + * @see FirePHP->setOptions() + * @param array $Options The options to be set + * @return void + */ + public static function setOptions($Options) + { + $instance = FirePHP::getInstance(true); + $instance->setOptions($Options); + } + + /** + * Get options for the library + * + * @see FirePHP->getOptions() + * @return array The options + */ + public static function getOptions() + { + $instance = FirePHP::getInstance(true); + return $instance->getOptions(); + } + + /** + * Log object to firebug + * + * @see http://www.firephp.org/Wiki/Reference/Fb + * @param mixed $Object + * @return true + * @throws Exception + */ + public static function send() + { + $instance = FirePHP::getInstance(true); + $args = func_get_args(); + return call_user_func_array(array($instance,'fb'),$args); + } + + /** + * Start a group for following messages + * + * Options: + * Collapsed: [true|false] + * Color: [#RRGGBB|ColorName] + * + * @param string $Name + * @param array $Options OPTIONAL Instructions on how to log the group + * @return true + */ + public static function group($Name, $Options=null) + { + $instance = FirePHP::getInstance(true); + return $instance->group($Name, $Options); + } + + /** + * Ends a group you have started before + * + * @return true + * @throws Exception + */ + public static function groupEnd() + { + return self::send(null, null, FirePHP::GROUP_END); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::LOG + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function log($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::LOG); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::INFO + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function info($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::INFO); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::WARN + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function warn($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::WARN); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::ERROR + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function error($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::ERROR); + } + + /** + * Dumps key and variable to firebug server panel + * + * @see FirePHP::DUMP + * @param string $Key + * @param mixed $Variable + * @return true + * @throws Exception + */ + public static function dump($Key, $Variable) + { + return self::send($Variable, $Key, FirePHP::DUMP); + } + + /** + * Log a trace in the firebug console + * + * @see FirePHP::TRACE + * @param string $Label + * @return true + * @throws Exception + */ + public static function trace($Label) + { + return self::send($Label, FirePHP::TRACE); + } + + /** + * Log a table in the firebug console + * + * @see FirePHP::TABLE + * @param string $Label + * @param string $Table + * @return true + * @throws Exception + */ + public static function table($Label, $Table) + { + return self::send($Table, $Label, FirePHP::TABLE); + } + +} diff --git a/includes/Smarty/libs/Config_File.class.php b/includes/Smarty/libs/Config_File.class.php new file mode 100644 index 0000000..5787ad1 --- /dev/null +++ b/includes/Smarty/libs/Config_File.class.php @@ -0,0 +1,393 @@ + + * @access public + * @package Smarty + */ + +/* $Id: Config_File.class.php 3149 2009-05-23 20:59:25Z monte.ohrt $ */ + +/** + * Config file reading class + * @package Smarty + */ +class Config_File { + /**#@+ + * Options + * @var boolean + */ + /** + * Controls whether variables with the same name overwrite each other. + */ + var $overwrite = true; + + /** + * Controls whether config values of on/true/yes and off/false/no get + * converted to boolean values automatically. + */ + var $booleanize = true; + + /** + * Controls whether hidden config sections/vars are read from the file. + */ + var $read_hidden = true; + + /** + * Controls whether or not to fix mac or dos formatted newlines. + * If set to true, \r or \r\n will be changed to \n. + */ + var $fix_newlines = true; + /**#@-*/ + + /** @access private */ + var $_config_path = ""; + var $_config_data = array(); + /**#@-*/ + + /** + * Constructs a new config file class. + * + * @param string $config_path (optional) path to the config files + */ + function Config_File($config_path = NULL) + { + if (isset($config_path)) + $this->set_path($config_path); + } + + + /** + * Set the path where configuration files can be found. + * + * @param string $config_path path to the config files + */ + function set_path($config_path) + { + if (!empty($config_path)) { + if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) { + $this->_trigger_error_msg("Bad config file path '$config_path'"); + return; + } + if(substr($config_path, -1) != DIRECTORY_SEPARATOR) { + $config_path .= DIRECTORY_SEPARATOR; + } + + $this->_config_path = $config_path; + } + } + + + /** + * Retrieves config info based on the file, section, and variable name. + * + * @param string $file_name config file to get info for + * @param string $section_name (optional) section to get info for + * @param string $var_name (optional) variable to get info for + * @return string|array a value or array of values + */ + function get($file_name, $section_name = NULL, $var_name = NULL) + { + if (empty($file_name)) { + $this->_trigger_error_msg('Empty config file name'); + return; + } else { + $file_name = $this->_config_path . $file_name; + if (!isset($this->_config_data[$file_name])) + $this->load_file($file_name, false); + } + + if (!empty($var_name)) { + if (empty($section_name)) { + return $this->_config_data[$file_name]["vars"][$var_name]; + } else { + if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name])) + return $this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name]; + else + return array(); + } + } else { + if (empty($section_name)) { + return (array)$this->_config_data[$file_name]["vars"]; + } else { + if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"])) + return (array)$this->_config_data[$file_name]["sections"][$section_name]["vars"]; + else + return array(); + } + } + } + + + /** + * Retrieves config info based on the key. + * + * @param $file_name string config key (filename/section/var) + * @return string|array same as get() + * @uses get() retrieves information from config file and returns it + */ + function &get_key($config_key) + { + list($file_name, $section_name, $var_name) = explode('/', $config_key, 3); + $result = &$this->get($file_name, $section_name, $var_name); + return $result; + } + + /** + * Get all loaded config file names. + * + * @return array an array of loaded config file names + */ + function get_file_names() + { + return array_keys($this->_config_data); + } + + + /** + * Get all section names from a loaded file. + * + * @param string $file_name config file to get section names from + * @return array an array of section names from the specified file + */ + function get_section_names($file_name) + { + $file_name = $this->_config_path . $file_name; + if (!isset($this->_config_data[$file_name])) { + $this->_trigger_error_msg("Unknown config file '$file_name'"); + return; + } + + return array_keys($this->_config_data[$file_name]["sections"]); + } + + + /** + * Get all global or section variable names. + * + * @param string $file_name config file to get info for + * @param string $section_name (optional) section to get info for + * @return array an array of variables names from the specified file/section + */ + function get_var_names($file_name, $section = NULL) + { + if (empty($file_name)) { + $this->_trigger_error_msg('Empty config file name'); + return; + } else if (!isset($this->_config_data[$file_name])) { + $this->_trigger_error_msg("Unknown config file '$file_name'"); + return; + } + + if (empty($section)) + return array_keys($this->_config_data[$file_name]["vars"]); + else + return array_keys($this->_config_data[$file_name]["sections"][$section]["vars"]); + } + + + /** + * Clear loaded config data for a certain file or all files. + * + * @param string $file_name file to clear config data for + */ + function clear($file_name = NULL) + { + if ($file_name === NULL) + $this->_config_data = array(); + else if (isset($this->_config_data[$file_name])) + $this->_config_data[$file_name] = array(); + } + + + /** + * Load a configuration file manually. + * + * @param string $file_name file name to load + * @param boolean $prepend_path whether current config path should be + * prepended to the filename + */ + function load_file($file_name, $prepend_path = true) + { + if ($prepend_path && $this->_config_path != "") + $config_file = $this->_config_path . $file_name; + else + $config_file = $file_name; + + ini_set('track_errors', true); + $fp = @fopen($config_file, "r"); + if (!is_resource($fp)) { + $this->_trigger_error_msg("Could not open config file '$config_file'"); + return false; + } + + $contents = ($size = filesize($config_file)) ? fread($fp, $size) : ''; + fclose($fp); + + $this->_config_data[$config_file] = $this->parse_contents($contents); + return true; + } + + /** + * Store the contents of a file manually. + * + * @param string $config_file file name of the related contents + * @param string $contents the file-contents to parse + */ + function set_file_contents($config_file, $contents) + { + $this->_config_data[$config_file] = $this->parse_contents($contents); + return true; + } + + /** + * parse the source of a configuration file manually. + * + * @param string $contents the file-contents to parse + */ + function parse_contents($contents) + { + if($this->fix_newlines) { + // fix mac/dos formatted newlines + $contents = preg_replace('!\r\n?!', "\n", $contents); + } + + $config_data = array(); + $config_data['sections'] = array(); + $config_data['vars'] = array(); + + /* reference to fill with data */ + $vars =& $config_data['vars']; + + /* parse file line by line */ + preg_match_all('!^.*\r?\n?!m', $contents, $match); + $lines = $match[0]; + for ($i=0, $count=count($lines); $i<$count; $i++) { + $line = $lines[$i]; + if (empty($line)) continue; + + if ( substr($line, 0, 1) == '[' && preg_match('!^\[(.*?)\]!', $line, $match) ) { + /* section found */ + if (substr($match[1], 0, 1) == '.') { + /* hidden section */ + if ($this->read_hidden) { + $section_name = substr($match[1], 1); + } else { + /* break reference to $vars to ignore hidden section */ + unset($vars); + $vars = array(); + continue; + } + } else { + $section_name = $match[1]; + } + if (!isset($config_data['sections'][$section_name])) + $config_data['sections'][$section_name] = array('vars' => array()); + $vars =& $config_data['sections'][$section_name]['vars']; + continue; + } + + if (preg_match('/^\s*(\.?\w+)\s*=\s*(.*)/s', $line, $match)) { + /* variable found */ + $var_name = rtrim($match[1]); + if (strpos($match[2], '"""') === 0) { + /* handle multiline-value */ + $lines[$i] = substr($match[2], 3); + $var_value = ''; + while ($i<$count) { + if (($pos = strpos($lines[$i], '"""')) === false) { + $var_value .= $lines[$i++]; + } else { + /* end of multiline-value */ + $var_value .= substr($lines[$i], 0, $pos); + break; + } + } + $booleanize = false; + + } else { + /* handle simple value */ + $var_value = preg_replace('/^([\'"])(.*)\1$/', '\2', rtrim($match[2])); + $booleanize = $this->booleanize; + + } + $this->_set_config_var($vars, $var_name, $var_value, $booleanize); + } + /* else unparsable line / means it is a comment / means ignore it */ + } + return $config_data; + } + + /**#@+ @access private */ + /** + * @param array &$container + * @param string $var_name + * @param mixed $var_value + * @param boolean $booleanize determines whether $var_value is converted to + * to true/false + */ + function _set_config_var(&$container, $var_name, $var_value, $booleanize) + { + if (substr($var_name, 0, 1) == '.') { + if (!$this->read_hidden) + return; + else + $var_name = substr($var_name, 1); + } + + if (!preg_match("/^[a-zA-Z_]\w*$/", $var_name)) { + $this->_trigger_error_msg("Bad variable name '$var_name'"); + return; + } + + if ($booleanize) { + if (preg_match("/^(on|true|yes)$/i", $var_value)) + $var_value = true; + else if (preg_match("/^(off|false|no)$/i", $var_value)) + $var_value = false; + } + + if (!isset($container[$var_name]) || $this->overwrite) + $container[$var_name] = $var_value; + else { + settype($container[$var_name], 'array'); + $container[$var_name][] = $var_value; + } + } + + /** + * @uses trigger_error() creates a PHP warning/error + * @param string $error_msg + * @param integer $error_type one of + */ + function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING) + { + trigger_error("Config_File error: $error_msg", $error_type); + } + /**#@-*/ +} + +?> diff --git a/includes/Smarty/libs/Smarty.class.php b/includes/Smarty/libs/Smarty.class.php new file mode 100644 index 0000000..e7298f2 --- /dev/null +++ b/includes/Smarty/libs/Smarty.class.php @@ -0,0 +1,1961 @@ + + * @author Andrei Zmievski + * @package Smarty + * @version 2.6.26 + */ + +/* $Id: Smarty.class.php 3163 2009-06-17 14:39:24Z monte.ohrt $ */ + +/** + * DIR_SEP isn't used anymore, but third party apps might + */ +if(!defined('DIR_SEP')) { + define('DIR_SEP', DIRECTORY_SEPARATOR); +} + +/** + * set SMARTY_DIR to absolute path to Smarty library files. + * if not defined, include_path will be used. Sets SMARTY_DIR only if user + * application has not already defined it. + */ + +if (!defined('SMARTY_DIR')) { + define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); +} + +if (!defined('SMARTY_CORE_DIR')) { + define('SMARTY_CORE_DIR', SMARTY_DIR . 'internals' . DIRECTORY_SEPARATOR); +} + +define('SMARTY_PHP_PASSTHRU', 0); +define('SMARTY_PHP_QUOTE', 1); +define('SMARTY_PHP_REMOVE', 2); +define('SMARTY_PHP_ALLOW', 3); + +/** + * @package Smarty + */ +class Smarty +{ + /**#@+ + * Smarty Configuration Section + */ + + /** + * The name of the directory where templates are located. + * + * @var string + */ + var $template_dir = 'templates'; + + /** + * The directory where compiled templates are located. + * + * @var string + */ + var $compile_dir = 'templates_c'; + + /** + * The directory where config files are located. + * + * @var string + */ + var $config_dir = 'configs'; + + /** + * An array of directories searched for plugins. + * + * @var array + */ + var $plugins_dir = array('plugins'); + + /** + * If debugging is enabled, a debug console window will display + * when the page loads (make sure your browser allows unrequested + * popup windows) + * + * @var boolean + */ + var $debugging = false; + + /** + * When set, smarty does uses this value as error_reporting-level. + * + * @var integer + */ + var $error_reporting = null; + + /** + * This is the path to the debug console template. If not set, + * the default one will be used. + * + * @var string + */ + var $debug_tpl = ''; + + /** + * This determines if debugging is enable-able from the browser. + *
    + *
  • NONE => no debugging control allowed
  • + *
  • URL => enable debugging when SMARTY_DEBUG is found in the URL.
  • + *
+ * @link http://www.foo.dom/index.php?SMARTY_DEBUG + * @var string + */ + var $debugging_ctrl = 'NONE'; + + /** + * This tells Smarty whether to check for recompiling or not. Recompiling + * does not need to happen unless a template or config file is changed. + * Typically you enable this during development, and disable for + * production. + * + * @var boolean + */ + var $compile_check = true; + + /** + * This forces templates to compile every time. Useful for development + * or debugging. + * + * @var boolean + */ + var $force_compile = false; + + /** + * This enables template caching. + *
    + *
  • 0 = no caching
  • + *
  • 1 = use class cache_lifetime value
  • + *
  • 2 = use cache_lifetime in cache file
  • + *
+ * @var integer + */ + var $caching = 0; + + /** + * The name of the directory for cache files. + * + * @var string + */ + var $cache_dir = 'cache'; + + /** + * This is the number of seconds cached content will persist. + *
    + *
  • 0 = always regenerate cache
  • + *
  • -1 = never expires
  • + *
+ * + * @var integer + */ + var $cache_lifetime = 3600; + + /** + * Only used when $caching is enabled. If true, then If-Modified-Since headers + * are respected with cached content, and appropriate HTTP headers are sent. + * This way repeated hits to a cached page do not send the entire page to the + * client every time. + * + * @var boolean + */ + var $cache_modified_check = false; + + /** + * This determines how Smarty handles "" tags in templates. + * possible values: + *
    + *
  • SMARTY_PHP_PASSTHRU -> print tags as plain text
  • + *
  • SMARTY_PHP_QUOTE -> escape tags as entities
  • + *
  • SMARTY_PHP_REMOVE -> remove php tags
  • + *
  • SMARTY_PHP_ALLOW -> execute php tags
  • + *
+ * + * @var integer + */ + var $php_handling = SMARTY_PHP_PASSTHRU; + + /** + * This enables template security. When enabled, many things are restricted + * in the templates that normally would go unchecked. This is useful when + * untrusted parties are editing templates and you want a reasonable level + * of security. (no direct execution of PHP in templates for example) + * + * @var boolean + */ + var $security = false; + + /** + * This is the list of template directories that are considered secure. This + * is used only if {@link $security} is enabled. One directory per array + * element. {@link $template_dir} is in this list implicitly. + * + * @var array + */ + var $secure_dir = array(); + + /** + * These are the security settings for Smarty. They are used only when + * {@link $security} is enabled. + * + * @var array + */ + var $security_settings = array( + 'PHP_HANDLING' => false, + 'IF_FUNCS' => array('array', 'list', + 'isset', 'empty', + 'count', 'sizeof', + 'in_array', 'is_array', + 'true', 'false', 'null'), + 'INCLUDE_ANY' => false, + 'PHP_TAGS' => false, + 'MODIFIER_FUNCS' => array('count'), + 'ALLOW_CONSTANTS' => false, + 'ALLOW_SUPER_GLOBALS' => true + ); + + /** + * This is an array of directories where trusted php scripts reside. + * {@link $security} is disabled during their inclusion/execution. + * + * @var array + */ + var $trusted_dir = array(); + + /** + * The left delimiter used for the template tags. + * + * @var string + */ + var $left_delimiter = '{'; + + /** + * The right delimiter used for the template tags. + * + * @var string + */ + var $right_delimiter = '}'; + + /** + * The order in which request variables are registered, similar to + * variables_order in php.ini E = Environment, G = GET, P = POST, + * C = Cookies, S = Server + * + * @var string + */ + var $request_vars_order = 'EGPCS'; + + /** + * Indicates wether $HTTP_*_VARS[] (request_use_auto_globals=false) + * are uses as request-vars or $_*[]-vars. note: if + * request_use_auto_globals is true, then $request_vars_order has + * no effect, but the php-ini-value "gpc_order" + * + * @var boolean + */ + var $request_use_auto_globals = true; + + /** + * Set this if you want different sets of compiled files for the same + * templates. This is useful for things like different languages. + * Instead of creating separate sets of templates per language, you + * set different compile_ids like 'en' and 'de'. + * + * @var string + */ + var $compile_id = null; + + /** + * This tells Smarty whether or not to use sub dirs in the cache/ and + * templates_c/ directories. sub directories better organized, but + * may not work well with PHP safe mode enabled. + * + * @var boolean + * + */ + var $use_sub_dirs = false; + + /** + * This is a list of the modifiers to apply to all template variables. + * Put each modifier in a separate array element in the order you want + * them applied. example: array('escape:"htmlall"'); + * + * @var array + */ + var $default_modifiers = array(); + + /** + * This is the resource type to be used when not specified + * at the beginning of the resource path. examples: + * $smarty->display('file:index.tpl'); + * $smarty->display('db:index.tpl'); + * $smarty->display('index.tpl'); // will use default resource type + * {include file="file:index.tpl"} + * {include file="db:index.tpl"} + * {include file="index.tpl"} {* will use default resource type *} + * + * @var array + */ + var $default_resource_type = 'file'; + + /** + * The function used for cache file handling. If not set, built-in caching is used. + * + * @var null|string function name + */ + var $cache_handler_func = null; + + /** + * This indicates which filters are automatically loaded into Smarty. + * + * @var array array of filter names + */ + var $autoload_filters = array(); + + /**#@+ + * @var boolean + */ + /** + * This tells if config file vars of the same name overwrite each other or not. + * if disabled, same name variables are accumulated in an array. + */ + var $config_overwrite = true; + + /** + * This tells whether or not to automatically booleanize config file variables. + * If enabled, then the strings "on", "true", and "yes" are treated as boolean + * true, and "off", "false" and "no" are treated as boolean false. + */ + var $config_booleanize = true; + + /** + * This tells whether hidden sections [.foobar] are readable from the + * tempalates or not. Normally you would never allow this since that is + * the point behind hidden sections: the application can access them, but + * the templates cannot. + */ + var $config_read_hidden = false; + + /** + * This tells whether or not automatically fix newlines in config files. + * It basically converts \r (mac) or \r\n (dos) to \n + */ + var $config_fix_newlines = true; + /**#@-*/ + + /** + * If a template cannot be found, this PHP function will be executed. + * Useful for creating templates on-the-fly or other special action. + * + * @var string function name + */ + var $default_template_handler_func = ''; + + /** + * The file that contains the compiler class. This can a full + * pathname, or relative to the php_include path. + * + * @var string + */ + var $compiler_file = 'Smarty_Compiler.class.php'; + + /** + * The class used for compiling templates. + * + * @var string + */ + var $compiler_class = 'Smarty_Compiler'; + + /** + * The class used to load config vars. + * + * @var string + */ + var $config_class = 'Config_File'; + +/**#@+ + * END Smarty Configuration Section + * There should be no need to touch anything below this line. + * @access private + */ + /** + * where assigned template vars are kept + * + * @var array + */ + var $_tpl_vars = array(); + + /** + * stores run-time $smarty.* vars + * + * @var null|array + */ + var $_smarty_vars = null; + + /** + * keeps track of sections + * + * @var array + */ + var $_sections = array(); + + /** + * keeps track of foreach blocks + * + * @var array + */ + var $_foreach = array(); + + /** + * keeps track of tag hierarchy + * + * @var array + */ + var $_tag_stack = array(); + + /** + * configuration object + * + * @var Config_file + */ + var $_conf_obj = null; + + /** + * loaded configuration settings + * + * @var array + */ + var $_config = array(array('vars' => array(), 'files' => array())); + + /** + * md5 checksum of the string 'Smarty' + * + * @var string + */ + var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; + + /** + * Smarty version number + * + * @var string + */ + var $_version = '2.6.26'; + + /** + * current template inclusion depth + * + * @var integer + */ + var $_inclusion_depth = 0; + + /** + * for different compiled templates + * + * @var string + */ + var $_compile_id = null; + + /** + * text in URL to enable debug mode + * + * @var string + */ + var $_smarty_debug_id = 'SMARTY_DEBUG'; + + /** + * debugging information for debug console + * + * @var array + */ + var $_smarty_debug_info = array(); + + /** + * info that makes up a cache file + * + * @var array + */ + var $_cache_info = array(); + + /** + * default file permissions + * + * @var integer + */ + var $_file_perms = 0644; + + /** + * default dir permissions + * + * @var integer + */ + var $_dir_perms = 0771; + + /** + * registered objects + * + * @var array + */ + var $_reg_objects = array(); + + /** + * table keeping track of plugins + * + * @var array + */ + var $_plugins = array( + 'modifier' => array(), + 'function' => array(), + 'block' => array(), + 'compiler' => array(), + 'prefilter' => array(), + 'postfilter' => array(), + 'outputfilter' => array(), + 'resource' => array(), + 'insert' => array()); + + + /** + * cache serials + * + * @var array + */ + var $_cache_serials = array(); + + /** + * name of optional cache include file + * + * @var string + */ + var $_cache_include = null; + + /** + * indicate if the current code is used in a compiled + * include + * + * @var string + */ + var $_cache_including = false; + + /**#@-*/ + /** + * The class constructor. + */ + function Smarty() + { + $this->assign('SCRIPT_NAME', isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] + : @$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_NAME']); + } + + /** + * assigns values to template variables + * + * @param array|string $tpl_var the template variable name(s) + * @param mixed $value the value to assign + */ + function assign($tpl_var, $value = null) + { + if (is_array($tpl_var)){ + foreach ($tpl_var as $key => $val) { + if ($key != '') { + $this->_tpl_vars[$key] = $val; + } + } + } else { + if ($tpl_var != '') + $this->_tpl_vars[$tpl_var] = $value; + } + } + + /** + * assigns values to template variables by reference + * + * @param string $tpl_var the template variable name + * @param mixed $value the referenced value to assign + */ + function assign_by_ref($tpl_var, &$value) + { + if ($tpl_var != '') + $this->_tpl_vars[$tpl_var] = &$value; + } + + /** + * appends values to template variables + * + * @param array|string $tpl_var the template variable name(s) + * @param mixed $value the value to append + */ + function append($tpl_var, $value=null, $merge=false) + { + if (is_array($tpl_var)) { + // $tpl_var is an array, ignore $value + foreach ($tpl_var as $_key => $_val) { + if ($_key != '') { + if(!@is_array($this->_tpl_vars[$_key])) { + settype($this->_tpl_vars[$_key],'array'); + } + if($merge && is_array($_val)) { + foreach($_val as $_mkey => $_mval) { + $this->_tpl_vars[$_key][$_mkey] = $_mval; + } + } else { + $this->_tpl_vars[$_key][] = $_val; + } + } + } + } else { + if ($tpl_var != '' && isset($value)) { + if(!@is_array($this->_tpl_vars[$tpl_var])) { + settype($this->_tpl_vars[$tpl_var],'array'); + } + if($merge && is_array($value)) { + foreach($value as $_mkey => $_mval) { + $this->_tpl_vars[$tpl_var][$_mkey] = $_mval; + } + } else { + $this->_tpl_vars[$tpl_var][] = $value; + } + } + } + } + + /** + * appends values to template variables by reference + * + * @param string $tpl_var the template variable name + * @param mixed $value the referenced value to append + */ + function append_by_ref($tpl_var, &$value, $merge=false) + { + if ($tpl_var != '' && isset($value)) { + if(!@is_array($this->_tpl_vars[$tpl_var])) { + settype($this->_tpl_vars[$tpl_var],'array'); + } + if ($merge && is_array($value)) { + foreach($value as $_key => $_val) { + $this->_tpl_vars[$tpl_var][$_key] = &$value[$_key]; + } + } else { + $this->_tpl_vars[$tpl_var][] = &$value; + } + } + } + + + /** + * clear the given assigned template variable. + * + * @param string $tpl_var the template variable to clear + */ + function clear_assign($tpl_var) + { + if (is_array($tpl_var)) + foreach ($tpl_var as $curr_var) + unset($this->_tpl_vars[$curr_var]); + else + unset($this->_tpl_vars[$tpl_var]); + } + + + /** + * Registers custom function to be used in templates + * + * @param string $function the name of the template function + * @param string $function_impl the name of the PHP function to register + */ + function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null) + { + $this->_plugins['function'][$function] = + array($function_impl, null, null, false, $cacheable, $cache_attrs); + + } + + /** + * Unregisters custom function + * + * @param string $function name of template function + */ + function unregister_function($function) + { + unset($this->_plugins['function'][$function]); + } + + /** + * Registers object to be used in templates + * + * @param string $object name of template object + * @param object &$object_impl the referenced PHP object to register + * @param null|array $allowed list of allowed methods (empty = all) + * @param boolean $smarty_args smarty argument format, else traditional + * @param null|array $block_functs list of methods that are block format + */ + function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) + { + settype($allowed, 'array'); + settype($smarty_args, 'boolean'); + $this->_reg_objects[$object] = + array(&$object_impl, $allowed, $smarty_args, $block_methods); + } + + /** + * Unregisters object + * + * @param string $object name of template object + */ + function unregister_object($object) + { + unset($this->_reg_objects[$object]); + } + + + /** + * Registers block function to be used in templates + * + * @param string $block name of template block + * @param string $block_impl PHP function to register + */ + function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null) + { + $this->_plugins['block'][$block] = + array($block_impl, null, null, false, $cacheable, $cache_attrs); + } + + /** + * Unregisters block function + * + * @param string $block name of template function + */ + function unregister_block($block) + { + unset($this->_plugins['block'][$block]); + } + + /** + * Registers compiler function + * + * @param string $function name of template function + * @param string $function_impl name of PHP function to register + */ + function register_compiler_function($function, $function_impl, $cacheable=true) + { + $this->_plugins['compiler'][$function] = + array($function_impl, null, null, false, $cacheable); + } + + /** + * Unregisters compiler function + * + * @param string $function name of template function + */ + function unregister_compiler_function($function) + { + unset($this->_plugins['compiler'][$function]); + } + + /** + * Registers modifier to be used in templates + * + * @param string $modifier name of template modifier + * @param string $modifier_impl name of PHP function to register + */ + function register_modifier($modifier, $modifier_impl) + { + $this->_plugins['modifier'][$modifier] = + array($modifier_impl, null, null, false); + } + + /** + * Unregisters modifier + * + * @param string $modifier name of template modifier + */ + function unregister_modifier($modifier) + { + unset($this->_plugins['modifier'][$modifier]); + } + + /** + * Registers a resource to fetch a template + * + * @param string $type name of resource + * @param array $functions array of functions to handle resource + */ + function register_resource($type, $functions) + { + if (count($functions)==4) { + $this->_plugins['resource'][$type] = + array($functions, false); + + } elseif (count($functions)==5) { + $this->_plugins['resource'][$type] = + array(array(array(&$functions[0], $functions[1]) + ,array(&$functions[0], $functions[2]) + ,array(&$functions[0], $functions[3]) + ,array(&$functions[0], $functions[4])) + ,false); + + } else { + $this->trigger_error("malformed function-list for '$type' in register_resource"); + + } + } + + /** + * Unregisters a resource + * + * @param string $type name of resource + */ + function unregister_resource($type) + { + unset($this->_plugins['resource'][$type]); + } + + /** + * Registers a prefilter function to apply + * to a template before compiling + * + * @param callback $function + */ + function register_prefilter($function) + { + $this->_plugins['prefilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters a prefilter function + * + * @param callback $function + */ + function unregister_prefilter($function) + { + unset($this->_plugins['prefilter'][$this->_get_filter_name($function)]); + } + + /** + * Registers a postfilter function to apply + * to a compiled template after compilation + * + * @param callback $function + */ + function register_postfilter($function) + { + $this->_plugins['postfilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters a postfilter function + * + * @param callback $function + */ + function unregister_postfilter($function) + { + unset($this->_plugins['postfilter'][$this->_get_filter_name($function)]); + } + + /** + * Registers an output filter function to apply + * to a template output + * + * @param callback $function + */ + function register_outputfilter($function) + { + $this->_plugins['outputfilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters an outputfilter function + * + * @param callback $function + */ + function unregister_outputfilter($function) + { + unset($this->_plugins['outputfilter'][$this->_get_filter_name($function)]); + } + + /** + * load a filter of specified type and name + * + * @param string $type filter type + * @param string $name filter name + */ + function load_filter($type, $name) + { + switch ($type) { + case 'output': + $_params = array('plugins' => array(array($type . 'filter', $name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + break; + + case 'pre': + case 'post': + if (!isset($this->_plugins[$type . 'filter'][$name])) + $this->_plugins[$type . 'filter'][$name] = false; + break; + } + } + + /** + * clear cached content for the given template and cache id + * + * @param string $tpl_file name of template file + * @param string $cache_id name of cache_id + * @param string $compile_id name of compile_id + * @param string $exp_time expiration time + * @return boolean + */ + function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null) + { + + if (!isset($compile_id)) + $compile_id = $this->compile_id; + + if (!isset($tpl_file)) + $compile_id = null; + + $_auto_id = $this->_get_auto_id($cache_id, $compile_id); + + if (!empty($this->cache_handler_func)) { + return call_user_func_array($this->cache_handler_func, + array('clear', &$this, &$dummy, $tpl_file, $cache_id, $compile_id, $exp_time)); + } else { + $_params = array('auto_base' => $this->cache_dir, + 'auto_source' => $tpl_file, + 'auto_id' => $_auto_id, + 'exp_time' => $exp_time); + require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + + } + + + /** + * clear the entire contents of cache (all templates) + * + * @param string $exp_time expire time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + function clear_all_cache($exp_time = null) + { + return $this->clear_cache(null, null, null, $exp_time); + } + + + /** + * test to see if valid cache exists for this template + * + * @param string $tpl_file name of template file + * @param string $cache_id + * @param string $compile_id + * @return string|false results of {@link _read_cache_file()} + */ + function is_cached($tpl_file, $cache_id = null, $compile_id = null) + { + if (!$this->caching) + return false; + + if (!isset($compile_id)) + $compile_id = $this->compile_id; + + $_params = array( + 'tpl_file' => $tpl_file, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id + ); + require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); + return smarty_core_read_cache_file($_params, $this); + } + + + /** + * clear all the assigned template variables. + * + */ + function clear_all_assign() + { + $this->_tpl_vars = array(); + } + + /** + * clears compiled version of specified template resource, + * or all compiled template files if one is not specified. + * This function is for advanced use only, not normally needed. + * + * @param string $tpl_file + * @param string $compile_id + * @param string $exp_time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null) + { + if (!isset($compile_id)) { + $compile_id = $this->compile_id; + } + $_params = array('auto_base' => $this->compile_dir, + 'auto_source' => $tpl_file, + 'auto_id' => $compile_id, + 'exp_time' => $exp_time, + 'extensions' => array('.inc', '.php')); + require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + + /** + * Checks whether requested template exists. + * + * @param string $tpl_file + * @return boolean + */ + function template_exists($tpl_file) + { + $_params = array('resource_name' => $tpl_file, 'quiet'=>true, 'get_source'=>false); + return $this->_fetch_resource_info($_params); + } + + /** + * Returns an array containing template variables + * + * @param string $name + * @param string $type + * @return array + */ + function &get_template_vars($name=null) + { + if(!isset($name)) { + return $this->_tpl_vars; + } elseif(isset($this->_tpl_vars[$name])) { + return $this->_tpl_vars[$name]; + } else { + // var non-existant, return valid reference + $_tmp = null; + return $_tmp; + } + } + + /** + * Returns an array containing config variables + * + * @param string $name + * @param string $type + * @return array + */ + function &get_config_vars($name=null) + { + if(!isset($name) && is_array($this->_config[0])) { + return $this->_config[0]['vars']; + } else if(isset($this->_config[0]['vars'][$name])) { + return $this->_config[0]['vars'][$name]; + } else { + // var non-existant, return valid reference + $_tmp = null; + return $_tmp; + } + } + + /** + * trigger Smarty error + * + * @param string $error_msg + * @param integer $error_type + */ + function trigger_error($error_msg, $error_type = E_USER_WARNING) + { + trigger_error("Smarty error: $error_msg", $error_type); + } + + + /** + * executes & displays the template results + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + */ + function display($resource_name, $cache_id = null, $compile_id = null) + { + $this->fetch($resource_name, $cache_id, $compile_id, true); + } + + /** + * executes & returns or displays the template results + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + * @param boolean $display + */ + function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false) + { + static $_cache_info = array(); + + $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting) + ? $this->error_reporting : error_reporting() & ~E_NOTICE); + + if (!$this->debugging && $this->debugging_ctrl == 'URL') { + $_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']; + if (@strstr($_query_string, $this->_smarty_debug_id)) { + if (@strstr($_query_string, $this->_smarty_debug_id . '=on')) { + // enable debugging for this browser session + @setcookie('SMARTY_DEBUG', true); + $this->debugging = true; + } elseif (@strstr($_query_string, $this->_smarty_debug_id . '=off')) { + // disable debugging for this browser session + @setcookie('SMARTY_DEBUG', false); + $this->debugging = false; + } else { + // enable debugging for this page + $this->debugging = true; + } + } else { + $this->debugging = (bool)($this->request_use_auto_globals ? @$_COOKIE['SMARTY_DEBUG'] : @$GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG']); + } + } + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $_debug_start_time = smarty_core_get_microtime($_params, $this); + $this->_smarty_debug_info[] = array('type' => 'template', + 'filename' => $resource_name, + 'depth' => 0); + $_included_tpls_idx = count($this->_smarty_debug_info) - 1; + } + + if (!isset($compile_id)) { + $compile_id = $this->compile_id; + } + + $this->_compile_id = $compile_id; + $this->_inclusion_depth = 0; + + if ($this->caching) { + // save old cache_info, initialize cache_info + array_push($_cache_info, $this->_cache_info); + $this->_cache_info = array(); + $_params = array( + 'tpl_file' => $resource_name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'results' => null + ); + require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); + if (smarty_core_read_cache_file($_params, $this)) { + $_smarty_results = $_params['results']; + if (!empty($this->_cache_info['insert_tags'])) { + $_params = array('plugins' => $this->_cache_info['insert_tags']); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + $_params = array('results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); + $_smarty_results = smarty_core_process_cached_inserts($_params, $this); + } + if (!empty($this->_cache_info['cache_serials'])) { + $_params = array('results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.process_compiled_include.php'); + $_smarty_results = smarty_core_process_compiled_include($_params, $this); + } + + + if ($display) { + if ($this->debugging) + { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $_debug_start_time; + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + $_smarty_results .= smarty_core_display_debug_console($_params, $this); + } + if ($this->cache_modified_check) { + $_server_vars = ($this->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; + $_last_modified_date = @substr($_server_vars['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_server_vars['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3); + $_gmt_mtime = gmdate('D, d M Y H:i:s', $this->_cache_info['timestamp']).' GMT'; + if (@count($this->_cache_info['insert_tags']) == 0 + && !$this->_cache_serials + && $_gmt_mtime == $_last_modified_date) { + if (php_sapi_name()=='cgi') + header('Status: 304 Not Modified'); + else + header('HTTP/1.1 304 Not Modified'); + + } else { + header('Last-Modified: '.$_gmt_mtime); + echo $_smarty_results; + } + } else { + echo $_smarty_results; + } + error_reporting($_smarty_old_error_level); + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + return true; + } else { + error_reporting($_smarty_old_error_level); + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + return $_smarty_results; + } + } else { + $this->_cache_info['template'][$resource_name] = true; + if ($this->cache_modified_check && $display) { + header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT'); + } + } + } + + // load filters that are marked as autoload + if (count($this->autoload_filters)) { + foreach ($this->autoload_filters as $_filter_type => $_filters) { + foreach ($_filters as $_filter) { + $this->load_filter($_filter_type, $_filter); + } + } + } + + $_smarty_compile_path = $this->_get_compile_path($resource_name); + + // if we just need to display the results, don't perform output + // buffering - for speed + $_cache_including = $this->_cache_including; + $this->_cache_including = false; + if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) { + if ($this->_is_compiled($resource_name, $_smarty_compile_path) + || $this->_compile_resource($resource_name, $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + } else { + ob_start(); + if ($this->_is_compiled($resource_name, $_smarty_compile_path) + || $this->_compile_resource($resource_name, $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + $_smarty_results = ob_get_contents(); + ob_end_clean(); + + foreach ((array)$this->_plugins['outputfilter'] as $_output_filter) { + $_smarty_results = call_user_func_array($_output_filter[0], array($_smarty_results, &$this)); + } + } + + if ($this->caching) { + $_params = array('tpl_file' => $resource_name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php'); + smarty_core_write_cache_file($_params, $this); + require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); + $_smarty_results = smarty_core_process_cached_inserts($_params, $this); + + if ($this->_cache_serials) { + // strip nocache-tags from output + $_smarty_results = preg_replace('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!s' + ,'' + ,$_smarty_results); + } + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + } + $this->_cache_including = $_cache_including; + + if ($display) { + if (isset($_smarty_results)) { echo $_smarty_results; } + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = (smarty_core_get_microtime($_params, $this) - $_debug_start_time); + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + echo smarty_core_display_debug_console($_params, $this); + } + error_reporting($_smarty_old_error_level); + return; + } else { + error_reporting($_smarty_old_error_level); + if (isset($_smarty_results)) { return $_smarty_results; } + } + } + + /** + * load configuration values + * + * @param string $file + * @param string $section + * @param string $scope + */ + function config_load($file, $section = null, $scope = 'global') + { + require_once($this->_get_plugin_filepath('function', 'config_load')); + smarty_function_config_load(array('file' => $file, 'section' => $section, 'scope' => $scope), $this); + } + + /** + * return a reference to a registered object + * + * @param string $name + * @return object + */ + function &get_registered_object($name) { + if (!isset($this->_reg_objects[$name])) + $this->_trigger_fatal_error("'$name' is not a registered object"); + + if (!is_object($this->_reg_objects[$name][0])) + $this->_trigger_fatal_error("registered '$name' is not an object"); + + return $this->_reg_objects[$name][0]; + } + + /** + * clear configuration values + * + * @param string $var + */ + function clear_config($var = null) + { + if(!isset($var)) { + // clear all values + $this->_config = array(array('vars' => array(), + 'files' => array())); + } else { + unset($this->_config[0]['vars'][$var]); + } + } + + /** + * get filepath of requested plugin + * + * @param string $type + * @param string $name + * @return string|false + */ + function _get_plugin_filepath($type, $name) + { + $_params = array('type' => $type, 'name' => $name); + require_once(SMARTY_CORE_DIR . 'core.assemble_plugin_filepath.php'); + return smarty_core_assemble_plugin_filepath($_params, $this); + } + + /** + * test if resource needs compiling + * + * @param string $resource_name + * @param string $compile_path + * @return boolean + */ + function _is_compiled($resource_name, $compile_path) + { + if (!$this->force_compile && file_exists($compile_path)) { + if (!$this->compile_check) { + // no need to check compiled file + return true; + } else { + // get file source and timestamp + $_params = array('resource_name' => $resource_name, 'get_source'=>false); + if (!$this->_fetch_resource_info($_params)) { + return false; + } + if ($_params['resource_timestamp'] <= filemtime($compile_path)) { + // template not expired, no recompile + return true; + } else { + // compile template + return false; + } + } + } else { + // compiled template does not exist, or forced compile + return false; + } + } + + /** + * compile the template + * + * @param string $resource_name + * @param string $compile_path + * @return boolean + */ + function _compile_resource($resource_name, $compile_path) + { + + $_params = array('resource_name' => $resource_name); + if (!$this->_fetch_resource_info($_params)) { + return false; + } + + $_source_content = $_params['source_content']; + $_cache_include = substr($compile_path, 0, -4).'.inc'; + + if ($this->_compile_source($resource_name, $_source_content, $_compiled_content, $_cache_include)) { + // if a _cache_serial was set, we also have to write an include-file: + if ($this->_cache_include_info) { + require_once(SMARTY_CORE_DIR . 'core.write_compiled_include.php'); + smarty_core_write_compiled_include(array_merge($this->_cache_include_info, array('compiled_content'=>$_compiled_content, 'resource_name'=>$resource_name)), $this); + } + + $_params = array('compile_path'=>$compile_path, 'compiled_content' => $_compiled_content); + require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); + smarty_core_write_compiled_resource($_params, $this); + + return true; + } else { + return false; + } + + } + + /** + * compile the given source + * + * @param string $resource_name + * @param string $source_content + * @param string $compiled_content + * @return boolean + */ + function _compile_source($resource_name, &$source_content, &$compiled_content, $cache_include_path=null) + { + if (file_exists(SMARTY_DIR . $this->compiler_file)) { + require_once(SMARTY_DIR . $this->compiler_file); + } else { + // use include_path + require_once($this->compiler_file); + } + + + $smarty_compiler = new $this->compiler_class; + + $smarty_compiler->template_dir = $this->template_dir; + $smarty_compiler->compile_dir = $this->compile_dir; + $smarty_compiler->plugins_dir = $this->plugins_dir; + $smarty_compiler->config_dir = $this->config_dir; + $smarty_compiler->force_compile = $this->force_compile; + $smarty_compiler->caching = $this->caching; + $smarty_compiler->php_handling = $this->php_handling; + $smarty_compiler->left_delimiter = $this->left_delimiter; + $smarty_compiler->right_delimiter = $this->right_delimiter; + $smarty_compiler->_version = $this->_version; + $smarty_compiler->security = $this->security; + $smarty_compiler->secure_dir = $this->secure_dir; + $smarty_compiler->security_settings = $this->security_settings; + $smarty_compiler->trusted_dir = $this->trusted_dir; + $smarty_compiler->use_sub_dirs = $this->use_sub_dirs; + $smarty_compiler->_reg_objects = &$this->_reg_objects; + $smarty_compiler->_plugins = &$this->_plugins; + $smarty_compiler->_tpl_vars = &$this->_tpl_vars; + $smarty_compiler->default_modifiers = $this->default_modifiers; + $smarty_compiler->compile_id = $this->_compile_id; + $smarty_compiler->_config = $this->_config; + $smarty_compiler->request_use_auto_globals = $this->request_use_auto_globals; + + if (isset($cache_include_path) && isset($this->_cache_serials[$cache_include_path])) { + $smarty_compiler->_cache_serial = $this->_cache_serials[$cache_include_path]; + } + $smarty_compiler->_cache_include = $cache_include_path; + + + $_results = $smarty_compiler->_compile_file($resource_name, $source_content, $compiled_content); + + if ($smarty_compiler->_cache_serial) { + $this->_cache_include_info = array( + 'cache_serial'=>$smarty_compiler->_cache_serial + ,'plugins_code'=>$smarty_compiler->_plugins_code + ,'include_file_path' => $cache_include_path); + + } else { + $this->_cache_include_info = null; + + } + + return $_results; + } + + /** + * Get the compile path for this resource + * + * @param string $resource_name + * @return string results of {@link _get_auto_filename()} + */ + function _get_compile_path($resource_name) + { + return $this->_get_auto_filename($this->compile_dir, $resource_name, + $this->_compile_id) . '.php'; + } + + /** + * fetch the template info. Gets timestamp, and source + * if get_source is true + * + * sets $source_content to the source of the template, and + * $resource_timestamp to its time stamp + * @param string $resource_name + * @param string $source_content + * @param integer $resource_timestamp + * @param boolean $get_source + * @param boolean $quiet + * @return boolean + */ + + function _fetch_resource_info(&$params) + { + if(!isset($params['get_source'])) { $params['get_source'] = true; } + if(!isset($params['quiet'])) { $params['quiet'] = false; } + + $_return = false; + $_params = array('resource_name' => $params['resource_name']) ; + if (isset($params['resource_base_path'])) + $_params['resource_base_path'] = $params['resource_base_path']; + else + $_params['resource_base_path'] = $this->template_dir; + + if ($this->_parse_resource_name($_params)) { + $_resource_type = $_params['resource_type']; + $_resource_name = $_params['resource_name']; + switch ($_resource_type) { + case 'file': + if ($params['get_source']) { + $params['source_content'] = $this->_read_file($_resource_name); + } + $params['resource_timestamp'] = filemtime($_resource_name); + $_return = is_file($_resource_name) && is_readable($_resource_name); + break; + + default: + // call resource functions to fetch the template source and timestamp + if ($params['get_source']) { + $_source_return = isset($this->_plugins['resource'][$_resource_type]) && + call_user_func_array($this->_plugins['resource'][$_resource_type][0][0], + array($_resource_name, &$params['source_content'], &$this)); + } else { + $_source_return = true; + } + + $_timestamp_return = isset($this->_plugins['resource'][$_resource_type]) && + call_user_func_array($this->_plugins['resource'][$_resource_type][0][1], + array($_resource_name, &$params['resource_timestamp'], &$this)); + + $_return = $_source_return && $_timestamp_return; + break; + } + } + + if (!$_return) { + // see if we can get a template with the default template handler + if (!empty($this->default_template_handler_func)) { + if (!is_callable($this->default_template_handler_func)) { + $this->trigger_error("default template handler function \"$this->default_template_handler_func\" doesn't exist."); + } else { + $_return = call_user_func_array( + $this->default_template_handler_func, + array($_params['resource_type'], $_params['resource_name'], &$params['source_content'], &$params['resource_timestamp'], &$this)); + } + } + } + + if (!$_return) { + if (!$params['quiet']) { + $this->trigger_error('unable to read resource: "' . $params['resource_name'] . '"'); + } + } else if ($_return && $this->security) { + require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); + if (!smarty_core_is_secure($_params, $this)) { + if (!$params['quiet']) + $this->trigger_error('(secure mode) accessing "' . $params['resource_name'] . '" is not allowed'); + $params['source_content'] = null; + $params['resource_timestamp'] = null; + return false; + } + } + return $_return; + } + + + /** + * parse out the type and name from the resource + * + * @param string $resource_base_path + * @param string $resource_name + * @param string $resource_type + * @param string $resource_name + * @return boolean + */ + + function _parse_resource_name(&$params) + { + + // split tpl_path by the first colon + $_resource_name_parts = explode(':', $params['resource_name'], 2); + + if (count($_resource_name_parts) == 1) { + // no resource type given + $params['resource_type'] = $this->default_resource_type; + $params['resource_name'] = $_resource_name_parts[0]; + } else { + if(strlen($_resource_name_parts[0]) == 1) { + // 1 char is not resource type, but part of filepath + $params['resource_type'] = $this->default_resource_type; + $params['resource_name'] = $params['resource_name']; + } else { + $params['resource_type'] = $_resource_name_parts[0]; + $params['resource_name'] = $_resource_name_parts[1]; + } + } + + if ($params['resource_type'] == 'file') { + if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $params['resource_name'])) { + // relative pathname to $params['resource_base_path'] + // use the first directory where the file is found + foreach ((array)$params['resource_base_path'] as $_curr_path) { + $_fullpath = $_curr_path . DIRECTORY_SEPARATOR . $params['resource_name']; + if (file_exists($_fullpath) && is_file($_fullpath)) { + $params['resource_name'] = $_fullpath; + return true; + } + // didn't find the file, try include_path + $_params = array('file_path' => $_fullpath); + require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $this)) { + $params['resource_name'] = $_params['new_file_path']; + return true; + } + } + return false; + } else { + /* absolute path */ + return file_exists($params['resource_name']); + } + } elseif (empty($this->_plugins['resource'][$params['resource_type']])) { + $_params = array('type' => $params['resource_type']); + require_once(SMARTY_CORE_DIR . 'core.load_resource_plugin.php'); + smarty_core_load_resource_plugin($_params, $this); + } + + return true; + } + + + /** + * Handle modifiers + * + * @param string|null $modifier_name + * @param array|null $map_array + * @return string result of modifiers + */ + function _run_mod_handler() + { + $_args = func_get_args(); + list($_modifier_name, $_map_array) = array_splice($_args, 0, 2); + list($_func_name, $_tpl_file, $_tpl_line) = + $this->_plugins['modifier'][$_modifier_name]; + + $_var = $_args[0]; + foreach ($_var as $_key => $_val) { + $_args[0] = $_val; + $_var[$_key] = call_user_func_array($_func_name, $_args); + } + return $_var; + } + + /** + * Remove starting and ending quotes from the string + * + * @param string $string + * @return string + */ + function _dequote($string) + { + if ((substr($string, 0, 1) == "'" || substr($string, 0, 1) == '"') && + substr($string, -1) == substr($string, 0, 1)) + return substr($string, 1, -1); + else + return $string; + } + + + /** + * read in a file + * + * @param string $filename + * @return string + */ + function _read_file($filename) + { + if ( file_exists($filename) && is_readable($filename) && ($fd = @fopen($filename, 'rb')) ) { + $contents = ''; + while (!feof($fd)) { + $contents .= fread($fd, 8192); + } + fclose($fd); + return $contents; + } else { + return false; + } + } + + /** + * get a concrete filename for automagically created content + * + * @param string $auto_base + * @param string $auto_source + * @param string $auto_id + * @return string + * @staticvar string|null + * @staticvar string|null + */ + function _get_auto_filename($auto_base, $auto_source = null, $auto_id = null) + { + $_compile_dir_sep = $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'; + $_return = $auto_base . DIRECTORY_SEPARATOR; + + if(isset($auto_id)) { + // make auto_id safe for directory names + $auto_id = str_replace('%7C',$_compile_dir_sep,(urlencode($auto_id))); + // split into separate directories + $_return .= $auto_id . $_compile_dir_sep; + } + + if(isset($auto_source)) { + // make source name safe for filename + $_filename = urlencode(basename($auto_source)); + $_crc32 = sprintf('%08X', crc32($auto_source)); + // prepend %% to avoid name conflicts with + // with $params['auto_id'] names + $_crc32 = substr($_crc32, 0, 2) . $_compile_dir_sep . + substr($_crc32, 0, 3) . $_compile_dir_sep . $_crc32; + $_return .= '%%' . $_crc32 . '%%' . $_filename; + } + + return $_return; + } + + /** + * unlink a file, possibly using expiration time + * + * @param string $resource + * @param integer $exp_time + */ + function _unlink($resource, $exp_time = null) + { + if(isset($exp_time)) { + if(time() - @filemtime($resource) >= $exp_time) { + return @unlink($resource); + } + } else { + return @unlink($resource); + } + } + + /** + * returns an auto_id for auto-file-functions + * + * @param string $cache_id + * @param string $compile_id + * @return string|null + */ + function _get_auto_id($cache_id=null, $compile_id=null) { + if (isset($cache_id)) + return (isset($compile_id)) ? $cache_id . '|' . $compile_id : $cache_id; + elseif(isset($compile_id)) + return $compile_id; + else + return null; + } + + /** + * trigger Smarty plugin error + * + * @param string $error_msg + * @param string $tpl_file + * @param integer $tpl_line + * @param string $file + * @param integer $line + * @param integer $error_type + */ + function _trigger_fatal_error($error_msg, $tpl_file = null, $tpl_line = null, + $file = null, $line = null, $error_type = E_USER_ERROR) + { + if(isset($file) && isset($line)) { + $info = ' ('.basename($file).", line $line)"; + } else { + $info = ''; + } + if (isset($tpl_line) && isset($tpl_file)) { + $this->trigger_error('[in ' . $tpl_file . ' line ' . $tpl_line . "]: $error_msg$info", $error_type); + } else { + $this->trigger_error($error_msg . $info, $error_type); + } + } + + + /** + * callback function for preg_replace, to call a non-cacheable block + * @return string + */ + function _process_compiled_include_callback($match) { + $_func = '_smarty_tplfunc_'.$match[2].'_'.$match[3]; + ob_start(); + $_func($this); + $_ret = ob_get_contents(); + ob_end_clean(); + return $_ret; + } + + + /** + * called for included templates + * + * @param string $_smarty_include_tpl_file + * @param string $_smarty_include_vars + */ + + // $_smarty_include_tpl_file, $_smarty_include_vars + + function _smarty_include($params) + { + if ($this->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $debug_start_time = smarty_core_get_microtime($_params, $this); + $this->_smarty_debug_info[] = array('type' => 'template', + 'filename' => $params['smarty_include_tpl_file'], + 'depth' => ++$this->_inclusion_depth); + $included_tpls_idx = count($this->_smarty_debug_info) - 1; + } + + $this->_tpl_vars = array_merge($this->_tpl_vars, $params['smarty_include_vars']); + + // config vars are treated as local, so push a copy of the + // current ones onto the front of the stack + array_unshift($this->_config, $this->_config[0]); + + $_smarty_compile_path = $this->_get_compile_path($params['smarty_include_tpl_file']); + + + if ($this->_is_compiled($params['smarty_include_tpl_file'], $_smarty_compile_path) + || $this->_compile_resource($params['smarty_include_tpl_file'], $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + + // pop the local vars off the front of the stack + array_shift($this->_config); + + $this->_inclusion_depth--; + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $debug_start_time; + } + + if ($this->caching) { + $this->_cache_info['template'][$params['smarty_include_tpl_file']] = true; + } + } + + + /** + * get or set an array of cached attributes for function that is + * not cacheable + * @return array + */ + function &_smarty_cache_attrs($cache_serial, $count) { + $_cache_attrs =& $this->_cache_info['cache_attrs'][$cache_serial][$count]; + + if ($this->_cache_including) { + /* return next set of cache_attrs */ + $_return = current($_cache_attrs); + next($_cache_attrs); + return $_return; + + } else { + /* add a reference to a new set of cache_attrs */ + $_cache_attrs[] = array(); + return $_cache_attrs[count($_cache_attrs)-1]; + + } + + } + + + /** + * wrapper for include() retaining $this + * @return mixed + */ + function _include($filename, $once=false, $params=null) + { + if ($once) { + return include_once($filename); + } else { + return include($filename); + } + } + + + /** + * wrapper for eval() retaining $this + * @return mixed + */ + function _eval($code, $params=null) + { + return eval($code); + } + + /** + * Extracts the filter name from the given callback + * + * @param callback $function + * @return string + */ + function _get_filter_name($function) + { + if (is_array($function)) { + $_class_name = (is_object($function[0]) ? + get_class($function[0]) : $function[0]); + return $_class_name . '_' . $function[1]; + } + else { + return $function; + } + } + + /**#@-*/ + +} + +/* vim: set expandtab: */ + +?> diff --git a/includes/Smarty/libs/Smarty_Compiler.class.php b/includes/Smarty/libs/Smarty_Compiler.class.php new file mode 100644 index 0000000..1178b84 --- /dev/null +++ b/includes/Smarty/libs/Smarty_Compiler.class.php @@ -0,0 +1,2365 @@ + + * @author Andrei Zmievski + * @version 2.6.26 + * @copyright 2001-2005 New Digital Group, Inc. + * @package Smarty + */ + +/* $Id: Smarty_Compiler.class.php 3163 2009-06-17 14:39:24Z monte.ohrt $ */ + +/** + * Template compiling class + * @package Smarty + */ +class Smarty_Compiler extends Smarty { + + // internal vars + /**#@+ + * @access private + */ + var $_folded_blocks = array(); // keeps folded template blocks + var $_current_file = null; // the current template being compiled + var $_current_line_no = 1; // line number for error messages + var $_capture_stack = array(); // keeps track of nested capture buffers + var $_plugin_info = array(); // keeps track of plugins to load + var $_init_smarty_vars = false; + var $_permitted_tokens = array('true','false','yes','no','on','off','null'); + var $_db_qstr_regexp = null; // regexps are setup in the constructor + var $_si_qstr_regexp = null; + var $_qstr_regexp = null; + var $_func_regexp = null; + var $_reg_obj_regexp = null; + var $_var_bracket_regexp = null; + var $_num_const_regexp = null; + var $_dvar_guts_regexp = null; + var $_dvar_regexp = null; + var $_cvar_regexp = null; + var $_svar_regexp = null; + var $_avar_regexp = null; + var $_mod_regexp = null; + var $_var_regexp = null; + var $_parenth_param_regexp = null; + var $_func_call_regexp = null; + var $_obj_ext_regexp = null; + var $_obj_start_regexp = null; + var $_obj_params_regexp = null; + var $_obj_call_regexp = null; + var $_cacheable_state = 0; + var $_cache_attrs_count = 0; + var $_nocache_count = 0; + var $_cache_serial = null; + var $_cache_include = null; + + var $_strip_depth = 0; + var $_additional_newline = "\n"; + + /**#@-*/ + /** + * The class constructor. + */ + function Smarty_Compiler() + { + // matches double quoted strings: + // "foobar" + // "foo\"bar" + $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'; + + // matches single quoted strings: + // 'foobar' + // 'foo\'bar' + $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''; + + // matches single or double quoted strings + $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')'; + + // matches bracket portion of vars + // [0] + // [foo] + // [$bar] + $this->_var_bracket_regexp = '\[\$?[\w\.]+\]'; + + // matches numerical constants + // 30 + // -12 + // 13.22 + $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)'; + + // matches $ vars (not objects): + // $foo + // $foo.bar + // $foo.bar.foobar + // $foo[0] + // $foo[$bar] + // $foo[5][blah] + // $foo[5].bar[$foobar][4] + $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))'; + $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]'; + $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp + . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?'; + $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp; + + // matches config vars: + // #foo# + // #foobar123_foo# + $this->_cvar_regexp = '\#\w+\#'; + + // matches section vars: + // %foo.bar% + $this->_svar_regexp = '\%\w+\.\w+\%'; + + // matches all valid variables (no quotes, no modifiers) + $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|' + . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')'; + + // matches valid variable syntax: + // $foo + // $foo + // #foo# + // #foo# + // "text" + // "text" + $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')'; + + // matches valid object call (one level of object nesting allowed in parameters): + // $foo->bar + // $foo->bar() + // $foo->bar("text") + // $foo->bar($foo, $bar, "text") + // $foo->bar($foo, "foo") + // $foo->bar->foo() + // $foo->bar->foo->bar() + // $foo->bar($foo->bar) + // $foo->bar($foo->bar()) + // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar)) + $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')'; + $this->_obj_restricted_param_regexp = '(?:' + . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')' + . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)'; + $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|' + . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)'; + $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp + . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)'; + $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)'; + $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)'; + + // matches valid modifier syntax: + // |foo + // |@foo + // |foo:"bar" + // |foo:$bar + // |foo:"bar":$foobar + // |foo|bar + // |foo:$foo->bar + $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|' + . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)'; + + // matches valid function name: + // foo123 + // _foo_bar + $this->_func_regexp = '[a-zA-Z_]\w*'; + + // matches valid registered object: + // foo->bar + $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*'; + + // matches valid parameter values: + // true + // $foo + // $foo|bar + // #foo# + // #foo#|bar + // "text" + // "text"|bar + // $foo->bar + $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' + . $this->_var_regexp . '|' . $this->_num_const_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)'; + + // matches valid parenthesised function parameters: + // + // "text" + // $foo, $bar, "text" + // $foo|bar, "foo"|bar, $foo->bar($foo)|bar + $this->_parenth_param_regexp = '(?:\((?:\w+|' + . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|' + . $this->_param_regexp . ')))*)?\))'; + + // matches valid function call: + // foo() + // foo_bar($foo) + // _foo_bar($foo,"bar") + // foo123($foo,$foo->bar(),"foo") + $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:' + . $this->_parenth_param_regexp . '))'; + } + + /** + * compile a resource + * + * sets $compiled_content to the compiled source + * @param string $resource_name + * @param string $source_content + * @param string $compiled_content + * @return true + */ + function _compile_file($resource_name, $source_content, &$compiled_content) + { + + if ($this->security) { + // do not allow php syntax to be executed unless specified + if ($this->php_handling == SMARTY_PHP_ALLOW && + !$this->security_settings['PHP_HANDLING']) { + $this->php_handling = SMARTY_PHP_PASSTHRU; + } + } + + $this->_load_filters(); + + $this->_current_file = $resource_name; + $this->_current_line_no = 1; + $ldq = preg_quote($this->left_delimiter, '~'); + $rdq = preg_quote($this->right_delimiter, '~'); + + // run template source through prefilter functions + if (count($this->_plugins['prefilter']) > 0) { + foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { + if ($prefilter === false) continue; + if ($prefilter[3] || is_callable($prefilter[0])) { + $source_content = call_user_func_array($prefilter[0], + array($source_content, &$this)); + $this->_plugins['prefilter'][$filter_name][3] = true; + } else { + $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented"); + } + } + } + + /* fetch all special blocks */ + $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s"; + + preg_match_all($search, $source_content, $match, PREG_SET_ORDER); + $this->_folded_blocks = $match; + reset($this->_folded_blocks); + + /* replace special blocks by "{php}" */ + $source_content = preg_replace($search.'e', "'" + . $this->_quote_replace($this->left_delimiter) . 'php' + . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'" + . $this->_quote_replace($this->right_delimiter) + . "'" + , $source_content); + + /* Gather all template tags. */ + preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match); + $template_tags = $_match[1]; + /* Split content by template tags to obtain non-template content. */ + $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content); + + /* loop through text blocks */ + for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) { + /* match anything resembling php tags */ + if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?\s*php\s*[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) { + /* replace tags with placeholders to prevent recursive replacements */ + $sp_match[1] = array_unique($sp_match[1]); + usort($sp_match[1], '_smarty_sort_length'); + for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { + $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]); + } + /* process each one */ + for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { + if ($this->php_handling == SMARTY_PHP_PASSTHRU) { + /* echo php contents */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', ''."\n", $text_blocks[$curr_tb]); + } else if ($this->php_handling == SMARTY_PHP_QUOTE) { + /* quote php tags */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]); + } else if ($this->php_handling == SMARTY_PHP_REMOVE) { + /* remove php tags */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]); + } else { + /* SMARTY_PHP_ALLOW, but echo non php starting tags */ + $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', ''."\n", $sp_match[1][$curr_sp]); + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]); + } + } + } + } + + /* Compile the template tags into PHP code. */ + $compiled_tags = array(); + for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) { + $this->_current_line_no += substr_count($text_blocks[$i], "\n"); + $compiled_tags[] = $this->_compile_tag($template_tags[$i]); + $this->_current_line_no += substr_count($template_tags[$i], "\n"); + } + if (count($this->_tag_stack)>0) { + list($_open_tag, $_line_no) = end($this->_tag_stack); + $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__); + return; + } + + /* Reformat $text_blocks between 'strip' and '/strip' tags, + removing spaces, tabs and newlines. */ + $strip = false; + for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { + if ($compiled_tags[$i] == '{strip}') { + $compiled_tags[$i] = ''; + $strip = true; + /* remove leading whitespaces */ + $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]); + } + if ($strip) { + /* strip all $text_blocks before the next '/strip' */ + for ($j = $i + 1; $j < $for_max; $j++) { + /* remove leading and trailing whitespaces of each line */ + $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]); + if ($compiled_tags[$j] == '{/strip}') { + /* remove trailing whitespaces from the last text_block */ + $text_blocks[$j] = rtrim($text_blocks[$j]); + } + $text_blocks[$j] = ""\'", "\\"=>"\\\\")) . "'; ?>"; + if ($compiled_tags[$j] == '{/strip}') { + $compiled_tags[$j] = "\n"; /* slurped by php, but necessary + if a newline is following the closing strip-tag */ + $strip = false; + $i = $j; + break; + } + } + } + } + $compiled_content = ''; + + $tag_guard = '%%%SMARTYOTG' . md5(uniqid(rand(), true)) . '%%%'; + + /* Interleave the compiled contents and text blocks to get the final result. */ + for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { + if ($compiled_tags[$i] == '') { + // tag result empty, remove first newline from following text block + $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]); + } + // replace legit PHP tags with placeholder + $text_blocks[$i] = str_replace('\n", $compiled_content); + $compiled_content = preg_replace("~(?\n", $compiled_content); + + // recover legit tags + $compiled_content = str_replace($tag_guard, '_cache_serial)) { + $compiled_content = "_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content; + } + + // run compiled template through postfilter functions + if (count($this->_plugins['postfilter']) > 0) { + foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { + if ($postfilter === false) continue; + if ($postfilter[3] || is_callable($postfilter[0])) { + $compiled_content = call_user_func_array($postfilter[0], + array($compiled_content, &$this)); + $this->_plugins['postfilter'][$filter_name][3] = true; + } else { + $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented"); + } + } + } + + // put header at the top of the compiled template + $template_header = "_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; + $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n"; + + /* Emit code to load needed plugins. */ + $this->_plugins_code = ''; + if (count($this->_plugin_info)) { + $_plugins_params = "array('plugins' => array("; + foreach ($this->_plugin_info as $plugin_type => $plugins) { + foreach ($plugins as $plugin_name => $plugin_info) { + $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], "; + $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),'; + } + } + $_plugins_params .= '))'; + $plugins_code = "\n"; + $template_header .= $plugins_code; + $this->_plugin_info = array(); + $this->_plugins_code = $plugins_code; + } + + if ($this->_init_smarty_vars) { + $template_header .= "\n"; + $this->_init_smarty_vars = false; + } + + $compiled_content = $template_header . $compiled_content; + return true; + } + + /** + * Compile a template tag + * + * @param string $template_tag + * @return string + */ + function _compile_tag($template_tag) + { + /* Matched comment. */ + if (substr($template_tag, 0, 1) == '*' && substr($template_tag, -1) == '*') + return ''; + + /* Split tag into two three parts: command, command modifiers and the arguments. */ + if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp + . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)) + (?:\s+(.*))?$ + ~xs', $template_tag, $match)) { + $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__); + } + + $tag_command = $match[1]; + $tag_modifier = isset($match[2]) ? $match[2] : null; + $tag_args = isset($match[3]) ? $match[3] : null; + + if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) { + /* tag name is a variable or object */ + $_return = $this->_parse_var_props($tag_command . $tag_modifier); + return "" . $this->_additional_newline; + } + + /* If the tag name is a registered object, we process it. */ + if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) { + return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier); + } + + switch ($tag_command) { + case 'include': + return $this->_compile_include_tag($tag_args); + + case 'include_php': + return $this->_compile_include_php_tag($tag_args); + + case 'if': + $this->_push_tag('if'); + return $this->_compile_if_tag($tag_args); + + case 'else': + list($_open_tag) = end($this->_tag_stack); + if ($_open_tag != 'if' && $_open_tag != 'elseif') + $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__); + else + $this->_push_tag('else'); + return ''; + + case 'elseif': + list($_open_tag) = end($this->_tag_stack); + if ($_open_tag != 'if' && $_open_tag != 'elseif') + $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__); + if ($_open_tag == 'if') + $this->_push_tag('elseif'); + return $this->_compile_if_tag($tag_args, true); + + case '/if': + $this->_pop_tag('if'); + return ''; + + case 'capture': + return $this->_compile_capture_tag(true, $tag_args); + + case '/capture': + return $this->_compile_capture_tag(false); + + case 'ldelim': + return $this->left_delimiter; + + case 'rdelim': + return $this->right_delimiter; + + case 'section': + $this->_push_tag('section'); + return $this->_compile_section_start($tag_args); + + case 'sectionelse': + $this->_push_tag('sectionelse'); + return ""; + break; + + case '/section': + $_open_tag = $this->_pop_tag('section'); + if ($_open_tag == 'sectionelse') + return ""; + else + return ""; + + case 'foreach': + $this->_push_tag('foreach'); + return $this->_compile_foreach_start($tag_args); + break; + + case 'foreachelse': + $this->_push_tag('foreachelse'); + return ""; + + case '/foreach': + $_open_tag = $this->_pop_tag('foreach'); + if ($_open_tag == 'foreachelse') + return ""; + else + return ""; + break; + + case 'strip': + case '/strip': + if (substr($tag_command, 0, 1)=='/') { + $this->_pop_tag('strip'); + if (--$this->_strip_depth==0) { /* outermost closing {/strip} */ + $this->_additional_newline = "\n"; + return '{' . $tag_command . '}'; + } + } else { + $this->_push_tag('strip'); + if ($this->_strip_depth++==0) { /* outermost opening {strip} */ + $this->_additional_newline = ""; + return '{' . $tag_command . '}'; + } + } + return ''; + + case 'php': + /* handle folded tags replaced by {php} */ + list(, $block) = each($this->_folded_blocks); + $this->_current_line_no += substr_count($block[0], "\n"); + /* the number of matched elements in the regexp in _compile_file() + determins the type of folded tag that was found */ + switch (count($block)) { + case 2: /* comment */ + return ''; + + case 3: /* literal */ + return ""\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline; + + case 4: /* php */ + if ($this->security && !$this->security_settings['PHP_TAGS']) { + $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__); + return; + } + return ''; + } + break; + + case 'insert': + return $this->_compile_insert_tag($tag_args); + + default: + if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) { + return $output; + } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) { + return $output; + } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) { + return $output; + } else { + $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__); + } + + } + } + + + /** + * compile the custom compiler tag + * + * sets $output to the compiled custom compiler tag + * @param string $tag_command + * @param string $tag_args + * @param string $output + * @return boolean + */ + function _compile_compiler_tag($tag_command, $tag_args, &$output) + { + $found = false; + $have_function = true; + + /* + * First we check if the compiler function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['compiler'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['compiler'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "compiler function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_compiler_' . $tag_command; + if (!is_callable($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true); + } + } + + /* + * True return value means that we either found a plugin or a + * dynamically registered function. False means that we didn't and the + * compiler should now emit code to load custom function plugin for this + * tag. + */ + if ($found) { + if ($have_function) { + $output = call_user_func_array($plugin_func, array($tag_args, &$this)); + if($output != '') { + $output = '_push_cacheable_state('compiler', $tag_command) + . $output + . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>'; + } + } else { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + } + return true; + } else { + return false; + } + } + + + /** + * compile block function tag + * + * sets $output to compiled block function tag + * @param string $tag_command + * @param string $tag_args + * @param string $tag_modifier + * @param string $output + * @return boolean + */ + function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output) + { + if (substr($tag_command, 0, 1) == '/') { + $start_tag = false; + $tag_command = substr($tag_command, 1); + } else + $start_tag = true; + + $found = false; + $have_function = true; + + /* + * First we check if the block function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['block'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['block'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "block function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_block_' . $tag_command; + if (!function_exists($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true); + + } + } + + if (!$found) { + return false; + } else if (!$have_function) { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + return true; + } + + /* + * Even though we've located the plugin function, compilation + * happens only once, so the plugin will still need to be loaded + * at runtime for future requests. + */ + $this->_add_plugin('block', $tag_command); + + if ($start_tag) + $this->_push_tag($tag_command); + else + $this->_pop_tag($tag_command); + + if ($start_tag) { + $output = '_push_cacheable_state('block', $tag_command); + $attrs = $this->_parse_attrs($tag_args); + $_cache_attrs=''; + $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs); + $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); '; + $output .= '$_block_repeat=true;' . $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat);'; + $output .= 'while ($_block_repeat) { ob_start(); ?>'; + } else { + $output = '_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat)'; + if ($tag_modifier != '') { + $this->_parse_modifiers($_out_tag_text, $tag_modifier); + } + $output .= '$_block_repeat=false;echo ' . $_out_tag_text . '; } '; + $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>'; + } + + return true; + } + + + /** + * compile custom function tag + * + * @param string $tag_command + * @param string $tag_args + * @param string $tag_modifier + * @return string + */ + function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output) + { + $found = false; + $have_function = true; + + /* + * First we check if the custom function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['function'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['function'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "custom function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_function_' . $tag_command; + if (!function_exists($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true); + + } + } + + if (!$found) { + return false; + } else if (!$have_function) { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + return true; + } + + /* declare plugin to be loaded on display of the template that + we compile right now */ + $this->_add_plugin('function', $tag_command); + + $_cacheable_state = $this->_push_cacheable_state('function', $tag_command); + $attrs = $this->_parse_attrs($tag_args); + $_cache_attrs = ''; + $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs); + + $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)"; + if($tag_modifier != '') { + $this->_parse_modifiers($output, $tag_modifier); + } + + if($output != '') { + $output = '_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline; + } + + return true; + } + + /** + * compile a registered object tag + * + * @param string $tag_command + * @param array $attrs + * @param string $tag_modifier + * @return string + */ + function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier) + { + if (substr($tag_command, 0, 1) == '/') { + $start_tag = false; + $tag_command = substr($tag_command, 1); + } else { + $start_tag = true; + } + + list($object, $obj_comp) = explode('->', $tag_command); + + $arg_list = array(); + if(count($attrs)) { + $_assign_var = false; + foreach ($attrs as $arg_name => $arg_value) { + if($arg_name == 'assign') { + $_assign_var = $arg_value; + unset($attrs['assign']); + continue; + } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + + if($this->_reg_objects[$object][2]) { + // smarty object argument format + $args = "array(".implode(',', (array)$arg_list)."), \$this"; + } else { + // traditional argument format + $args = implode(',', array_values($attrs)); + if (empty($args)) { + $args = ''; + } + } + + $prefix = ''; + $postfix = ''; + $newline = ''; + if(!is_object($this->_reg_objects[$object][0])) { + $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) { + $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) { + // method + if(in_array($obj_comp, $this->_reg_objects[$object][3])) { + // block method + if ($start_tag) { + $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); "; + $prefix .= "\$_block_repeat=true; \$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat); "; + $prefix .= "while (\$_block_repeat) { ob_start();"; + $return = null; + $postfix = ''; + } else { + $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); \$_block_repeat=false;"; + $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat)"; + $postfix = "} array_pop(\$this->_tag_stack);"; + } + } else { + // non-block method + $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)"; + } + } else { + // property + $return = "\$this->_reg_objects['$object'][0]->$obj_comp"; + } + + if($return != null) { + if($tag_modifier != '') { + $this->_parse_modifiers($return, $tag_modifier); + } + + if(!empty($_assign_var)) { + $output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);"; + } else { + $output = 'echo ' . $return . ';'; + $newline = $this->_additional_newline; + } + } else { + $output = ''; + } + + return '" . $newline; + } + + /** + * Compile {insert ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_insert_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $name = $this->_dequote($attrs['name']); + + if (empty($name)) { + return $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__); + } + + if (!preg_match('~^\w+$~', $name)) { + return $this->_syntax_error("'insert: 'name' must be an insert function name", E_USER_ERROR, __FILE__, __LINE__); + } + + if (!empty($attrs['script'])) { + $delayed_loading = true; + } else { + $delayed_loading = false; + } + + foreach ($attrs as $arg_name => $arg_value) { + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + + $this->_add_plugin('insert', $name, $delayed_loading); + + $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))"; + + return "" . $this->_additional_newline; + } + + /** + * Compile {include ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_include_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + if (empty($attrs['file'])) { + $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__); + } + + foreach ($attrs as $arg_name => $arg_value) { + if ($arg_name == 'file') { + $include_file = $arg_value; + continue; + } else if ($arg_name == 'assign') { + $assign_var = $arg_value; + continue; + } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + + $output = '_tpl_vars;\n"; + + + $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))"; + $output .= "\$this->_smarty_include($_params);\n" . + "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . + "unset(\$_smarty_tpl_vars);\n"; + + if (isset($assign_var)) { + $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n"; + } + + $output .= ' ?>'; + + return $output; + + } + + /** + * Compile {include ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_include_php_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + + if (empty($attrs['file'])) { + $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__); + } + + $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']); + $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true'; + + $arg_list = array(); + foreach($attrs as $arg_name => $arg_value) { + if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') { + if(is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + + $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))"; + + return "" . $this->_additional_newline; + } + + + /** + * Compile {section ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_section_start($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + $output = '_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__); + } + + $output .= "unset(\$this->_sections[$section_name]);\n"; + $section_props = "\$this->_sections[$section_name]"; + + foreach ($attrs as $attr_name => $attr_value) { + switch ($attr_name) { + case 'loop': + $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n"; + break; + + case 'show': + if (is_bool($attr_value)) + $show_attr_value = $attr_value ? 'true' : 'false'; + else + $show_attr_value = "(bool)$attr_value"; + $output .= "{$section_props}['show'] = $show_attr_value;\n"; + break; + + case 'name': + $output .= "{$section_props}['$attr_name'] = $attr_value;\n"; + break; + + case 'max': + case 'start': + $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n"; + break; + + case 'step': + $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n"; + break; + + default: + $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__); + break; + } + } + + if (!isset($attrs['show'])) + $output .= "{$section_props}['show'] = true;\n"; + + if (!isset($attrs['loop'])) + $output .= "{$section_props}['loop'] = 1;\n"; + + if (!isset($attrs['max'])) + $output .= "{$section_props}['max'] = {$section_props}['loop'];\n"; + else + $output .= "if ({$section_props}['max'] < 0)\n" . + " {$section_props}['max'] = {$section_props}['loop'];\n"; + + if (!isset($attrs['step'])) + $output .= "{$section_props}['step'] = 1;\n"; + + if (!isset($attrs['start'])) + $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n"; + else { + $output .= "if ({$section_props}['start'] < 0)\n" . + " {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" . + "else\n" . + " {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n"; + } + + $output .= "if ({$section_props}['show']) {\n"; + if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) { + $output .= " {$section_props}['total'] = {$section_props}['loop'];\n"; + } else { + $output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n"; + } + $output .= " if ({$section_props}['total'] == 0)\n" . + " {$section_props}['show'] = false;\n" . + "} else\n" . + " {$section_props}['total'] = 0;\n"; + + $output .= "if ({$section_props}['show']):\n"; + $output .= " + for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1; + {$section_props}['iteration'] <= {$section_props}['total']; + {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n"; + $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n"; + $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n"; + $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n"; + $output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n"; + $output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n"; + + $output .= "?>"; + + return $output; + } + + + /** + * Compile {foreach ...} tag. + * + * @param string $tag_args + * @return string + */ + function _compile_foreach_start($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + if (empty($attrs['from'])) { + return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__); + } + $from = $attrs['from']; + + if (empty($attrs['item'])) { + return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__); + } + $item = $this->_dequote($attrs['item']); + if (!preg_match('~^\w+$~', $item)) { + return $this->_syntax_error("foreach: 'item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); + } + + if (isset($attrs['key'])) { + $key = $this->_dequote($attrs['key']); + if (!preg_match('~^\w+$~', $key)) { + return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); + } + $key_part = "\$this->_tpl_vars['$key'] => "; + } else { + $key = null; + $key_part = ''; + } + + if (isset($attrs['name'])) { + $name = $attrs['name']; + } else { + $name = null; + } + + $output = '_foreach[$name]"; + $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n"; + $output .= "if ({$foreach_props}['total'] > 0):\n"; + $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; + $output .= " {$foreach_props}['iteration']++;\n"; + } else { + $output .= "if (count(\$_from)):\n"; + $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; + } + $output .= '?>'; + + return $output; + } + + + /** + * Compile {capture} .. {/capture} tags + * + * @param boolean $start true if this is the {capture} tag + * @param string $tag_args + * @return string + */ + + function _compile_capture_tag($start, $tag_args = '') + { + $attrs = $this->_parse_attrs($tag_args); + + if ($start) { + $buffer = isset($attrs['name']) ? $attrs['name'] : "'default'"; + $assign = isset($attrs['assign']) ? $attrs['assign'] : null; + $append = isset($attrs['append']) ? $attrs['append'] : null; + + $output = ""; + $this->_capture_stack[] = array($buffer, $assign, $append); + } else { + list($buffer, $assign, $append) = array_pop($this->_capture_stack); + $output = "_smarty_vars['capture'][$buffer] = ob_get_contents(); "; + if (isset($assign)) { + $output .= " \$this->assign($assign, ob_get_contents());"; + } + if (isset($append)) { + $output .= " \$this->append($append, ob_get_contents());"; + } + $output .= "ob_end_clean(); ?>"; + } + + return $output; + } + + /** + * Compile {if ...} tag + * + * @param string $tag_args + * @param boolean $elseif if true, uses elseif instead of if + * @return string + */ + function _compile_if_tag($tag_args, $elseif = false) + { + + /* Tokenize args for 'if' tag. */ + preg_match_all('~(?> + ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call + ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string + \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token + \b\w+\b | # valid word token + \S+ # anything else + )~x', $tag_args, $match); + + $tokens = $match[0]; + + if(empty($tokens)) { + $_error_msg = $elseif ? "'elseif'" : "'if'"; + $_error_msg .= ' statement requires arguments'; + $this->_syntax_error($_error_msg, E_USER_ERROR, __FILE__, __LINE__); + } + + + // make sure we have balanced parenthesis + $token_count = array_count_values($tokens); + if(isset($token_count['(']) && $token_count['('] != $token_count[')']) { + $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__); + } + + $is_arg_stack = array(); + + for ($i = 0; $i < count($tokens); $i++) { + + $token = &$tokens[$i]; + + switch (strtolower($token)) { + case '!': + case '%': + case '!==': + case '==': + case '===': + case '>': + case '<': + case '!=': + case '<>': + case '<<': + case '>>': + case '<=': + case '>=': + case '&&': + case '||': + case '|': + case '^': + case '&': + case '~': + case ')': + case ',': + case '+': + case '-': + case '*': + case '/': + case '@': + break; + + case 'eq': + $token = '=='; + break; + + case 'ne': + case 'neq': + $token = '!='; + break; + + case 'lt': + $token = '<'; + break; + + case 'le': + case 'lte': + $token = '<='; + break; + + case 'gt': + $token = '>'; + break; + + case 'ge': + case 'gte': + $token = '>='; + break; + + case 'and': + $token = '&&'; + break; + + case 'or': + $token = '||'; + break; + + case 'not': + $token = '!'; + break; + + case 'mod': + $token = '%'; + break; + + case '(': + array_push($is_arg_stack, $i); + break; + + case 'is': + /* If last token was a ')', we operate on the parenthesized + expression. The start of the expression is on the stack. + Otherwise, we operate on the last encountered token. */ + if ($tokens[$i-1] == ')') { + $is_arg_start = array_pop($is_arg_stack); + if ($is_arg_start != 0) { + if (preg_match('~^' . $this->_func_regexp . '$~', $tokens[$is_arg_start-1])) { + $is_arg_start--; + } + } + } else + $is_arg_start = $i-1; + /* Construct the argument for 'is' expression, so it knows + what to operate on. */ + $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); + + /* Pass all tokens from next one until the end to the + 'is' expression parsing function. The function will + return modified tokens, where the first one is the result + of the 'is' expression and the rest are the tokens it + didn't touch. */ + $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); + + /* Replace the old tokens with the new ones. */ + array_splice($tokens, $is_arg_start, count($tokens), $new_tokens); + + /* Adjust argument start so that it won't change from the + current position for the next iteration. */ + $i = $is_arg_start; + break; + + default: + if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) { + // function call + if($this->security && + !in_array($token, $this->security_settings['IF_FUNCS'])) { + $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); + } + } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && (strpos('+-*/^%&|', substr($token, -1)) === false) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') { + // variable function call + $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); + } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) { + // object or variable + $token = $this->_parse_var_props($token); + } elseif(is_numeric($token)) { + // number, skip it + } else { + $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__); + } + break; + } + } + + if ($elseif) + return ''; + else + return ''; + } + + + function _compile_arg_list($type, $name, $attrs, &$cache_code) { + $arg_list = array(); + + if (isset($type) && isset($name) + && isset($this->_plugins[$type]) + && isset($this->_plugins[$type][$name]) + && empty($this->_plugins[$type][$name][4]) + && is_array($this->_plugins[$type][$name][5]) + ) { + /* we have a list of parameters that should be cached */ + $_cache_attrs = $this->_plugins[$type][$name][5]; + $_count = $this->_cache_attrs_count++; + $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');"; + + } else { + /* no parameters are cached */ + $_cache_attrs = null; + } + + foreach ($attrs as $arg_name => $arg_value) { + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + if (is_null($arg_value)) + $arg_value = 'null'; + if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) { + $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)"; + } else { + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + return $arg_list; + } + + /** + * Parse is expression + * + * @param string $is_arg + * @param array $tokens + * @return array + */ + function _parse_is_expr($is_arg, $tokens) + { + $expr_end = 0; + $negate_expr = false; + + if (($first_token = array_shift($tokens)) == 'not') { + $negate_expr = true; + $expr_type = array_shift($tokens); + } else + $expr_type = $first_token; + + switch ($expr_type) { + case 'even': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; + } else + $expr = "!(1 & $is_arg)"; + break; + + case 'odd': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; + } else + $expr = "(1 & $is_arg)"; + break; + + case 'div': + if (@$tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")"; + } else { + $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__); + } + break; + + default: + $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__); + break; + } + + if ($negate_expr) { + $expr = "!($expr)"; + } + + array_splice($tokens, 0, $expr_end, $expr); + + return $tokens; + } + + + /** + * Parse attribute string + * + * @param string $tag_args + * @return array + */ + function _parse_attrs($tag_args) + { + + /* Tokenize tag attributes. */ + preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) + )+ | + [=] + ~x', $tag_args, $match); + $tokens = $match[0]; + + $attrs = array(); + /* Parse state: + 0 - expecting attribute name + 1 - expecting '=' + 2 - expecting attribute value (not '=') */ + $state = 0; + + foreach ($tokens as $token) { + switch ($state) { + case 0: + /* If the token is a valid identifier, we set attribute name + and go to state 1. */ + if (preg_match('~^\w+$~', $token)) { + $attr_name = $token; + $state = 1; + } else + $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); + break; + + case 1: + /* If the token is '=', then we go to state 2. */ + if ($token == '=') { + $state = 2; + } else + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + break; + + case 2: + /* If token is not '=', we set the attribute value and go to + state 0. */ + if ($token != '=') { + /* We booleanize the token if it's a non-quoted possible + boolean value. */ + if (preg_match('~^(on|yes|true)$~', $token)) { + $token = 'true'; + } else if (preg_match('~^(off|no|false)$~', $token)) { + $token = 'false'; + } else if ($token == 'null') { + $token = 'null'; + } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) { + /* treat integer literally */ + } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) { + /* treat as a string, double-quote it escaping quotes */ + $token = '"'.addslashes($token).'"'; + } + + $attrs[$attr_name] = $token; + $state = 0; + } else + $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); + break; + } + $last_token = $token; + } + + if($state != 0) { + if($state == 1) { + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + } else { + $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); + } + } + + $this->_parse_vars_props($attrs); + + return $attrs; + } + + /** + * compile multiple variables and section properties tokens into + * PHP code + * + * @param array $tokens + */ + function _parse_vars_props(&$tokens) + { + foreach($tokens as $key => $val) { + $tokens[$key] = $this->_parse_var_props($val); + } + } + + /** + * compile single variable and section properties token into + * PHP code + * + * @param string $val + * @param string $tag_attrs + * @return string + */ + function _parse_var_props($val) + { + $val = trim($val); + + if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) { + // $ variable or object + $return = $this->_parse_var($match[1]); + $modifiers = $match[2]; + if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) { + $_default_mod_string = implode('|',(array)$this->default_modifiers); + $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers; + } + $this->_parse_modifiers($return, $modifiers); + return $return; + } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // double quoted text + preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + $return = $this->_expand_quoted_text($match[1]); + if($match[2] != '') { + $this->_parse_modifiers($return, $match[2]); + } + return $return; + } + elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // numerical constant + preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + if($match[2] != '') { + $this->_parse_modifiers($match[1], $match[2]); + return $match[1]; + } + } + elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // single quoted text + preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + if($match[2] != '') { + $this->_parse_modifiers($match[1], $match[2]); + return $match[1]; + } + } + elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // config var + return $this->_parse_conf_var($val); + } + elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // section var + return $this->_parse_section_prop($val); + } + elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) { + // literal string + return $this->_expand_quoted_text('"' . strtr($val, array('\\' => '\\\\', '"' => '\\"')) .'"'); + } + return $val; + } + + /** + * expand quoted text with embedded variables + * + * @param string $var_expr + * @return string + */ + function _expand_quoted_text($var_expr) + { + // if contains unescaped $, expand it + if(preg_match_all('~(?:\`(?_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?_parse_var(str_replace('`','',$_var)) . ')."'; + } + $var_expr = strtr($var_expr, $_replace); + $_return = preg_replace('~\.""|(?_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE); + + if(count($_math_vars) > 1) { + $_first_var = ""; + $_complete_var = ""; + $_output = ""; + // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter) + foreach($_math_vars as $_k => $_math_var) { + $_math_var = $_math_vars[$_k]; + + if(!empty($_math_var) || is_numeric($_math_var)) { + // hit a math operator, so process the stuff which came before it + if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) { + $_has_math = true; + if(!empty($_complete_var) || is_numeric($_complete_var)) { + $_output .= $this->_parse_var($_complete_var); + } + + // just output the math operator to php + $_output .= $_math_var; + + if(empty($_first_var)) + $_first_var = $_complete_var; + + $_complete_var = ""; + } else { + $_complete_var .= $_math_var; + } + } + } + if($_has_math) { + if(!empty($_complete_var) || is_numeric($_complete_var)) + $_output .= $this->_parse_var($_complete_var); + + // get the modifiers working (only the last var from math + modifier is left) + $var_expr = $_complete_var; + } + } + + // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit) + if(is_numeric(substr($var_expr, 0, 1))) + $_var_ref = $var_expr; + else + $_var_ref = substr($var_expr, 1); + + if(!$_has_math) { + + // get [foo] and .foo and ->foo and (...) pieces + preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match); + + $_indexes = $match[0]; + $_var_name = array_shift($_indexes); + + /* Handle $smarty.* variable references as a special case. */ + if ($_var_name == 'smarty') { + /* + * If the reference could be compiled, use the compiled output; + * otherwise, fall back on the $smarty variable generated at + * run-time. + */ + if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) { + $_output = $smarty_ref; + } else { + $_var_name = substr(array_shift($_indexes), 1); + $_output = "\$this->_smarty_vars['$_var_name']"; + } + } elseif(is_numeric($_var_name) && is_numeric(substr($var_expr, 0, 1))) { + // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers + if(count($_indexes) > 0) + { + $_var_name .= implode("", $_indexes); + $_indexes = array(); + } + $_output = $_var_name; + } else { + $_output = "\$this->_tpl_vars['$_var_name']"; + } + + foreach ($_indexes as $_index) { + if (substr($_index, 0, 1) == '[') { + $_index = substr($_index, 1, -1); + if (is_numeric($_index)) { + $_output .= "[$_index]"; + } elseif (substr($_index, 0, 1) == '$') { + if (strpos($_index, '.') !== false) { + $_output .= '[' . $this->_parse_var($_index) . ']'; + } else { + $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]"; + } + } else { + $_var_parts = explode('.', $_index); + $_var_section = $_var_parts[0]; + $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index'; + $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]"; + } + } else if (substr($_index, 0, 1) == '.') { + if (substr($_index, 1, 1) == '$') + $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]"; + else + $_output .= "['" . substr($_index, 1) . "']"; + } else if (substr($_index,0,2) == '->') { + if(substr($_index,2,2) == '__') { + $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } elseif($this->security && substr($_index, 2, 1) == '_') { + $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } elseif (substr($_index, 2, 1) == '$') { + if ($this->security) { + $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } else { + $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}'; + } + } else { + $_output .= $_index; + } + } elseif (substr($_index, 0, 1) == '(') { + $_index = $this->_parse_parenth_args($_index); + $_output .= $_index; + } else { + $_output .= $_index; + } + } + } + + return $_output; + } + + /** + * parse arguments in function call parenthesis + * + * @param string $parenth_args + * @return string + */ + function _parse_parenth_args($parenth_args) + { + preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match); + $orig_vals = $match = $match[0]; + $this->_parse_vars_props($match); + $replace = array(); + for ($i = 0, $count = count($match); $i < $count; $i++) { + $replace[$orig_vals[$i]] = $match[$i]; + } + return strtr($parenth_args, $replace); + } + + /** + * parse configuration variable expression into PHP code + * + * @param string $conf_var_expr + */ + function _parse_conf_var($conf_var_expr) + { + $parts = explode('|', $conf_var_expr, 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; + + $var_name = substr($var_ref, 1, -1); + + $output = "\$this->_config[0]['vars']['$var_name']"; + + $this->_parse_modifiers($output, $modifiers); + + return $output; + } + + /** + * parse section property expression into PHP code + * + * @param string $section_prop_expr + * @return string + */ + function _parse_section_prop($section_prop_expr) + { + $parts = explode('|', $section_prop_expr, 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; + + preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); + $section_name = $match[1]; + $prop_name = $match[2]; + + $output = "\$this->_sections['$section_name']['$prop_name']"; + + $this->_parse_modifiers($output, $modifiers); + + return $output; + } + + + /** + * parse modifier chain into PHP code + * + * sets $output to parsed modified chain + * @param string $output + * @param string $modifier_string + */ + function _parse_modifiers(&$output, $modifier_string) + { + preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match); + list(, $_modifiers, $modifier_arg_strings) = $_match; + + for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) { + $_modifier_name = $_modifiers[$_i]; + + if($_modifier_name == 'smarty') { + // skip smarty modifier + continue; + } + + preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match); + $_modifier_args = $_match[1]; + + if (substr($_modifier_name, 0, 1) == '@') { + $_map_array = false; + $_modifier_name = substr($_modifier_name, 1); + } else { + $_map_array = true; + } + + if (empty($this->_plugins['modifier'][$_modifier_name]) + && !$this->_get_plugin_filepath('modifier', $_modifier_name) + && function_exists($_modifier_name)) { + if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { + $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } else { + $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false); + } + } + $this->_add_plugin('modifier', $_modifier_name); + + $this->_parse_vars_props($_modifier_args); + + if($_modifier_name == 'default') { + // supress notifications of default modifier vars and args + if(substr($output, 0, 1) == '$') { + $output = '@' . $output; + } + if(isset($_modifier_args[0]) && substr($_modifier_args[0], 0, 1) == '$') { + $_modifier_args[0] = '@' . $_modifier_args[0]; + } + } + if (count($_modifier_args) > 0) + $_modifier_args = ', '.implode(', ', $_modifier_args); + else + $_modifier_args = ''; + + if ($_map_array) { + $output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))"; + + } else { + + $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)"; + + } + } + } + + + /** + * add plugin + * + * @param string $type + * @param string $name + * @param boolean? $delayed_loading + */ + function _add_plugin($type, $name, $delayed_loading = null) + { + if (!isset($this->_plugin_info[$type])) { + $this->_plugin_info[$type] = array(); + } + if (!isset($this->_plugin_info[$type][$name])) { + $this->_plugin_info[$type][$name] = array($this->_current_file, + $this->_current_line_no, + $delayed_loading); + } + } + + + /** + * Compiles references of type $smarty.foo + * + * @param string $indexes + * @return string + */ + function _compile_smarty_ref(&$indexes) + { + /* Extract the reference name. */ + $_ref = substr($indexes[0], 1); + foreach($indexes as $_index_no=>$_index) { + if (substr($_index, 0, 1) != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) { + $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); + } + } + + switch ($_ref) { + case 'now': + $compiled_ref = 'time()'; + $_max_index = 1; + break; + + case 'foreach': + array_shift($indexes); + $_var = $this->_parse_var_props(substr($indexes[0], 1)); + $_propname = substr($indexes[1], 1); + $_max_index = 1; + switch ($_propname) { + case 'index': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)"; + break; + + case 'first': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)"; + break; + + case 'last': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])"; + break; + + case 'show': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)"; + break; + + default: + unset($_max_index); + $compiled_ref = "\$this->_foreach[$_var]"; + } + break; + + case 'section': + array_shift($indexes); + $_var = $this->_parse_var_props(substr($indexes[0], 1)); + $compiled_ref = "\$this->_sections[$_var]"; + break; + + case 'get': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_GET"; + break; + + case 'post': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_POST"; + break; + + case 'cookies': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_COOKIE"; + break; + + case 'env': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_ENV"; + break; + + case 'server': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_SERVER"; + break; + + case 'session': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_SESSION"; + break; + + /* + * These cases are handled either at run-time or elsewhere in the + * compiler. + */ + case 'request': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + if ($this->request_use_auto_globals) { + $compiled_ref = "\$_REQUEST"; + break; + } else { + $this->_init_smarty_vars = true; + } + return null; + + case 'capture': + return null; + + case 'template': + $compiled_ref = "'$this->_current_file'"; + $_max_index = 1; + break; + + case 'version': + $compiled_ref = "'$this->_version'"; + $_max_index = 1; + break; + + case 'const': + if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) { + $this->_syntax_error("(secure mode) constants not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + array_shift($indexes); + if (preg_match('!^\.\w+$!', $indexes[0])) { + $compiled_ref = '@' . substr($indexes[0], 1); + } else { + $_val = $this->_parse_var_props(substr($indexes[0], 1)); + $compiled_ref = '@constant(' . $_val . ')'; + } + $_max_index = 1; + break; + + case 'config': + $compiled_ref = "\$this->_config[0]['vars']"; + $_max_index = 3; + break; + + case 'ldelim': + $compiled_ref = "'$this->left_delimiter'"; + break; + + case 'rdelim': + $compiled_ref = "'$this->right_delimiter'"; + break; + + default: + $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__); + break; + } + + if (isset($_max_index) && count($indexes) > $_max_index) { + $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); + } + + array_shift($indexes); + return $compiled_ref; + } + + /** + * compiles call to plugin of type $type with name $name + * returns a string containing the function-name or method call + * without the paramter-list that would have follow to make the + * call valid php-syntax + * + * @param string $type + * @param string $name + * @return string + */ + function _compile_plugin_call($type, $name) { + if (isset($this->_plugins[$type][$name])) { + /* plugin loaded */ + if (is_array($this->_plugins[$type][$name][0])) { + return ((is_object($this->_plugins[$type][$name][0][0])) ? + "\$this->_plugins['$type']['$name'][0][0]->" /* method callback */ + : (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */ + ). $this->_plugins[$type][$name][0][1]; + + } else { + /* function callback */ + return $this->_plugins[$type][$name][0]; + + } + } else { + /* plugin not loaded -> auto-loadable-plugin */ + return 'smarty_'.$type.'_'.$name; + + } + } + + /** + * load pre- and post-filters + */ + function _load_filters() + { + if (count($this->_plugins['prefilter']) > 0) { + foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { + if ($prefilter === false) { + unset($this->_plugins['prefilter'][$filter_name]); + $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + } + } + } + if (count($this->_plugins['postfilter']) > 0) { + foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { + if ($postfilter === false) { + unset($this->_plugins['postfilter'][$filter_name]); + $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + } + } + } + } + + + /** + * Quote subpattern references + * + * @param string $string + * @return string + */ + function _quote_replace($string) + { + return strtr($string, array('\\' => '\\\\', '$' => '\\$')); + } + + /** + * display Smarty syntax error + * + * @param string $error_msg + * @param integer $error_type + * @param string $file + * @param integer $line + */ + function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null) + { + $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type); + } + + + /** + * check if the compilation changes from cacheable to + * non-cacheable state with the beginning of the current + * plugin. return php-code to reflect the transition. + * @return string + */ + function _push_cacheable_state($type, $name) { + $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; + if ($_cacheable + || 0<$this->_cacheable_state++) return ''; + if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty')); + $_ret = 'if ($this->caching && !$this->_cache_including): echo \'{nocache:' + . $this->_cache_serial . '#' . $this->_nocache_count + . '}\'; endif;'; + return $_ret; + } + + + /** + * check if the compilation changes from non-cacheable to + * cacheable state with the end of the current plugin return + * php-code to reflect the transition. + * @return string + */ + function _pop_cacheable_state($type, $name) { + $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; + if ($_cacheable + || --$this->_cacheable_state>0) return ''; + return 'if ($this->caching && !$this->_cache_including): echo \'{/nocache:' + . $this->_cache_serial . '#' . ($this->_nocache_count++) + . '}\'; endif;'; + } + + + /** + * push opening tag-name, file-name and line-number on the tag-stack + * @param string the opening tag's name + */ + function _push_tag($open_tag) + { + array_push($this->_tag_stack, array($open_tag, $this->_current_line_no)); + } + + /** + * pop closing tag-name + * raise an error if this stack-top doesn't match with the closing tag + * @param string the closing tag's name + * @return string the opening tag's name + */ + function _pop_tag($close_tag) + { + $message = ''; + if (count($this->_tag_stack)>0) { + list($_open_tag, $_line_no) = array_pop($this->_tag_stack); + if ($close_tag == $_open_tag) { + return $_open_tag; + } + if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) { + return $this->_pop_tag($close_tag); + } + if ($close_tag == 'section' && $_open_tag == 'sectionelse') { + $this->_pop_tag($close_tag); + return $_open_tag; + } + if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') { + $this->_pop_tag($close_tag); + return $_open_tag; + } + if ($_open_tag == 'else' || $_open_tag == 'elseif') { + $_open_tag = 'if'; + } elseif ($_open_tag == 'sectionelse') { + $_open_tag = 'section'; + } elseif ($_open_tag == 'foreachelse') { + $_open_tag = 'foreach'; + } + $message = " expected {/$_open_tag} (opened line $_line_no)."; + } + $this->_syntax_error("mismatched tag {/$close_tag}.$message", + E_USER_ERROR, __FILE__, __LINE__); + } + +} + +/** + * compare to values by their string length + * + * @access private + * @param string $a + * @param string $b + * @return 0|-1|1 + */ +function _smarty_sort_length($a, $b) +{ + if($a == $b) + return 0; + + if(strlen($a) == strlen($b)) + return ($a > $b) ? -1 : 1; + + return (strlen($a) > strlen($b)) ? -1 : 1; +} + + +/* vim: set et: */ + +?> diff --git a/includes/Smarty/libs/debug.tpl b/includes/Smarty/libs/debug.tpl new file mode 100644 index 0000000..c05ef5d --- /dev/null +++ b/includes/Smarty/libs/debug.tpl @@ -0,0 +1,157 @@ +{* Smarty *} +{* debug.tpl, last updated version 2.1.0 *} +{assign_debug_info} +{capture assign=debug_output} + + + + Smarty Debug Console +{literal} + +{/literal} + + + +

Smarty Debug Console

+ +

included templates & config files (load time in seconds)

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

no templates included

+{/section} +
+ +

assigned template variables

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

no template variables assigned

+ +

assigned config file variables (outer template scope)

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

no config vars assigned

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