Compare commits
1 commit
main
...
fix/pwd_co
Author | SHA1 | Date | |
---|---|---|---|
4808df102a |
1
.gitattributes
vendored
|
@ -1 +0,0 @@
|
||||||
src/includes/config.php merge=ours
|
|
2
.gitignore
vendored
|
@ -1,3 +1,3 @@
|
||||||
src/templates_c
|
src/templates_c
|
||||||
src/item_images
|
src/item_images
|
||||||
**/.*.swp
|
|
||||||
|
|
39
README.md
|
@ -1,38 +1 @@
|
||||||
# PHP Gift Wishlist
|
The README.md for the application is in [src](src/README.md).
|
||||||
|
|
||||||
The PHP Gift Wishlist is a web-enabled gift registry intended for use among
|
|
||||||
a circle of family members or friends.
|
|
||||||
|
|
||||||
This project is based on [phpgiftreg](https://github.com/generalpf/phpgiftreg).
|
|
||||||
I have forked Ryan's repository and made many changes. Thank you, Ryan, for all
|
|
||||||
of your hard work!
|
|
||||||
|
|
||||||
It is intended to fill the following purposes:
|
|
||||||
|
|
||||||
* Permit the long-term storage of a list of items one desires, along with its price, where it can be bought, and (optionally) a URL where it can be
|
|
||||||
viewed.
|
|
||||||
* Enabled items to be "locked" by one shopper so that the same item is not bought by someone else.
|
|
||||||
|
|
||||||
Its features include:
|
|
||||||
|
|
||||||
* A single unifying view of items on your own list and people whose lists you can view.
|
|
||||||
* A now-optional request/permit system by which you can control who can see your list.
|
|
||||||
* A "checkin/checkout" system which allows you to reserve items on someone's list.
|
|
||||||
* An in-system messaging system by which users can be informed of item deletions or custom announcements.
|
|
||||||
* New users can request accounts. Optionally, administrators will be informed about the request, and they can then approve or reject the request. Either way, the user will be informed by e-mail.
|
|
||||||
* A site-customizable ranking system for items.
|
|
||||||
* An events system for users to add significant (read: gift-bearing) events which will show up on others' displays when the event nears.
|
|
||||||
|
|
||||||
## Installing
|
|
||||||
|
|
||||||
Read [INSTALL](src/INSTALL) for installation instructions.
|
|
||||||
|
|
||||||
If you have any questions, comments, feature requests, or patches, feel free to e-mail me.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
phpgiftreg is licensed by the GPL. For more information on the GPL, visit http://www.gnu.org
|
|
||||||
|
|
||||||
Copyright 2024 Michael Erdely <mike@erdelynet.com>
|
|
||||||
|
|
||||||
Copyright 2022 Ryan Walberg <generalpf@gmail.com> [@GeneralPeeEff](https://twitter.com/GeneralPeeEff)
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ $opt = $smarty->opt();
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
if (!isset($_SESSION["userid"])) {
|
if (!isset($_SESSION["userid"])) {
|
||||||
header("Location: " . getFullPath("login.php") . "?from=admin.php");
|
header("Location: " . getFullPath("login.php"));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
else if ($_SESSION["admin"] != 1) {
|
else if ($_SESSION["admin"] != 1) {
|
||||||
|
@ -31,78 +31,52 @@ else {
|
||||||
$userid = $_SESSION["userid"];
|
$userid = $_SESSION["userid"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_GET["familyid"])) {
|
|
||||||
$familyid = filter_var(trim($_GET["familyid"]), FILTER_SANITIZE_NUMBER_INT);
|
|
||||||
|
|
||||||
if (filter_var($familyid, FILTER_SANITIZE_NUMBER_INT) === false || $familyid == "" || !is_numeric($familyid) || $familyid < 0) {
|
|
||||||
die("Invalid familyid ({$_GET["familyid"]})");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_GET["userid"])) {
|
|
||||||
$userid = filter_var(trim($_GET["userid"]), FILTER_SANITIZE_NUMBER_INT);
|
|
||||||
|
|
||||||
if (filter_var($userid, FILTER_SANITIZE_NUMBER_INT) === false || $userid == "" || !is_numeric($userid) || $userid < 0) {
|
|
||||||
die("Invalid userid ({$_GET["userid"]})");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$action = $_GET["action"];
|
$action = $_GET["action"];
|
||||||
if ($action == "approve") {
|
if ($action == "approve") {
|
||||||
$pwd = generatePassword($opt);
|
$pwd = generatePassword($opt);
|
||||||
if ($familyid != "") {
|
if ($_GET["familyid"] != "") {
|
||||||
$stmt = $smarty->dbh()->prepare("INSERT INTO {$opt["table_prefix"]}memberships(userid,familyid) VALUES(?, ?)");
|
$stmt = $smarty->dbh()->prepare("INSERT INTO {$opt["table_prefix"]}memberships(userid,familyid) VALUES(?, ?)");
|
||||||
$stmt->bindValue(1, (int) $userid, PDO::PARAM_INT);
|
$stmt->bindValue(1, (int) $_GET["userid"], PDO::PARAM_INT);
|
||||||
$stmt->bindValue(2, (int) $familyid, PDO::PARAM_INT);
|
$stmt->bindValue(2, (int) $_GET["familyid"], PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
}
|
}
|
||||||
$stmt = $smarty->dbh()->prepare("UPDATE {$opt["table_prefix"]}users SET approved = 1, password = {$opt["password_hasher"]}(?) WHERE userid = ?");
|
$stmt = $smarty->dbh()->prepare("UPDATE {$opt["table_prefix"]}users SET approved = 1, password = {$opt["password_hasher"]}(?) WHERE userid = ?");
|
||||||
$stmt->bindParam(1, $pwd, PDO::PARAM_STR);
|
$stmt->bindParam(1, $pwd, PDO::PARAM_INT);
|
||||||
$stmt->bindValue(2, (int) $userid, PDO::PARAM_INT);
|
$stmt->bindValue(2, (int) $_GET["userid"], PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
// send the e-mails
|
// send the e-mails
|
||||||
$stmt = $smarty->dbh()->prepare("SELECT username, email FROM {$opt["table_prefix"]}users WHERE userid = ?");
|
$stmt = $smarty->dbh()->prepare("SELECT username, email FROM {$opt["table_prefix"]}users WHERE userid = ?");
|
||||||
$stmt->bindValue(1, (int) $userid, PDO::PARAM_INT);
|
$stmt->bindValue(1, (int) $_GET["userid"], PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
if ($row = $stmt->fetch()) {
|
if ($row = $stmt->fetch()) {
|
||||||
mail(
|
mail(
|
||||||
$row["email"],
|
$row["email"],
|
||||||
"Gift Registry application approved",
|
"Gift Registry application approved",
|
||||||
"Your Gift Registry application was approved.\r\n" .
|
"Your Gift Registry application was approved by " . $_SESSION["fullname"] . ".\r\n" .
|
||||||
"Your username is {$row["username"]} and your password is '$pwd'.\r\n" .
|
"Your username is " . $row["username"] . " and your password is '$pwd'.",
|
||||||
"Log in to {$_SERVER['REQUEST_SCHEME']}://{$_SERVER['HTTP_HOST']}/ and change your password under " .
|
|
||||||
"'Update Profile' as soon as possible:\r\n" .
|
|
||||||
" {$_SERVER['REQUEST_SCHEME']}://{$_SERVER['HTTP_HOST']}/profile.php\r\n" .
|
|
||||||
"\r\n" .
|
|
||||||
"There is help and a browser bookmarklet at {$_SERVER['REQUEST_SCHEME']}://{$_SERVER['HTTP_HOST']}/help.php\r\n" .
|
|
||||||
"\r\n" .
|
|
||||||
"Once you've logged in, you can see the people you can shop for under 'Available People To Shopping For'. " .
|
|
||||||
"Click on the icon next to each person you want to shop for to see their lists.\r\n" .
|
|
||||||
"\r\n" .
|
|
||||||
"If you have any questions or problems, email {$opt['email_from']}.\r\n",
|
|
||||||
"From: {$opt["email_from"]}\r\nReply-To: {$opt["email_reply_to"]}\r\nX-Mailer: {$opt["email_xmailer"]}\r\n"
|
"From: {$opt["email_from"]}\r\nReply-To: {$opt["email_reply_to"]}\r\nX-Mailer: {$opt["email_xmailer"]}\r\n"
|
||||||
) or die("Mail not accepted for " . $row["email"]);
|
) or die("Mail not accepted for " . $row["email"]);
|
||||||
}
|
}
|
||||||
header("Location: " . getFullPath("families.php"));
|
header("Location: " . getFullPath("index.php"));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
else if ($action == "reject") {
|
else if ($action == "reject") {
|
||||||
// send the e-mails
|
// send the e-mails
|
||||||
$stmt = $smarty->dbh()->prepare("SELECT email FROM {$opt["table_prefix"]}users WHERE userid = ?");
|
$stmt = $smarty->dbh()->prepare("SELECT email FROM {$opt["table_prefix"]}users WHERE userid = ?");
|
||||||
$stmt->bindValue(1, (int) $userid, PDO::PARAM_INT);
|
$stmt->bindValue(1, (int) $_GET["userid"], PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
if ($row = $stmt->fetch()) {
|
if ($row = $stmt->fetch()) {
|
||||||
mail(
|
mail(
|
||||||
$row["email"],
|
$row["email"],
|
||||||
"Gift Registry application denied",
|
"Gift Registry application denied",
|
||||||
"Your Gift Registry application was denied.",
|
"Your Gift Registry application was denied by " . $_SESSION["fullname"] . ".",
|
||||||
"From: {$opt["email_from"]}\r\nReply-To: {$opt["email_reply_to"]}\r\nX-Mailer: {$opt["email_xmailer"]}\r\n"
|
"From: {$opt["email_from"]}\r\nReply-To: {$opt["email_reply_to"]}\r\nX-Mailer: {$opt["email_xmailer"]}\r\n"
|
||||||
) or die("Mail not accepted for " . $row["email"]);
|
) or die("Mail not accepted for " . $row["email"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $smarty->dbh()->prepare("DELETE FROM {$opt["table_prefix"]}users WHERE userid = ?");
|
$stmt = $smarty->dbh()->prepare("DELETE FROM {$opt["table_prefix"]}users WHERE userid = ?");
|
||||||
$stmt->bindValue(1, (int) $userid, PDO::PARAM_INT);
|
$stmt->bindValue(1, (int) $_GET["userid"], PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
header("Location: " . getFullPath("index.php"));
|
header("Location: " . getFullPath("index.php"));
|
||||||
|
|
1088
src/bootstrap/css/bootstrap-responsive.css
vendored
Normal file
9
src/bootstrap/css/bootstrap-responsive.min.css
vendored
Normal file
6858
src/bootstrap/css/bootstrap.css
vendored
Normal file
9
src/bootstrap/css/bootstrap.min.css
vendored
Normal file
605
src/bootstrap/css/bootswatch.less
Normal file
|
@ -0,0 +1,605 @@
|
||||||
|
// Flatness by Jenil (www.jgog.in)
|
||||||
|
// Bootswatch 2.3.2
|
||||||
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
// TYPOGRAPHY
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
@import url("http://fonts.googleapis.com/css?family=Lato:400,700,900,400italic");
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 48px;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SCAFFOLDING
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NAVBAR
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
|
||||||
|
.brand {
|
||||||
|
|
||||||
|
text-shadow: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @linkColorHover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-inner {
|
||||||
|
.box-shadow(none);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav > li > a {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav > .active > a,
|
||||||
|
.nav > .active > a:hover,
|
||||||
|
.nav > .active > a:focus {
|
||||||
|
.box-shadow(none);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-search .search-query {
|
||||||
|
border: none;
|
||||||
|
.box-shadow(none);
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-navbar {
|
||||||
|
background-image: none;
|
||||||
|
.box-shadow(none);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn, .btn-group {
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-inverse {
|
||||||
|
|
||||||
|
.brand:hover {
|
||||||
|
color: @blueDark;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-search .search-query {
|
||||||
|
border-color: transparent;
|
||||||
|
.box-shadow(none);
|
||||||
|
line-height: normal;
|
||||||
|
color: @textColor;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
padding: 4px 14px;
|
||||||
|
color: @textColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.subnav {
|
||||||
|
|
||||||
|
border-color: transparent;
|
||||||
|
background-image: none;
|
||||||
|
background-color: @grayLighter;
|
||||||
|
.box-shadow(none);
|
||||||
|
|
||||||
|
&-fixed {
|
||||||
|
top: @navbarHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav > li > a {
|
||||||
|
border-color: transparent;
|
||||||
|
.box-shadow(none);
|
||||||
|
color: @textColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav > .active > a,
|
||||||
|
.nav > .active > a:hover {
|
||||||
|
border-color: transparent;
|
||||||
|
background-color: darken(@grayLighter, 10%);
|
||||||
|
.box-shadow(none);
|
||||||
|
color: @textColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NAVIGATION
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
.nav-list {
|
||||||
|
|
||||||
|
& > li > a,
|
||||||
|
& > .active > a,
|
||||||
|
.nav-header {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
background: none;
|
||||||
|
border-bottom: 2px solid @dropdownDividerBottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-pills {
|
||||||
|
|
||||||
|
.open .dropdown-toggle {
|
||||||
|
background-color: @blueDark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
|
||||||
|
ul {
|
||||||
|
|
||||||
|
.box-shadow(none);
|
||||||
|
|
||||||
|
& > li > a {
|
||||||
|
background-color: @green;
|
||||||
|
border-color: transparent;
|
||||||
|
color: @white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten(@green, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .active > a,
|
||||||
|
& > .active > a:hover {
|
||||||
|
background-color: @paginationActiveBackground;
|
||||||
|
color: @textColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .disabled > a,
|
||||||
|
& > .disabled > a:hover {
|
||||||
|
background-color: lighten(@green, 10%);
|
||||||
|
color: @white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pager {
|
||||||
|
|
||||||
|
li > a,
|
||||||
|
li > span {
|
||||||
|
background-color: @green;
|
||||||
|
border: none;
|
||||||
|
color: @white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten(@green, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled > a,
|
||||||
|
.disabled > span,
|
||||||
|
.disabled > a:hover,
|
||||||
|
.disabled > span:hover {
|
||||||
|
background-color: lighten(@green, 10%);
|
||||||
|
color: @white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
|
||||||
|
& > li {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BUTTONS
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 9px 20px;
|
||||||
|
border: none;
|
||||||
|
background-image: none;
|
||||||
|
color: @white;
|
||||||
|
text-decoration: none;
|
||||||
|
text-shadow: none;
|
||||||
|
.box-shadow(none);
|
||||||
|
-webkit-transition: 0.25s;
|
||||||
|
-moz-transition: 0.25s;
|
||||||
|
transition: 0.25s;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
color: white;
|
||||||
|
-webkit-transition: 0.25s;
|
||||||
|
-moz-transition: 0.25s;
|
||||||
|
transition: 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active,
|
||||||
|
&.active {
|
||||||
|
.box-shadow(none);
|
||||||
|
color: rgba(255, 255, 255, 0.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled,
|
||||||
|
&[disabled] {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-large {
|
||||||
|
padding: @paddingLarge;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-small {
|
||||||
|
padding: @paddingSmall;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-mini {
|
||||||
|
padding: @paddingMini;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TABLES
|
||||||
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
.table tbody tr {
|
||||||
|
&.success > td,
|
||||||
|
&.error > td,
|
||||||
|
&.warning > td,
|
||||||
|
&.info > td {
|
||||||
|
color: @white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FORMS
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
textarea,
|
||||||
|
input[type="text"],
|
||||||
|
input[type="password"],
|
||||||
|
input[type="datetime"],
|
||||||
|
input[type="datetime-local"],
|
||||||
|
input[type="date"],
|
||||||
|
input[type="month"],
|
||||||
|
input[type="time"],
|
||||||
|
input[type="week"],
|
||||||
|
input[type="number"],
|
||||||
|
input[type="email"],
|
||||||
|
input[type="url"],
|
||||||
|
input[type="search"],
|
||||||
|
input[type="tel"],
|
||||||
|
input[type="color"],
|
||||||
|
.uneditable-input {
|
||||||
|
padding: 7px 6px;
|
||||||
|
border: 2px solid #dce4ec;
|
||||||
|
text-indent: 1px;
|
||||||
|
.border-radius(@inputBorderRadius);
|
||||||
|
.box-shadow(none);
|
||||||
|
.placeholder(#acb6c0);
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: #1abc9c;
|
||||||
|
.box-shadow(none);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-prepend {
|
||||||
|
|
||||||
|
.add-on:first-child,
|
||||||
|
.btn:first-child {
|
||||||
|
.border-radius(@inputBorderRadius 0 0 @inputBorderRadius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-append {
|
||||||
|
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
.uneditable-input {
|
||||||
|
|
||||||
|
.border-radius(@inputBorderRadius 0 0 @inputBorderRadius);
|
||||||
|
|
||||||
|
+ .btn-group .btn:last-child {
|
||||||
|
.border-radius(0 @inputBorderRadius @inputBorderRadius 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-on:last-child,
|
||||||
|
.btn:last-child,
|
||||||
|
.btn-group:last-child > .dropdown-toggle {
|
||||||
|
.border-radius(0 @inputBorderRadius @inputBorderRadius 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-prepend,
|
||||||
|
.input-append {
|
||||||
|
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
.uneditable-input {
|
||||||
|
.border-radius(0);
|
||||||
|
+ .btn-group .btn {
|
||||||
|
.border-radius(0 @inputBorderRadius @inputBorderRadius 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-on:first-child,
|
||||||
|
.btn:first-child {
|
||||||
|
.border-radius(@inputBorderRadius 0 0 @inputBorderRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-on:last-child,
|
||||||
|
.btn:last-child {
|
||||||
|
.border-radius(0 @inputBorderRadius @inputBorderRadius 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-append,
|
||||||
|
.input-prepend {
|
||||||
|
|
||||||
|
.add-on {
|
||||||
|
padding: 9px 5px;
|
||||||
|
text-shadow: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group.error,
|
||||||
|
.control-group.error input:focus,
|
||||||
|
.control-group.error textarea:focus {
|
||||||
|
border-color: #e74c3c;
|
||||||
|
.box-shadow(none);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group.success,
|
||||||
|
.control-group.success input:focus,
|
||||||
|
.control-group.success textarea:focus {
|
||||||
|
border-color: #2ecc71;
|
||||||
|
.box-shadow(none);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group.warning,
|
||||||
|
.control-group.warning input:focus,
|
||||||
|
.control-group.warning textarea:focus {
|
||||||
|
border-color: #f1c40f;
|
||||||
|
.box-shadow(none);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group.info,
|
||||||
|
.control-group.info input:focus,
|
||||||
|
.control-group.info textarea:focus {
|
||||||
|
border-color: #3498db;
|
||||||
|
.box-shadow(none);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[disabled],
|
||||||
|
input[readonly],
|
||||||
|
textarea[disabled],
|
||||||
|
textarea[readonly] {
|
||||||
|
background-color: #eaeded;
|
||||||
|
border-color: transparent;
|
||||||
|
color: #cad2d3;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="file"]{
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
legend {
|
||||||
|
border-bottom: none;
|
||||||
|
color: @textColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
border-top: none;
|
||||||
|
.border-radius(@baseBorderRadius);
|
||||||
|
background-color: darken(@grayLighter, 5%);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DROPDOWNS
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
// ALERTS, LABELS, BADGES
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
background-color: @orange;
|
||||||
|
color: @white;
|
||||||
|
text-shadow: none;
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
color: @white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-error {
|
||||||
|
background-color: @red;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-success {
|
||||||
|
background-color: @green;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-info {
|
||||||
|
background-color: @blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
padding: 6px 10px;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
padding: 6px 10px;
|
||||||
|
.border-radius(@borderRadiusLarge);
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MISC
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
.well {
|
||||||
|
border: none;
|
||||||
|
.box-shadow(none);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
|
||||||
|
background: @grayLighter;
|
||||||
|
border-radius: 32px;
|
||||||
|
height: 12px;
|
||||||
|
.box-shadow(none);
|
||||||
|
|
||||||
|
.bar {
|
||||||
|
background-color: @blueDark;
|
||||||
|
background-image: none;
|
||||||
|
.box-shadow(none);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar + .bar {
|
||||||
|
.box-shadow(none);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-striped .bar {
|
||||||
|
#gradient > .striped(@blueDark);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-success .bar,
|
||||||
|
&-success.progress-striped .bar,
|
||||||
|
.bar-success {
|
||||||
|
background-color: @green;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-warning .bar,
|
||||||
|
&-warning.progress-striped .bar,
|
||||||
|
.bar-warning {
|
||||||
|
background-color: @yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-danger .bar,
|
||||||
|
&-danger.progress-striped .bar,
|
||||||
|
.bar-danger {
|
||||||
|
background-color: @red;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-info .bar,
|
||||||
|
&-info.progress-striped .bar,
|
||||||
|
.bar-info {
|
||||||
|
background-color: @blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip {
|
||||||
|
|
||||||
|
&.in {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover {
|
||||||
|
color: @white;
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
border-bottom: 2px solid @dropdownDividerBottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
|
||||||
|
&-header {
|
||||||
|
background-color: @navbarBackground;
|
||||||
|
border-bottom: none;
|
||||||
|
color: @white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-footer {
|
||||||
|
background-color: @grayLighter;
|
||||||
|
border-top: none;
|
||||||
|
.box-shadow(none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MEDIA QUERIES
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
|
||||||
|
div.subnav {
|
||||||
|
|
||||||
|
.nav > li:first-child > a,
|
||||||
|
.nav > li + li > a {
|
||||||
|
border-color: transparent;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: darken(@grayLighter, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav > li:last-child > a {
|
||||||
|
border-radius: 0 0 4px 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-append,
|
||||||
|
.input-prepend {
|
||||||
|
|
||||||
|
.add-on,.btn {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 979px) {
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
|
||||||
|
.nav-collapse .nav > li > a {
|
||||||
|
color: @white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: @green;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
300
src/bootstrap/css/variables.less
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
// Flatness by Jenil (www.jgog.in)
|
||||||
|
// Bootswatch 2.3.2
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
// Global values
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
// Grays
|
||||||
|
// -------------------------
|
||||||
|
@black: #000;
|
||||||
|
@grayDarker: #222;
|
||||||
|
@grayDark: #7b8a8b;
|
||||||
|
@gray: #95A5A6;
|
||||||
|
@grayLight: #b4bcc2;
|
||||||
|
@grayLighter: #ECF0F1;
|
||||||
|
@white: #fff;
|
||||||
|
|
||||||
|
|
||||||
|
// Accent colors
|
||||||
|
// -------------------------
|
||||||
|
@blue: #3498DB;
|
||||||
|
@blueDark: #2C3E50;
|
||||||
|
@green: #18BC9C;
|
||||||
|
@red: #E74C3C;
|
||||||
|
@yellow: #e6bb0d;
|
||||||
|
@orange: #F39C12;
|
||||||
|
@pink: #ff6699;
|
||||||
|
@purple: #8E44AD;
|
||||||
|
|
||||||
|
|
||||||
|
// Scaffolding
|
||||||
|
// -------------------------
|
||||||
|
@bodyBackground: @white;
|
||||||
|
@textColor: @blueDark;
|
||||||
|
|
||||||
|
|
||||||
|
// Links
|
||||||
|
// -------------------------
|
||||||
|
@linkColor: #1ABC9C;
|
||||||
|
@linkColorHover: lighten(@linkColor, 5%);
|
||||||
|
|
||||||
|
|
||||||
|
// Typography
|
||||||
|
// -------------------------
|
||||||
|
@sansFontFamily: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
@serifFontFamily: Georgia, "Times New Roman", Times, serif;
|
||||||
|
@monoFontFamily: Monaco, Menlo, Consolas, "Courier New", monospace;
|
||||||
|
|
||||||
|
@baseFontSize: 15px;
|
||||||
|
@baseFontFamily: @sansFontFamily;
|
||||||
|
@baseLineHeight: 20px;
|
||||||
|
@altFontFamily: @serifFontFamily;
|
||||||
|
|
||||||
|
@headingsFontFamily: inherit; // empty to use BS default, @baseFontFamily
|
||||||
|
@headingsFontWeight: bold; // instead of browser default, bold
|
||||||
|
@headingsColor: inherit; // empty to use BS default, @textColor
|
||||||
|
|
||||||
|
|
||||||
|
// Component sizing
|
||||||
|
// -------------------------
|
||||||
|
// Based on 14px font-size and 20px line-height
|
||||||
|
|
||||||
|
@fontSizeLarge: @baseFontSize * 1.25; // ~18px
|
||||||
|
@fontSizeSmall: @baseFontSize * 0.85; // ~12px
|
||||||
|
@fontSizeMini: @baseFontSize * 0.75; // ~11px
|
||||||
|
|
||||||
|
@paddingLarge: 18px 36px; // 44px
|
||||||
|
@paddingSmall: 2px 12px; // 26px
|
||||||
|
@paddingMini: 1px 8px; // 24px
|
||||||
|
|
||||||
|
@baseBorderRadius: 6px;
|
||||||
|
@borderRadiusLarge: 10px;
|
||||||
|
@borderRadiusSmall: 3px;
|
||||||
|
|
||||||
|
|
||||||
|
// Tables
|
||||||
|
// -------------------------
|
||||||
|
@tableBackground: transparent; // overall background-color
|
||||||
|
@tableBackgroundAccent: #f9f9f9; // for striping
|
||||||
|
@tableBackgroundHover: #f5f5f5; // for hover
|
||||||
|
@tableBorder: #ddd; // table and cell border
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
// -------------------------
|
||||||
|
@btnBackground: @grayLight;
|
||||||
|
@btnBackgroundHighlight: lighten(@btnBackground, 10%);
|
||||||
|
@btnBorder: #ddd;
|
||||||
|
|
||||||
|
@btnPrimaryBackground: @textColor;
|
||||||
|
@btnPrimaryBackgroundHighlight: lighten(@btnPrimaryBackground, 10%);
|
||||||
|
|
||||||
|
@btnInfoBackground: @blue;
|
||||||
|
@btnInfoBackgroundHighlight: lighten(@btnInfoBackground, 10%);
|
||||||
|
|
||||||
|
@btnSuccessBackground: @green;
|
||||||
|
@btnSuccessBackgroundHighlight: lighten(@btnSuccessBackground, 10%);
|
||||||
|
|
||||||
|
@btnWarningBackground: @orange;
|
||||||
|
@btnWarningBackgroundHighlight: lighten(@btnWarningBackground, 10%);
|
||||||
|
|
||||||
|
@btnDangerBackground: @red;
|
||||||
|
@btnDangerBackgroundHighlight: lighten(@btnDangerBackground, 10%);
|
||||||
|
|
||||||
|
@btnInverseBackground: @grayDarker;
|
||||||
|
@btnInverseBackgroundHighlight: lighten(@btnInverseBackground, 10%);
|
||||||
|
|
||||||
|
|
||||||
|
// Forms
|
||||||
|
// -------------------------
|
||||||
|
@inputBackground: @white;
|
||||||
|
@inputBorder: #dce4ec;
|
||||||
|
@inputBorderRadius: @baseBorderRadius;
|
||||||
|
@inputDisabledBackground: #eaeded;
|
||||||
|
@formActionsBackground: #f5f5f5;
|
||||||
|
@inputHeight: @baseLineHeight + 10px; // base line-height + 8px vertical padding + 2px top/bottom border
|
||||||
|
|
||||||
|
|
||||||
|
// Dropdowns
|
||||||
|
// -------------------------
|
||||||
|
@dropdownBackground: @blueDark;
|
||||||
|
@dropdownBorder: rgba(0,0,0,0);
|
||||||
|
@dropdownDividerTop: rgba(0,0,0,0.2);
|
||||||
|
@dropdownDividerBottom: rgba(0,0,0,0.2);
|
||||||
|
|
||||||
|
@dropdownLinkColor: @white;
|
||||||
|
@dropdownLinkColorHover: @white;
|
||||||
|
@dropdownLinkColorActive: @dropdownLinkColor;
|
||||||
|
|
||||||
|
@dropdownLinkBackgroundActive: @green;
|
||||||
|
@dropdownLinkBackgroundHover: @green;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// COMPONENT VARIABLES
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
// Z-index master list
|
||||||
|
// -------------------------
|
||||||
|
// Used for a bird's eye view of components dependent on the z-axis
|
||||||
|
// Try to avoid customizing these :)
|
||||||
|
@zindexDropdown: 1000;
|
||||||
|
@zindexPopover: 1010;
|
||||||
|
@zindexTooltip: 1030;
|
||||||
|
@zindexFixedNavbar: 1030;
|
||||||
|
@zindexModalBackdrop: 1040;
|
||||||
|
@zindexModal: 1050;
|
||||||
|
|
||||||
|
|
||||||
|
// Sprite icons path
|
||||||
|
// -------------------------
|
||||||
|
@iconSpritePath: "../img/glyphicons-halflings.png";
|
||||||
|
@iconWhiteSpritePath: "../img/glyphicons-halflings-white.png";
|
||||||
|
|
||||||
|
|
||||||
|
// Input placeholder text color
|
||||||
|
// -------------------------
|
||||||
|
@placeholderText: @grayLight;
|
||||||
|
|
||||||
|
|
||||||
|
// Hr border color
|
||||||
|
// -------------------------
|
||||||
|
@hrBorder: @grayLighter;
|
||||||
|
|
||||||
|
|
||||||
|
// Horizontal forms & lists
|
||||||
|
// -------------------------
|
||||||
|
@horizontalComponentOffset: 180px;
|
||||||
|
|
||||||
|
|
||||||
|
// Wells
|
||||||
|
// -------------------------
|
||||||
|
@wellBackground: @grayLighter;
|
||||||
|
|
||||||
|
|
||||||
|
// Navbar
|
||||||
|
// -------------------------
|
||||||
|
@navbarCollapseWidth: 979px;
|
||||||
|
@navbarCollapseDesktopWidth: @navbarCollapseWidth + 1;
|
||||||
|
|
||||||
|
@navbarHeight: 50px;
|
||||||
|
@navbarBackgroundHighlight: @textColor;
|
||||||
|
@navbarBackground: @textColor;
|
||||||
|
@navbarBorder: darken(@navbarBackground, 5%);
|
||||||
|
|
||||||
|
@navbarText: @white;
|
||||||
|
@navbarLinkColor: @white;
|
||||||
|
@navbarLinkColorHover: @linkColor;
|
||||||
|
@navbarLinkColorActive: @linkColor;
|
||||||
|
@navbarLinkBackgroundHover: transparent;
|
||||||
|
@navbarLinkBackgroundActive: darken(@navbarBackground, 5%);
|
||||||
|
|
||||||
|
@navbarBrandColor: @navbarLinkColor;
|
||||||
|
|
||||||
|
// Inverted navbar
|
||||||
|
@navbarInverseBackground: @green;
|
||||||
|
@navbarInverseBackgroundHighlight: @green;
|
||||||
|
@navbarInverseBorder: darken(@green, 5%);
|
||||||
|
|
||||||
|
@navbarInverseText: @white;
|
||||||
|
@navbarInverseLinkColor: @white;
|
||||||
|
@navbarInverseLinkColorHover: @blueDark;
|
||||||
|
@navbarInverseLinkColorActive: @blueDark;
|
||||||
|
@navbarInverseLinkBackgroundHover: transparent;
|
||||||
|
@navbarInverseLinkBackgroundActive: darken(@navbarInverseBackground, 5%);
|
||||||
|
|
||||||
|
@navbarInverseSearchBackground: @white;
|
||||||
|
@navbarInverseSearchBackgroundFocus: @white;
|
||||||
|
@navbarInverseSearchBorder: @grayLight;
|
||||||
|
@navbarInverseSearchPlaceholderColor: @gray;
|
||||||
|
|
||||||
|
@navbarInverseBrandColor: @navbarInverseLinkColor;
|
||||||
|
|
||||||
|
|
||||||
|
// Pagination
|
||||||
|
// -------------------------
|
||||||
|
@paginationBackground: #fff;
|
||||||
|
@paginationBorder: #ddd;
|
||||||
|
@paginationActiveBackground: @grayLighter;
|
||||||
|
|
||||||
|
|
||||||
|
// Hero unit
|
||||||
|
// -------------------------
|
||||||
|
@heroUnitBackground: @grayLighter;
|
||||||
|
@heroUnitHeadingColor: inherit;
|
||||||
|
@heroUnitLeadColor: inherit;
|
||||||
|
|
||||||
|
|
||||||
|
// Form states and alerts
|
||||||
|
// -------------------------
|
||||||
|
@warningText: @yellow;
|
||||||
|
@warningBackground: @yellow;
|
||||||
|
@warningBorder: transparent;
|
||||||
|
|
||||||
|
@errorText: @red;
|
||||||
|
@errorBackground: @red;
|
||||||
|
@errorBorder: transparent;
|
||||||
|
|
||||||
|
@successText: @green;
|
||||||
|
@successBackground: @green;
|
||||||
|
@successBorder: transparent;
|
||||||
|
|
||||||
|
@infoText: @blue;
|
||||||
|
@infoBackground: @blue;
|
||||||
|
@infoBorder: transparent;
|
||||||
|
|
||||||
|
|
||||||
|
// Tooltips and popovers
|
||||||
|
// -------------------------
|
||||||
|
@tooltipColor: #fff;
|
||||||
|
@tooltipBackground: @blueDark;
|
||||||
|
@tooltipArrowWidth: 5px;
|
||||||
|
@tooltipArrowColor: @tooltipBackground;
|
||||||
|
|
||||||
|
@popoverBackground: @blueDark;
|
||||||
|
@popoverArrowWidth: 10px;
|
||||||
|
@popoverArrowColor: @blueDark;
|
||||||
|
@popoverTitleBackground: @blueDark;
|
||||||
|
|
||||||
|
// Special enhancement for popovers
|
||||||
|
@popoverArrowOuterWidth: @popoverArrowWidth + 1;
|
||||||
|
@popoverArrowOuterColor: rgba(0,0,0,.25);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// GRID
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
// Default 940px grid
|
||||||
|
// -------------------------
|
||||||
|
@gridColumns: 12;
|
||||||
|
@gridColumnWidth: 60px;
|
||||||
|
@gridGutterWidth: 20px;
|
||||||
|
@gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1));
|
||||||
|
|
||||||
|
// 1200px min
|
||||||
|
@gridColumnWidth1200: 70px;
|
||||||
|
@gridGutterWidth1200: 30px;
|
||||||
|
@gridRowWidth1200: (@gridColumns * @gridColumnWidth1200) + (@gridGutterWidth1200 * (@gridColumns - 1));
|
||||||
|
|
||||||
|
// 768px-979px
|
||||||
|
@gridColumnWidth768: 42px;
|
||||||
|
@gridGutterWidth768: 20px;
|
||||||
|
@gridRowWidth768: (@gridColumns * @gridColumnWidth768) + (@gridGutterWidth768 * (@gridColumns - 1));
|
||||||
|
|
||||||
|
|
||||||
|
// Fluid grid
|
||||||
|
// -------------------------
|
||||||
|
@fluidGridColumnWidth: percentage(@gridColumnWidth/@gridRowWidth);
|
||||||
|
@fluidGridGutterWidth: percentage(@gridGutterWidth/@gridRowWidth);
|
||||||
|
|
||||||
|
// 1200px min
|
||||||
|
@fluidGridColumnWidth1200: percentage(@gridColumnWidth1200/@gridRowWidth1200);
|
||||||
|
@fluidGridGutterWidth1200: percentage(@gridGutterWidth1200/@gridRowWidth1200);
|
||||||
|
|
||||||
|
// 768px-979px
|
||||||
|
@fluidGridColumnWidth768: percentage(@gridColumnWidth768/@gridRowWidth768);
|
||||||
|
@fluidGridGutterWidth768: percentage(@gridGutterWidth768/@gridRowWidth768);
|
BIN
src/bootstrap/img/glyphicons-halflings-white.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
src/bootstrap/img/glyphicons-halflings.png
Normal file
After Width: | Height: | Size: 12 KiB |
2025
src/bootstrap/js/bootstrap.js
vendored
Normal file
6
src/bootstrap/js/bootstrap.min.js
vendored
Normal file
|
@ -20,7 +20,7 @@ $opt = $smarty->opt();
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
if (!isset($_SESSION["userid"])) {
|
if (!isset($_SESSION["userid"])) {
|
||||||
header("Location: " . getFullPath("login.php") . "?from=categories.php");
|
header("Location: " . getFullPath("login.php"));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
else if ($_SESSION["admin"] != 1) {
|
else if ($_SESSION["admin"] != 1) {
|
||||||
|
@ -31,42 +31,30 @@ else {
|
||||||
$userid = $_SESSION["userid"];
|
$userid = $_SESSION["userid"];
|
||||||
}
|
}
|
||||||
if (!empty($_GET["message"])) {
|
if (!empty($_GET["message"])) {
|
||||||
$message = filter_var(trim($_GET["message"], FILTER_SANITIZE_STRING));;
|
$message = $_GET["message"];
|
||||||
$message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$haserror = false;
|
|
||||||
$error_message = "";
|
|
||||||
$action = isset($_GET["action"]) ? $_GET["action"] : "";
|
$action = isset($_GET["action"]) ? $_GET["action"] : "";
|
||||||
|
|
||||||
if ($action == "insert" || $action == "update") {
|
if ($action == "insert" || $action == "update") {
|
||||||
/* validate the data. */
|
/* validate the data. */
|
||||||
$category = filter_var(trim($_GET["category"]), FILTER_SANITIZE_STRING);
|
$category = trim($_GET["category"]);
|
||||||
$category = htmlspecialchars($category, ENT_QUOTES, 'UTF-8');
|
|
||||||
|
|
||||||
|
$haserror = false;
|
||||||
if ($category == "") {
|
if ($category == "") {
|
||||||
$haserror = true;
|
$haserror = true;
|
||||||
$error_message = trim("$error_message A category is required.");
|
$category_error = "A category is required.";
|
||||||
$category_error = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_GET["categoryid"])) {
|
|
||||||
$categoryid = filter_var(trim($_GET["categoryid"]), FILTER_SANITIZE_NUMBER_INT);
|
|
||||||
|
|
||||||
if (filter_var($categoryid, FILTER_SANITIZE_NUMBER_INT) === false || $categoryid == "" || !is_numeric($categoryid) || $categoryid < 0) {
|
|
||||||
die("Invalid categoryid ({$_GET["categoryid"]})");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($action == "delete") {
|
if ($action == "delete") {
|
||||||
/* first, NULL all category FKs for items that use this category. */
|
/* first, NULL all category FKs for items that use this category. */
|
||||||
$stmt = $smarty->dbh()->prepare("UPDATE {$opt["table_prefix"]}items SET category = NULL WHERE category = ?");
|
$stmt = $smarty->dbh()->prepare("UPDATE {$opt["table_prefix"]}items SET category = NULL WHERE category = ?");
|
||||||
$stmt->bindValue(1, (int) $categoryid, PDO::PARAM_INT);
|
$stmt->bindValue(1, (int) $_GET["categoryid"], PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$stmt = $smarty->dbh()->prepare("DELETE FROM {$opt["table_prefix"]}categories WHERE categoryid = ?");
|
$stmt = $smarty->dbh()->prepare("DELETE FROM {$opt["table_prefix"]}categories WHERE categoryid = ?");
|
||||||
$stmt->bindValue(1, (int) $categoryid, PDO::PARAM_INT);
|
$stmt->bindValue(1, (int) $_GET["categoryid"], PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
header("Location: " . getFullPath("categories.php?message=Category+deleted."));
|
header("Location: " . getFullPath("categories.php?message=Category+deleted."));
|
||||||
|
@ -74,7 +62,7 @@ if ($action == "delete") {
|
||||||
}
|
}
|
||||||
else if ($action == "edit") {
|
else if ($action == "edit") {
|
||||||
$stmt = $smarty->dbh()->prepare("SELECT category FROM {$opt["table_prefix"]}categories WHERE categoryid = ?");
|
$stmt = $smarty->dbh()->prepare("SELECT category FROM {$opt["table_prefix"]}categories WHERE categoryid = ?");
|
||||||
$stmt->bindValue(1, (int) $categoryid, PDO::PARAM_INT);
|
$stmt->bindValue(1, (int) $_GET["categoryid"], PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
if ($row = $stmt->fetch()) {
|
if ($row = $stmt->fetch()) {
|
||||||
$category = $row["category"];
|
$category = $row["category"];
|
||||||
|
@ -99,7 +87,7 @@ else if ($action == "update") {
|
||||||
"SET category = ? " .
|
"SET category = ? " .
|
||||||
"WHERE categoryid = ?");
|
"WHERE categoryid = ?");
|
||||||
$stmt->bindParam(1, $category, PDO::PARAM_STR);
|
$stmt->bindParam(1, $category, PDO::PARAM_STR);
|
||||||
$stmt->bindValue(2, (int) $categoryid, PDO::PARAM_INT);
|
$stmt->bindValue(2, (int) $_GET["categoryid"], PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
header("Location: " . getFullPath("categories.php?message=Category+updated."));
|
header("Location: " . getFullPath("categories.php?message=Category+updated."));
|
||||||
|
@ -125,8 +113,8 @@ if (isset($action)) {
|
||||||
$smarty->assign('action', $action);
|
$smarty->assign('action', $action);
|
||||||
}
|
}
|
||||||
$smarty->assign('categories', $categories);
|
$smarty->assign('categories', $categories);
|
||||||
if (isset($categoryid)) {
|
if (isset($_GET["categoryid"])) {
|
||||||
$smarty->assign('categoryid', (int) $categoryid);
|
$smarty->assign('categoryid', (int) $_GET["categoryid"]);
|
||||||
}
|
}
|
||||||
if (isset($message)) {
|
if (isset($message)) {
|
||||||
$smarty->assign('message', $message);
|
$smarty->assign('message', $message);
|
||||||
|
@ -136,8 +124,5 @@ if (isset($category_error)) {
|
||||||
$smarty->assign('category_error', $category_error);
|
$smarty->assign('category_error', $category_error);
|
||||||
}
|
}
|
||||||
$smarty->assign('haserror', isset($haserror) ? $haserror : false);
|
$smarty->assign('haserror', isset($haserror) ? $haserror : false);
|
||||||
if ($error_message != "") {
|
|
||||||
$smarty->assign('error_message', $error_message);
|
|
||||||
}
|
|
||||||
$smarty->display('categories.tpl');
|
$smarty->display('categories.tpl');
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
.nav-collapse .nav > li > a:hover,
|
|
||||||
.nav-collapse .dropdown-menu a:hover {
|
|
||||||
background-color: #f2f2f2;
|
|
||||||
}
|
|
||||||
.navbar-inverse .nav-collapse .nav > li > a,
|
|
||||||
.navbar-inverse .nav-collapse .dropdown-menu a {
|
|
||||||
color: #999999;
|
|
||||||
}
|
|
1
src/css/phpgiftrec.min.css
vendored
|
@ -1,20 +0,0 @@
|
||||||
/* Ensure the main content takes up available space */
|
|
||||||
html, body {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
main {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
fill: currentcolor;
|
|
||||||
}
|
|
||||||
|
|
||||||
.boldicon {
|
|
||||||
fill: currentcolor;
|
|
||||||
stroke: currentcolor;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
7
src/datepicker/css/datepicker.css
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
/*
|
||||||
|
Datepicker for Bootstrap
|
||||||
|
Copyright 2012 Stefan Petre
|
||||||
|
Licensed under the Apache License v2.0
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
.datepicker { top: 0; left: 0; padding: 4px; margin-top: 1px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; /*.dow { border-top: 1px solid #ddd !important; }*/ } .datepicker:before { content: ''; display: inline-block; border-left: 7px solid transparent; border-right: 7px solid transparent; border-bottom: 7px solid #ccc; border-bottom-color: rgba(0, 0, 0, 0.2); position: absolute; top: -7px; left: 6px; } .datepicker:after { content: ''; display: inline-block; border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 6px solid #ffffff; position: absolute; top: -6px; left: 7px; } .datepicker > div { display: none; } .datepicker table { width: 100%; margin: 0; } .datepicker td, .datepicker th { text-align: center; width: 20px; height: 20px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .datepicker td.day:hover { background: #eeeeee; cursor: pointer; } .datepicker td.old, .datepicker td.new { color: #999999; } .datepicker td.active, .datepicker td.active:hover { background-color: #006dcc; background-image: -moz-linear-gradient(top, #0088cc, #0044cc); background-image: -ms-linear-gradient(top, #0088cc, #0044cc); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); background-image: -o-linear-gradient(top, #0088cc, #0044cc); background-image: linear-gradient(top, #0088cc, #0044cc); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); border-color: #0044cc #0044cc #002a80; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); color: #fff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } .datepicker td.active:hover, .datepicker td.active:hover:hover, .datepicker td.active:active, .datepicker td.active:hover:active, .datepicker td.active.active, .datepicker td.active:hover.active, .datepicker td.active.disabled, .datepicker td.active:hover.disabled, .datepicker td.active[disabled], .datepicker td.active:hover[disabled] { background-color: #0044cc; } .datepicker td.active:active, .datepicker td.active:hover:active, .datepicker td.active.active, .datepicker td.active:hover.active { background-color: #003399 \9; } .datepicker td span { display: block; width: 47px; height: 54px; line-height: 54px; float: left; margin: 2px; cursor: pointer; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .datepicker td span:hover { background: #eeeeee; } .datepicker td span.active { background-color: #006dcc; background-image: -moz-linear-gradient(top, #0088cc, #0044cc); background-image: -ms-linear-gradient(top, #0088cc, #0044cc); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); background-image: -o-linear-gradient(top, #0088cc, #0044cc); background-image: linear-gradient(top, #0088cc, #0044cc); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); border-color: #0044cc #0044cc #002a80; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); color: #fff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } .datepicker td span.active:hover, .datepicker td span.active:active, .datepicker td span.active.active, .datepicker td span.active.disabled, .datepicker td span.active[disabled] { background-color: #0044cc; } .datepicker td span.active:active, .datepicker td span.active.active { background-color: #003399 \9; } .datepicker td span.old { color: #999999; } .datepicker th.switch { width: 145px; } .datepicker th.next, .datepicker th.prev { font-size: 19.5px; } .datepicker thead tr:first-child th { cursor: pointer; } .datepicker thead tr:first-child th:hover { background: #eeeeee; } .input-append.date .add-on i, .input-prepend.date .add-on i { display: block; cursor: pointer; width: 16px; height: 16px; }
|
454
src/datepicker/js/bootstrap-datepicker.js
vendored
Normal file
|
@ -0,0 +1,454 @@
|
||||||
|
/* =========================================================
|
||||||
|
* bootstrap-datepicker.js
|
||||||
|
* http://www.eyecon.ro/bootstrap-datepicker
|
||||||
|
* =========================================================
|
||||||
|
* Copyright 2012 Stefan Petre
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ========================================================= */
|
||||||
|
|
||||||
|
!function( $ ) {
|
||||||
|
|
||||||
|
// Picker object
|
||||||
|
|
||||||
|
var Datepicker = function(element, options){
|
||||||
|
this.element = $(element);
|
||||||
|
this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy');
|
||||||
|
this.picker = $(DPGlobal.template)
|
||||||
|
.appendTo('body')
|
||||||
|
.on({
|
||||||
|
click: $.proxy(this.click, this),
|
||||||
|
mousedown: $.proxy(this.mousedown, this)
|
||||||
|
});
|
||||||
|
this.isInput = this.element.is('input');
|
||||||
|
this.component = this.element.is('.date') ? this.element.find('.add-on') : false;
|
||||||
|
|
||||||
|
if (this.isInput) {
|
||||||
|
this.element.on({
|
||||||
|
focus: $.proxy(this.show, this),
|
||||||
|
blur: $.proxy(this.hide, this),
|
||||||
|
keyup: $.proxy(this.update, this)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (this.component){
|
||||||
|
this.component.on('click', $.proxy(this.show, this));
|
||||||
|
} else {
|
||||||
|
this.element.on('click', $.proxy(this.show, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0;
|
||||||
|
if (typeof this.minViewMode === 'string') {
|
||||||
|
switch (this.minViewMode) {
|
||||||
|
case 'months':
|
||||||
|
this.minViewMode = 1;
|
||||||
|
break;
|
||||||
|
case 'years':
|
||||||
|
this.minViewMode = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.minViewMode = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.viewMode = options.viewMode||this.element.data('date-viewmode')||0;
|
||||||
|
if (typeof this.viewMode === 'string') {
|
||||||
|
switch (this.viewMode) {
|
||||||
|
case 'months':
|
||||||
|
this.viewMode = 1;
|
||||||
|
break;
|
||||||
|
case 'years':
|
||||||
|
this.viewMode = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.viewMode = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.startViewMode = this.viewMode;
|
||||||
|
this.weekStart = options.weekStart||this.element.data('date-weekstart')||0;
|
||||||
|
this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
|
||||||
|
this.fillDow();
|
||||||
|
this.fillMonths();
|
||||||
|
this.update();
|
||||||
|
this.showMode();
|
||||||
|
};
|
||||||
|
|
||||||
|
Datepicker.prototype = {
|
||||||
|
constructor: Datepicker,
|
||||||
|
|
||||||
|
show: function(e) {
|
||||||
|
this.picker.show();
|
||||||
|
this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
|
||||||
|
this.place();
|
||||||
|
$(window).on('resize', $.proxy(this.place, this));
|
||||||
|
if (e ) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
if (!this.isInput) {
|
||||||
|
$(document).on('mousedown', $.proxy(this.hide, this));
|
||||||
|
}
|
||||||
|
this.element.trigger({
|
||||||
|
type: 'show',
|
||||||
|
date: this.date
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function(){
|
||||||
|
this.picker.hide();
|
||||||
|
$(window).off('resize', this.place);
|
||||||
|
this.viewMode = this.startViewMode;
|
||||||
|
this.showMode();
|
||||||
|
if (!this.isInput) {
|
||||||
|
$(document).off('mousedown', this.hide);
|
||||||
|
}
|
||||||
|
this.set();
|
||||||
|
this.element.trigger({
|
||||||
|
type: 'hide',
|
||||||
|
date: this.date
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
set: function() {
|
||||||
|
var formated = DPGlobal.formatDate(this.date, this.format);
|
||||||
|
if (!this.isInput) {
|
||||||
|
if (this.component){
|
||||||
|
this.element.find('input').prop('value', formated);
|
||||||
|
}
|
||||||
|
this.element.data('date', formated);
|
||||||
|
} else {
|
||||||
|
this.element.prop('value', formated);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setValue: function(newDate) {
|
||||||
|
if (typeof newDate === 'string') {
|
||||||
|
this.date = DPGlobal.parseDate(newDate, this.format);
|
||||||
|
} else {
|
||||||
|
this.date = new Date(newDate);
|
||||||
|
}
|
||||||
|
this.set();
|
||||||
|
this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0);
|
||||||
|
this.fill();
|
||||||
|
},
|
||||||
|
|
||||||
|
place: function(){
|
||||||
|
var offset = this.component ? this.component.offset() : this.element.offset();
|
||||||
|
this.picker.css({
|
||||||
|
top: offset.top + this.height,
|
||||||
|
left: offset.left
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
update: function(newDate){
|
||||||
|
this.date = DPGlobal.parseDate(
|
||||||
|
typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')),
|
||||||
|
this.format
|
||||||
|
);
|
||||||
|
this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0);
|
||||||
|
this.fill();
|
||||||
|
},
|
||||||
|
|
||||||
|
fillDow: function(){
|
||||||
|
var dowCnt = this.weekStart;
|
||||||
|
var html = '<tr>';
|
||||||
|
while (dowCnt < this.weekStart + 7) {
|
||||||
|
html += '<th class="dow">'+DPGlobal.dates.daysMin[(dowCnt++)%7]+'</th>';
|
||||||
|
}
|
||||||
|
html += '</tr>';
|
||||||
|
this.picker.find('.datepicker-days thead').append(html);
|
||||||
|
},
|
||||||
|
|
||||||
|
fillMonths: function(){
|
||||||
|
var html = '';
|
||||||
|
var i = 0
|
||||||
|
while (i < 12) {
|
||||||
|
html += '<span class="month">'+DPGlobal.dates.monthsShort[i++]+'</span>';
|
||||||
|
}
|
||||||
|
this.picker.find('.datepicker-months td').append(html);
|
||||||
|
},
|
||||||
|
|
||||||
|
fill: function() {
|
||||||
|
var d = new Date(this.viewDate),
|
||||||
|
year = d.getFullYear(),
|
||||||
|
month = d.getMonth(),
|
||||||
|
currentDate = this.date.valueOf();
|
||||||
|
this.picker.find('.datepicker-days th:eq(1)')
|
||||||
|
.text(DPGlobal.dates.months[month]+' '+year);
|
||||||
|
var prevMonth = new Date(year, month-1, 28,0,0,0,0),
|
||||||
|
day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth());
|
||||||
|
prevMonth.setDate(day);
|
||||||
|
prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7);
|
||||||
|
var nextMonth = new Date(prevMonth);
|
||||||
|
nextMonth.setDate(nextMonth.getDate() + 42);
|
||||||
|
nextMonth = nextMonth.valueOf();
|
||||||
|
html = [];
|
||||||
|
var clsName;
|
||||||
|
while(prevMonth.valueOf() < nextMonth) {
|
||||||
|
if (prevMonth.getDay() === this.weekStart) {
|
||||||
|
html.push('<tr>');
|
||||||
|
}
|
||||||
|
clsName = '';
|
||||||
|
if (prevMonth.getMonth() < month) {
|
||||||
|
clsName += ' old';
|
||||||
|
} else if (prevMonth.getMonth() > month) {
|
||||||
|
clsName += ' new';
|
||||||
|
}
|
||||||
|
if (prevMonth.valueOf() === currentDate) {
|
||||||
|
clsName += ' active';
|
||||||
|
}
|
||||||
|
html.push('<td class="day'+clsName+'">'+prevMonth.getDate() + '</td>');
|
||||||
|
if (prevMonth.getDay() === this.weekEnd) {
|
||||||
|
html.push('</tr>');
|
||||||
|
}
|
||||||
|
prevMonth.setDate(prevMonth.getDate()+1);
|
||||||
|
}
|
||||||
|
this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
|
||||||
|
var currentYear = this.date.getFullYear();
|
||||||
|
|
||||||
|
var months = this.picker.find('.datepicker-months')
|
||||||
|
.find('th:eq(1)')
|
||||||
|
.text(year)
|
||||||
|
.end()
|
||||||
|
.find('span').removeClass('active');
|
||||||
|
if (currentYear === year) {
|
||||||
|
months.eq(this.date.getMonth()).addClass('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
html = '';
|
||||||
|
year = parseInt(year/10, 10) * 10;
|
||||||
|
var yearCont = this.picker.find('.datepicker-years')
|
||||||
|
.find('th:eq(1)')
|
||||||
|
.text(year + '-' + (year + 9))
|
||||||
|
.end()
|
||||||
|
.find('td');
|
||||||
|
year -= 1;
|
||||||
|
for (var i = -1; i < 11; i++) {
|
||||||
|
html += '<span class="year'+(i === -1 || i === 10 ? ' old' : '')+(currentYear === year ? ' active' : '')+'">'+year+'</span>';
|
||||||
|
year += 1;
|
||||||
|
}
|
||||||
|
yearCont.html(html);
|
||||||
|
},
|
||||||
|
|
||||||
|
click: function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
var target = $(e.target).closest('span, td, th');
|
||||||
|
if (target.length === 1) {
|
||||||
|
switch(target[0].nodeName.toLowerCase()) {
|
||||||
|
case 'th':
|
||||||
|
switch(target[0].className) {
|
||||||
|
case 'switch':
|
||||||
|
this.showMode(1);
|
||||||
|
break;
|
||||||
|
case 'prev':
|
||||||
|
case 'next':
|
||||||
|
this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call(
|
||||||
|
this.viewDate,
|
||||||
|
this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) +
|
||||||
|
DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1)
|
||||||
|
);
|
||||||
|
this.fill();
|
||||||
|
this.set();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'span':
|
||||||
|
if (target.is('.month')) {
|
||||||
|
var month = target.parent().find('span').index(target);
|
||||||
|
this.viewDate.setMonth(month);
|
||||||
|
} else {
|
||||||
|
var year = parseInt(target.text(), 10)||0;
|
||||||
|
this.viewDate.setFullYear(year);
|
||||||
|
}
|
||||||
|
if (this.viewMode !== 0) {
|
||||||
|
this.date = new Date(this.viewDate);
|
||||||
|
this.element.trigger({
|
||||||
|
type: 'changeDate',
|
||||||
|
date: this.date,
|
||||||
|
viewMode: DPGlobal.modes[this.viewMode].clsName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.showMode(-1);
|
||||||
|
this.fill();
|
||||||
|
this.set();
|
||||||
|
break;
|
||||||
|
case 'td':
|
||||||
|
if (target.is('.day')){
|
||||||
|
var day = parseInt(target.text(), 10)||1;
|
||||||
|
var month = this.viewDate.getMonth();
|
||||||
|
if (target.is('.old')) {
|
||||||
|
month -= 1;
|
||||||
|
} else if (target.is('.new')) {
|
||||||
|
month += 1;
|
||||||
|
}
|
||||||
|
var year = this.viewDate.getFullYear();
|
||||||
|
this.date = new Date(year, month, day,0,0,0,0);
|
||||||
|
this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0);
|
||||||
|
this.fill();
|
||||||
|
this.set();
|
||||||
|
this.element.trigger({
|
||||||
|
type: 'changeDate',
|
||||||
|
date: this.date,
|
||||||
|
viewMode: DPGlobal.modes[this.viewMode].clsName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mousedown: function(e){
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
},
|
||||||
|
|
||||||
|
showMode: function(dir) {
|
||||||
|
if (dir) {
|
||||||
|
this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
|
||||||
|
}
|
||||||
|
this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.datepicker = function ( option, val ) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this),
|
||||||
|
data = $this.data('datepicker'),
|
||||||
|
options = typeof option === 'object' && option;
|
||||||
|
if (!data) {
|
||||||
|
$this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options))));
|
||||||
|
}
|
||||||
|
if (typeof option === 'string') data[option](val);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.datepicker.defaults = {
|
||||||
|
};
|
||||||
|
$.fn.datepicker.Constructor = Datepicker;
|
||||||
|
|
||||||
|
var DPGlobal = {
|
||||||
|
modes: [
|
||||||
|
{
|
||||||
|
clsName: 'days',
|
||||||
|
navFnc: 'Month',
|
||||||
|
navStep: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
clsName: 'months',
|
||||||
|
navFnc: 'FullYear',
|
||||||
|
navStep: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
clsName: 'years',
|
||||||
|
navFnc: 'FullYear',
|
||||||
|
navStep: 10
|
||||||
|
}],
|
||||||
|
dates:{
|
||||||
|
days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
|
||||||
|
daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
||||||
|
daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
|
||||||
|
months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
|
||||||
|
monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
||||||
|
},
|
||||||
|
isLeapYear: function (year) {
|
||||||
|
return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
|
||||||
|
},
|
||||||
|
getDaysInMonth: function (year, month) {
|
||||||
|
return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
|
||||||
|
},
|
||||||
|
parseFormat: function(format){
|
||||||
|
var separator = format.match(/[.\/\-\s].*?/),
|
||||||
|
parts = format.split(/\W+/);
|
||||||
|
if (!separator || !parts || parts.length === 0){
|
||||||
|
throw new Error("Invalid date format.");
|
||||||
|
}
|
||||||
|
return {separator: separator, parts: parts};
|
||||||
|
},
|
||||||
|
parseDate: function(date, format) {
|
||||||
|
var parts = date.split(format.separator),
|
||||||
|
date = new Date(),
|
||||||
|
val;
|
||||||
|
date.setHours(0);
|
||||||
|
date.setMinutes(0);
|
||||||
|
date.setSeconds(0);
|
||||||
|
date.setMilliseconds(0);
|
||||||
|
if (parts.length === format.parts.length) {
|
||||||
|
for (var i=0, cnt = format.parts.length; i < cnt; i++) {
|
||||||
|
val = parseInt(parts[i], 10)||1;
|
||||||
|
switch(format.parts[i]) {
|
||||||
|
case 'dd':
|
||||||
|
case 'd':
|
||||||
|
date.setDate(val);
|
||||||
|
break;
|
||||||
|
case 'mm':
|
||||||
|
case 'm':
|
||||||
|
date.setMonth(val - 1);
|
||||||
|
break;
|
||||||
|
case 'yy':
|
||||||
|
date.setFullYear(2000 + val);
|
||||||
|
break;
|
||||||
|
case 'yyyy':
|
||||||
|
date.setFullYear(val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return date;
|
||||||
|
},
|
||||||
|
formatDate: function(date, format){
|
||||||
|
var val = {
|
||||||
|
d: date.getDate(),
|
||||||
|
m: date.getMonth() + 1,
|
||||||
|
yy: date.getFullYear().toString().substring(2),
|
||||||
|
yyyy: date.getFullYear()
|
||||||
|
};
|
||||||
|
val.dd = (val.d < 10 ? '0' : '') + val.d;
|
||||||
|
val.mm = (val.m < 10 ? '0' : '') + val.m;
|
||||||
|
var date = [];
|
||||||
|
for (var i=0, cnt = format.parts.length; i < cnt; i++) {
|
||||||
|
date.push(val[format.parts[i]]);
|
||||||
|
}
|
||||||
|
return date.join(format.separator);
|
||||||
|
},
|
||||||
|
headTemplate: '<thead>'+
|
||||||
|
'<tr>'+
|
||||||
|
'<th class="prev">‹</th>'+
|
||||||
|
'<th colspan="5" class="switch"></th>'+
|
||||||
|
'<th class="next">›</th>'+
|
||||||
|
'</tr>'+
|
||||||
|
'</thead>',
|
||||||
|
contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>'
|
||||||
|
};
|
||||||
|
DPGlobal.template = '<div class="datepicker dropdown-menu">'+
|
||||||
|
'<div class="datepicker-days">'+
|
||||||
|
'<table class=" table-condensed">'+
|
||||||
|
DPGlobal.headTemplate+
|
||||||
|
'<tbody></tbody>'+
|
||||||
|
'</table>'+
|
||||||
|
'</div>'+
|
||||||
|
'<div class="datepicker-months">'+
|
||||||
|
'<table class="table-condensed">'+
|
||||||
|
DPGlobal.headTemplate+
|
||||||
|
DPGlobal.contTemplate+
|
||||||
|
'</table>'+
|
||||||
|
'</div>'+
|
||||||
|
'<div class="datepicker-years">'+
|
||||||
|
'<table class="table-condensed">'+
|
||||||
|
DPGlobal.headTemplate+
|
||||||
|
DPGlobal.contTemplate+
|
||||||
|
'</table>'+
|
||||||
|
'</div>'+
|
||||||
|
'</div>';
|
||||||
|
|
||||||
|
}( window.jQuery )
|
119
src/datepicker/less/datepicker.less
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/*!
|
||||||
|
* Datepicker for Bootstrap
|
||||||
|
*
|
||||||
|
* Copyright 2012 Stefan Petre
|
||||||
|
* Licensed under the Apache License v2.0
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
.datepicker {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: 4px;
|
||||||
|
margin-top: 1px;
|
||||||
|
.border-radius(4px);
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
border-left: 7px solid transparent;
|
||||||
|
border-right: 7px solid transparent;
|
||||||
|
border-bottom: 7px solid #ccc;
|
||||||
|
border-bottom-color: rgba(0,0,0,.2);
|
||||||
|
position: absolute;
|
||||||
|
top: -7px;
|
||||||
|
left: 6px;
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
border-left: 6px solid transparent;
|
||||||
|
border-right: 6px solid transparent;
|
||||||
|
border-bottom: 6px solid @white;
|
||||||
|
position: absolute;
|
||||||
|
top: -6px;
|
||||||
|
left: 7px;
|
||||||
|
}
|
||||||
|
>div {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
table{
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
td,
|
||||||
|
th{
|
||||||
|
text-align: center;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
.border-radius(4px);
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
&.day:hover {
|
||||||
|
background: @grayLighter;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
&.old,
|
||||||
|
&.new {
|
||||||
|
color: @grayLight;
|
||||||
|
}
|
||||||
|
&.active,
|
||||||
|
&.active:hover {
|
||||||
|
.buttonBackground(@primaryButtonBackground, spin(@primaryButtonBackground, 20));
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0 -1px 0 rgba(0,0,0,.25);
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
width: 47px;
|
||||||
|
height: 54px;
|
||||||
|
line-height: 54px;
|
||||||
|
float: left;
|
||||||
|
margin: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
.border-radius(4px);
|
||||||
|
&:hover {
|
||||||
|
background: @grayLighter;
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
.buttonBackground(@primaryButtonBackground, spin(@primaryButtonBackground, 20));
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0 -1px 0 rgba(0,0,0,.25);
|
||||||
|
}
|
||||||
|
&.old {
|
||||||
|
color: @grayLight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
&.switch {
|
||||||
|
width: 145px;
|
||||||
|
}
|
||||||
|
&.next,
|
||||||
|
&.prev {
|
||||||
|
font-size: @baseFontSize * 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thead tr:first-child th {
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover{
|
||||||
|
background: @grayLighter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*.dow {
|
||||||
|
border-top: 1px solid #ddd !important;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
.input-append,
|
||||||
|
.input-prepend {
|
||||||
|
&.date {
|
||||||
|
.add-on i {
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,7 +20,7 @@ $opt = $smarty->opt();
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
if (!isset($_SESSION["userid"])) {
|
if (!isset($_SESSION["userid"])) {
|
||||||
header("Location: " . getFullPath("login.php") . "?from=event.php");
|
header("Location: " . getFullPath("login.php"));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -28,20 +28,12 @@ else {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($_GET["message"])) {
|
if (!empty($_GET["message"])) {
|
||||||
$message = filter_var(trim($_GET["message"], FILTER_SANITIZE_STRING));;
|
$message = $_GET["message"];
|
||||||
$message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_GET["eventid"])) {
|
if (isset($_GET["eventid"])) {
|
||||||
$eventid = filter_var(trim($_GET["eventid"]), FILTER_SANITIZE_NUMBER_INT);
|
$eventid = $_GET["eventid"];
|
||||||
|
|
||||||
if (filter_var($eventid, FILTER_SANITIZE_NUMBER_INT) === false || $eventid == "" || !is_numeric($eventid) || $eventid < 0) {
|
|
||||||
die("Invalid eventid ({$_GET["eventid"]})");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$haserror = false;
|
|
||||||
$error_message = "";
|
|
||||||
|
|
||||||
// for security, let's make sure that if an eventid was passed in, it belongs
|
// for security, let's make sure that if an eventid was passed in, it belongs
|
||||||
// to $userid (or is a system event and the user is an admin).
|
// to $userid (or is a system event and the user is an admin).
|
||||||
|
@ -70,7 +62,7 @@ $action = isset($_GET["action"]) ? $_GET["action"] : "";
|
||||||
|
|
||||||
if ($action == "insert" || $action == "update") {
|
if ($action == "insert" || $action == "update") {
|
||||||
/* validate the data. */
|
/* validate the data. */
|
||||||
$description = filter_var(trim($_GET["description"], FILTER_SANITIZE_STRING));;
|
$description = trim($_GET["description"]);
|
||||||
try {
|
try {
|
||||||
$eventdate = new DateTime($_GET["eventdate"]);
|
$eventdate = new DateTime($_GET["eventdate"]);
|
||||||
}
|
}
|
||||||
|
@ -80,15 +72,14 @@ if ($action == "insert" || $action == "update") {
|
||||||
$recurring = (strtoupper($_GET["recurring"]) == "ON" ? 1 : 0);
|
$recurring = (strtoupper($_GET["recurring"]) == "ON" ? 1 : 0);
|
||||||
$systemevent = (strtoupper($_GET["systemevent"]) == "ON" ? 1 : 0);
|
$systemevent = (strtoupper($_GET["systemevent"]) == "ON" ? 1 : 0);
|
||||||
|
|
||||||
|
$haserror = false;
|
||||||
if ($description == "") {
|
if ($description == "") {
|
||||||
$haserror = true;
|
$haserror = true;
|
||||||
$error_message = trim("$error_message A description is required.");
|
$description_error = "A description is required.";
|
||||||
$description_error = true;
|
|
||||||
}
|
}
|
||||||
if ($eventdate == FALSE) {
|
if ($eventdate == FALSE) {
|
||||||
$haserror = true;
|
$haserror = true;
|
||||||
$error_message = trim("$error_message Date is out of range for this server.");
|
$eventdate_error = "Date is out of range for this server.";
|
||||||
$eventdate_error = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,9 +198,6 @@ try {
|
||||||
}
|
}
|
||||||
$smarty->assign('action', $action);
|
$smarty->assign('action', $action);
|
||||||
$smarty->assign('haserror', isset($haserror) ? $haserror : false);
|
$smarty->assign('haserror', isset($haserror) ? $haserror : false);
|
||||||
if ($error_message != "") {
|
|
||||||
$smarty->assign('error_message', $error_message);
|
|
||||||
}
|
|
||||||
$smarty->assign('events', $events);
|
$smarty->assign('events', $events);
|
||||||
$smarty->assign('eventdate', $eventdate->format($opt["date_format"]));
|
$smarty->assign('eventdate', $eventdate->format($opt["date_format"]));
|
||||||
if (isset($eventdate_error)) {
|
if (isset($eventdate_error)) {
|
||||||
|
|
|
@ -19,10 +19,8 @@ $smarty = new MySmarty();
|
||||||
$opt = $smarty->opt();
|
$opt = $smarty->opt();
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
$haserror = false;
|
|
||||||
$error_message = "";
|
|
||||||
if (!isset($_SESSION["userid"])) {
|
if (!isset($_SESSION["userid"])) {
|
||||||
header("Location: " . getFullPath("login.php") . "?from=families.php");
|
header("Location: " . getFullPath("login.php"));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
else if ($_SESSION["admin"] != 1) {
|
else if ($_SESSION["admin"] != 1) {
|
||||||
|
@ -33,44 +31,22 @@ else {
|
||||||
$userid = $_SESSION["userid"];
|
$userid = $_SESSION["userid"];
|
||||||
}
|
}
|
||||||
if (!empty($_GET["message"])) {
|
if (!empty($_GET["message"])) {
|
||||||
$message = filter_var(trim($_GET["message"], FILTER_SANITIZE_STRING));;
|
$message = $_GET["message"];
|
||||||
$message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$action = empty($_GET["action"]) ? "" : $_GET["action"];
|
$action = empty($_GET["action"]) ? "" : $_GET["action"];
|
||||||
|
|
||||||
if (isset($_GET["familyid"])) {
|
if (!empty($_GET["familyid"]))
|
||||||
$familyid = filter_var(trim($_GET["familyid"]), FILTER_SANITIZE_NUMBER_INT);
|
$familyid = (int) $_GET["familyid"];
|
||||||
|
|
||||||
if (filter_var($familyid, FILTER_SANITIZE_NUMBER_INT) === false || $familyid == "" || !is_numeric($familyid) || $familyid < 0) {
|
|
||||||
die("Invalid familyid ({$_GET["familyid"]})");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($familyid)) $familyid = 1;
|
|
||||||
|
|
||||||
if (isset($_GET["members"])) {
|
|
||||||
$members = isset($_GET["members"]) ? $_GET["members"] : array();
|
|
||||||
if (!is_array($members)) {
|
|
||||||
die("Invalid data for members ({$_GET["members"]})");
|
|
||||||
}
|
|
||||||
foreach ($members as $index => $member) {
|
|
||||||
$members[$index] = filter_var($member, FILTER_SANITIZE_NUMBER_INT);
|
|
||||||
if (filter_var($members[$index], FILTER_SANITIZE_NUMBER_INT) === false) {
|
|
||||||
die("Invalid data for members ({$_GET["members"]})");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($action == "insert" || $action == "update") {
|
if ($action == "insert" || $action == "update") {
|
||||||
/* validate the data. */
|
/* validate the data. */
|
||||||
$familyname = filter_var(trim($_GET["familyname"]), FILTER_SANITIZE_STRING);
|
$familyname = trim($_GET["familyname"]);
|
||||||
$familyname = htmlspecialchars($familyname, ENT_QUOTES, 'UTF-8');
|
|
||||||
|
|
||||||
|
$haserror = false;
|
||||||
if ($familyname == "") {
|
if ($familyname == "") {
|
||||||
$haserror = true;
|
$haserror = true;
|
||||||
$error_message = "A family name is required.";
|
$familyname_error = "A family name is required.";
|
||||||
$familyname_error = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +121,7 @@ else if ($action == "update") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ($action == "members") {
|
else if ($action == "members") {
|
||||||
|
$members = isset($_GET["members"]) ? $_GET["members"] : array();
|
||||||
try {
|
try {
|
||||||
/* first, delete all memberships for this family. */
|
/* first, delete all memberships for this family. */
|
||||||
$stmt = $smarty->dbh()->prepare("DELETE FROM {$opt["table_prefix"]}memberships WHERE familyid = ?");
|
$stmt = $smarty->dbh()->prepare("DELETE FROM {$opt["table_prefix"]}memberships WHERE familyid = ?");
|
||||||
|
@ -196,9 +173,6 @@ try {
|
||||||
|
|
||||||
$smarty->assign('action', $action);
|
$smarty->assign('action', $action);
|
||||||
$smarty->assign('haserror', $haserror);
|
$smarty->assign('haserror', $haserror);
|
||||||
if ($error_message != "") {
|
|
||||||
$smarty->assign('error_message', $error_message);
|
|
||||||
}
|
|
||||||
if (isset($familyname_error)) {
|
if (isset($familyname_error)) {
|
||||||
$smarty->assign('familyname_error', $familyname_error);
|
$smarty->assign('familyname_error', $familyname_error);
|
||||||
}
|
}
|
||||||
|
|
BIN
src/favicon.ico
Before Width: | Height: | Size: 68 KiB |
|
@ -64,8 +64,6 @@ if (isset($_POST["action"]) && $_POST["action"] == "forgot") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!isset($username)) $username = "";
|
|
||||||
$smarty->assign('username', $username);
|
|
||||||
$smarty->display('forgot.tpl');
|
$smarty->display('forgot.tpl');
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
76
src/help.php
|
@ -1,76 +0,0 @@
|
||||||
<?php
|
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
require_once(dirname(__FILE__) . "/includes/funcLib.php");
|
|
||||||
require_once(dirname(__FILE__) . "/includes/MySmarty.class.php");
|
|
||||||
$smarty = new MySmarty();
|
|
||||||
$opt = $smarty->opt();
|
|
||||||
|
|
||||||
session_start();
|
|
||||||
if (!isset($_SESSION["userid"])) {
|
|
||||||
header("Location: " . getFullPath("login.php") . "?from=help.php");
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$userid = $_SESSION["userid"];
|
|
||||||
}
|
|
||||||
|
|
||||||
$action = "";
|
|
||||||
if (!empty($_POST["action"])) {
|
|
||||||
$action = $_POST["action"];
|
|
||||||
|
|
||||||
if ($action == "save") {
|
|
||||||
if (!empty($_POST["show_helptext"]))
|
|
||||||
$show_helptext = ($_POST["show_helptext"] == "on" ? 1 : 0);
|
|
||||||
else
|
|
||||||
$show_helptext = 0;
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = $smarty->dbh()->prepare("UPDATE {$opt["table_prefix"]}users SET show_helptext = ? WHERE userid = ?");
|
|
||||||
$stmt->bindParam(1, $show_helptext, PDO::PARAM_BOOL);
|
|
||||||
$stmt->bindParam(2, $userid, PDO::PARAM_INT);
|
|
||||||
$stmt->execute();
|
|
||||||
}
|
|
||||||
catch (PDOException $e) {
|
|
||||||
die("sql exception: " . $e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
die("Unknown verb.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = $smarty->dbh()->prepare("SELECT show_helptext FROM {$opt["table_prefix"]}users WHERE userid = ?");
|
|
||||||
$stmt->bindParam(1, $userid, PDO::PARAM_INT);
|
|
||||||
|
|
||||||
$stmt->execute();
|
|
||||||
if ($row = $stmt->fetch()) {
|
|
||||||
$smarty->assign('show_helptext', $row["show_helptext"]);
|
|
||||||
$_SESSION['show_helptext'] = $row["show_helptext"];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
die("You don't exist.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (PDOException $e) {
|
|
||||||
die("sql exception: " . $e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
$smarty->assign('myurl', "{$_SERVER['REQUEST_SCHEME']}://{$_SERVER['HTTP_HOST']}");
|
|
||||||
$smarty->display('help.tpl');
|
|
||||||
|
|
||||||
?>
|
|
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 701 B |
Before Width: | Height: | Size: 698 B |
Before Width: | Height: | Size: 718 B |
Before Width: | Height: | Size: 724 B |
Before Width: | Height: | Size: 687 B |
Before Width: | Height: | Size: 6 KiB |
Before Width: | Height: | Size: 854 B |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 736 B |
Before Width: | Height: | Size: 6 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 972 B |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1,013 B |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 845 B |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 20 KiB |
|
@ -1,10 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
define('SMARTY_DIR', dirname(__FILE__) . "/smarty-5.4.1/libs/");
|
define('SMARTY_DIR', dirname(__FILE__) . "/smarty-3.1.48/libs/");
|
||||||
require_once(SMARTY_DIR . "Smarty.class.php");
|
require_once(SMARTY_DIR . "Smarty.class.php");
|
||||||
require_once(dirname(__FILE__) . "/config.php");
|
require_once(dirname(__FILE__) . "/config.php");
|
||||||
|
|
||||||
class MySmarty extends Smarty\Smarty {
|
class MySmarty extends Smarty {
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
|
@ -19,12 +19,11 @@ class MySmarty extends Smarty\Smarty {
|
||||||
$opt["pdo_password"]);
|
$opt["pdo_password"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function opt($session = NULL) {
|
public function opt() {
|
||||||
static $opt;
|
static $opt;
|
||||||
if (!isset($opt)) {
|
if (!isset($opt)) {
|
||||||
$opt = getGlobalOptions();
|
$opt = getGlobalOptions();
|
||||||
}
|
}
|
||||||
$opt['show_helptext'] = isset($_SESSION['show_helptext']) ? $_SESSION['show_helptext'] : $opt['show_helptext'];
|
|
||||||
return $opt;
|
return $opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,32 +14,15 @@
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
function getGlobalOptions() {
|
function getGlobalOptions() {
|
||||||
// Read information
|
|
||||||
$conf_file = '/var/www/conf/phpgiftreg.conf';
|
|
||||||
$mysql_conn_string = "mysql:host=localhost;dbname=giftreg";
|
|
||||||
$mysql_username = "giftreg";
|
|
||||||
$mysql_password = "cn3Malk";
|
|
||||||
if (file_exists($conf_file)) {
|
|
||||||
$ini_file = parse_ini_file($conf_file);
|
|
||||||
if (isset($ini_file['mysql_conn_string'])) {
|
|
||||||
$mysql_conn_string = $ini_file['mysql_conn_string'];
|
|
||||||
}
|
|
||||||
if (isset($ini_file['mysql_username'])) {
|
|
||||||
$mysql_username = $ini_file['mysql_username'];
|
|
||||||
}
|
|
||||||
if (isset($ini_file['mysql_password'])) {
|
|
||||||
$mysql_password = $ini_file['mysql_password'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array(
|
return array(
|
||||||
/* The PDO connection string.
|
/* The PDO connection string.
|
||||||
http://www.php.net/manual/en/pdo.connections.php
|
http://www.php.net/manual/en/pdo.connections.php
|
||||||
*/
|
*/
|
||||||
"pdo_connection_string" => $mysql_conn_string,
|
"pdo_connection_string" => "mysql:host=localhost;dbname=giftreg",
|
||||||
|
|
||||||
/* The database username and password. */
|
/* The database username and password. */
|
||||||
"pdo_username" => $mysql_username,
|
"pdo_username" => "giftreg",
|
||||||
"pdo_password" => $mysql_password,
|
"pdo_password" => "cn3Malk",
|
||||||
|
|
||||||
/* The maximum number of days before an event which produces a notification. */
|
/* The maximum number of days before an event which produces a notification. */
|
||||||
"event_threshold" => "60",
|
"event_threshold" => "60",
|
||||||
|
@ -48,7 +31,7 @@ function getGlobalOptions() {
|
||||||
0 = auto-approve,
|
0 = auto-approve,
|
||||||
1 = require approval
|
1 = require approval
|
||||||
*/
|
*/
|
||||||
"shop_requires_approval" => 0,
|
"shop_requires_approval" => 1,
|
||||||
|
|
||||||
/* Whether or not requesting a new account is immediately approved.
|
/* Whether or not requesting a new account is immediately approved.
|
||||||
0 = auto-approve,
|
0 = auto-approve,
|
||||||
|
@ -56,12 +39,6 @@ function getGlobalOptions() {
|
||||||
*/
|
*/
|
||||||
"newuser_requires_approval" => 1,
|
"newuser_requires_approval" => 1,
|
||||||
|
|
||||||
/* Do not allow new user to choose family
|
|
||||||
0 = allow new user to choose family
|
|
||||||
1 or more = default family
|
|
||||||
*/
|
|
||||||
"newuser_default_family" => 1,
|
|
||||||
|
|
||||||
/* Whether or not whom an item is reserved/bought by is hidden. */
|
/* Whether or not whom an item is reserved/bought by is hidden. */
|
||||||
"anonymous_purchasing" => 0,
|
"anonymous_purchasing" => 0,
|
||||||
|
|
||||||
|
@ -69,30 +46,27 @@ function getGlobalOptions() {
|
||||||
"items_per_page" => 10,
|
"items_per_page" => 10,
|
||||||
|
|
||||||
/* The e-mail From: header. */
|
/* The e-mail From: header. */
|
||||||
"email_from" => "wishlist@erdelynet.com",
|
"email_from" => "webmaster@" . $_SERVER['SERVER_NAME'],
|
||||||
|
|
||||||
/* The e-mail Reply-To: header. */
|
/* The e-mail Reply-To: header. */
|
||||||
"email_reply_to" => "wishlist@erdelynet.com",
|
"email_reply_to" => "rwalberg@mts.net",
|
||||||
|
|
||||||
/* The e-mail X-Mailer header. */
|
/* The e-mail X-Mailer header. */
|
||||||
"email_xmailer" => "PHP/" . phpversion(),
|
"email_xmailer" => "PHP/" . phpversion(),
|
||||||
|
|
||||||
/* Application name. */
|
|
||||||
"app_name" => "Gift Wishlist",
|
|
||||||
|
|
||||||
/* Whether or not to show brief blurbs in certain spots which describe how
|
/* Whether or not to show brief blurbs in certain spots which describe how
|
||||||
features work.
|
features work.
|
||||||
0 = don't help text,
|
0 = don't help text,
|
||||||
1 = show help text
|
1 = show help text
|
||||||
*/
|
*/
|
||||||
"show_helptext" => 1,
|
"show_helptext" => 0,
|
||||||
|
|
||||||
/* Whether or not clicking the Delete Item link requires a JavaScript-based
|
/* Whether or not clicking the Delete Item link requires a JavaScript-based
|
||||||
confirmation.
|
confirmation.
|
||||||
0 = don't show confirmation,
|
0 = don't show confirmation,
|
||||||
1 = show confirmation
|
1 = show confirmation
|
||||||
*/
|
*/
|
||||||
"confirm_item_deletes" => 1,
|
"confirm_item_deletes" => 0,
|
||||||
|
|
||||||
/* Whether or not to allow multiple quantities of an item. */
|
/* Whether or not to allow multiple quantities of an item. */
|
||||||
"allow_multiples" => 1,
|
"allow_multiples" => 1,
|
||||||
|
@ -128,39 +102,7 @@ function getGlobalOptions() {
|
||||||
0 = don't hide it,
|
0 = don't hide it,
|
||||||
1 = hide it
|
1 = hide it
|
||||||
*/
|
*/
|
||||||
"hide_zero_price" => 0,
|
"hide_zero_price" => 1,
|
||||||
|
|
||||||
/* Default raking
|
|
||||||
This is the default rankings list:
|
|
||||||
5 = I'd love to get this
|
|
||||||
4 = I would really, really like this
|
|
||||||
3 = Would make me happy
|
|
||||||
2 = Would be nice to have
|
|
||||||
1 = Wouldn't mind it
|
|
||||||
*/
|
|
||||||
"default_ranking" => 3,
|
|
||||||
|
|
||||||
/* Default category
|
|
||||||
This is the default categories list:
|
|
||||||
1 = Miscellaneous
|
|
||||||
2 = Music
|
|
||||||
3 = Video Games
|
|
||||||
4 = Clothing
|
|
||||||
5 = Movies/DVD
|
|
||||||
6 = Gift Certificates
|
|
||||||
7 = Hobbies
|
|
||||||
8 = Household
|
|
||||||
9 = Electronics
|
|
||||||
10 = Ornaments/Figurines
|
|
||||||
11 = Automotive
|
|
||||||
12 = Toys
|
|
||||||
13 = Jewelry
|
|
||||||
14 = Computer
|
|
||||||
15 = Games
|
|
||||||
16 = Tools
|
|
||||||
17 = Books
|
|
||||||
*/
|
|
||||||
"default_category" => 1,
|
|
||||||
|
|
||||||
/* Whether or not to hash passwords. Your version of MySQL may or may not
|
/* Whether or not to hash passwords. Your version of MySQL may or may not
|
||||||
support it.
|
support it.
|
||||||
|
@ -171,7 +113,7 @@ function getGlobalOptions() {
|
||||||
UPDATE users SET password = MD5(password)
|
UPDATE users SET password = MD5(password)
|
||||||
on your database to convert the passwords. This operation is NON-REVERSIBLE!
|
on your database to convert the passwords. This operation is NON-REVERSIBLE!
|
||||||
*/
|
*/
|
||||||
"password_hasher" => "SHA1",
|
"password_hasher" => "MD5",
|
||||||
|
|
||||||
/* Whether or not to allow image uploads. If on, the next option must point to
|
/* Whether or not to allow image uploads. If on, the next option must point to
|
||||||
a valid subdirectory that is writeable by the web server. The setup.php
|
a valid subdirectory that is writeable by the web server. The setup.php
|
||||||
|
|
|
@ -1,138 +0,0 @@
|
||||||
<?php
|
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
function getGlobalOptions() {
|
|
||||||
return array(
|
|
||||||
/* The PDO connection string.
|
|
||||||
http://www.php.net/manual/en/pdo.connections.php
|
|
||||||
*/
|
|
||||||
"pdo_connection_string" => "mysql:host=localhost;dbname=giftreg",
|
|
||||||
|
|
||||||
/* The database username and password. */
|
|
||||||
"pdo_username" => "giftreg",
|
|
||||||
"pdo_password" => "cn3Malk",
|
|
||||||
|
|
||||||
/* The maximum number of days before an event which produces a notification. */
|
|
||||||
"event_threshold" => "60",
|
|
||||||
|
|
||||||
/* Whether or not requesting to shop for someone is immediately approved.
|
|
||||||
0 = auto-approve,
|
|
||||||
1 = require approval
|
|
||||||
*/
|
|
||||||
"shop_requires_approval" => 1,
|
|
||||||
|
|
||||||
/* Whether or not requesting a new account is immediately approved.
|
|
||||||
0 = auto-approve,
|
|
||||||
1 = require administrator approval
|
|
||||||
*/
|
|
||||||
"newuser_requires_approval" => 1,
|
|
||||||
|
|
||||||
/* Whether or not whom an item is reserved/bought by is hidden. */
|
|
||||||
"anonymous_purchasing" => 0,
|
|
||||||
|
|
||||||
/* The number of your items that show on each page. */
|
|
||||||
"items_per_page" => 10,
|
|
||||||
|
|
||||||
/* The e-mail From: header. */
|
|
||||||
"email_from" => "webmaster@" . $_SERVER['SERVER_NAME'],
|
|
||||||
|
|
||||||
/* The e-mail Reply-To: header. */
|
|
||||||
"email_reply_to" => "rwalberg@mts.net",
|
|
||||||
|
|
||||||
/* The e-mail X-Mailer header. */
|
|
||||||
"email_xmailer" => "PHP/" . phpversion(),
|
|
||||||
|
|
||||||
/* Whether or not to show brief blurbs in certain spots which describe how
|
|
||||||
features work.
|
|
||||||
0 = don't help text,
|
|
||||||
1 = show help text
|
|
||||||
*/
|
|
||||||
"show_helptext" => 0,
|
|
||||||
|
|
||||||
/* Whether or not clicking the Delete Item link requires a JavaScript-based
|
|
||||||
confirmation.
|
|
||||||
0 = don't show confirmation,
|
|
||||||
1 = show confirmation
|
|
||||||
*/
|
|
||||||
"confirm_item_deletes" => 0,
|
|
||||||
|
|
||||||
/* Whether or not to allow multiple quantities of an item. */
|
|
||||||
"allow_multiples" => 1,
|
|
||||||
|
|
||||||
/* This is prefixed to all currency values, set it as appropriate for your currency. */
|
|
||||||
"currency_symbol" => "$", // US or other dollars
|
|
||||||
//"currency_symbol" => "£", // Pound (£) symbol
|
|
||||||
//"currency_symbol" => "¥", // Yen
|
|
||||||
//"currency_symbol" => "€", // Euro
|
|
||||||
//"currency_symbol" => "€", // Euro alternative
|
|
||||||
|
|
||||||
/* The date format used in DateTime::format()
|
|
||||||
http://php.net/manual/en/function.date.php */
|
|
||||||
"date_format" => "m/d/Y",
|
|
||||||
|
|
||||||
/* If this is set to something other than "" then phpgiftreg will expect that
|
|
||||||
string to prefix all tables in this installation. Useful for running
|
|
||||||
multiple phpgiftreg installations in the same MySQL database.
|
|
||||||
*/
|
|
||||||
"table_prefix" => "",
|
|
||||||
//"table_prefix" => "gift_", // all tables must be prefixed by `gift_'
|
|
||||||
|
|
||||||
/* Whether or not your own events show up on the home page.
|
|
||||||
0 = don't show my own events,
|
|
||||||
1 = show my own events
|
|
||||||
*/
|
|
||||||
"show_own_events" => 1,
|
|
||||||
|
|
||||||
/* The length of random generated passwords. */
|
|
||||||
"password_length" => 8,
|
|
||||||
|
|
||||||
/* Whether or not to hide the price when it's $0.00.
|
|
||||||
0 = don't hide it,
|
|
||||||
1 = hide it
|
|
||||||
*/
|
|
||||||
"hide_zero_price" => 1,
|
|
||||||
|
|
||||||
/* Whether or not to hash passwords. Your version of MySQL may or may not
|
|
||||||
support it.
|
|
||||||
"MD5" = use MySQL's MD5() function,
|
|
||||||
"SHA1" = use MySQL's SHA1() function,
|
|
||||||
"" = use nothing (store passwords in plaintext).
|
|
||||||
If you switch this on, you're going to need to do a
|
|
||||||
UPDATE users SET password = MD5(password)
|
|
||||||
on your database to convert the passwords. This operation is NON-REVERSIBLE!
|
|
||||||
*/
|
|
||||||
"password_hasher" => "MD5",
|
|
||||||
|
|
||||||
/* Whether or not to allow image uploads. If on, the next option must point to
|
|
||||||
a valid subdirectory that is writeable by the web server. The setup.php
|
|
||||||
script will confirm this.
|
|
||||||
0 = don't allow images,
|
|
||||||
1 = allow images
|
|
||||||
*/
|
|
||||||
"allow_images" => 1,
|
|
||||||
|
|
||||||
/* The *sub*-directory we we can store item images. If you don't want to
|
|
||||||
allow images to be attached to items, leave this variable empty ("").
|
|
||||||
Trailing / is optional.
|
|
||||||
*/
|
|
||||||
"image_subdir" => "item_images",
|
|
||||||
|
|
||||||
/* The number of minutes in between subscription notifications so the subscribers
|
|
||||||
don't get flooded with updates.
|
|
||||||
*/
|
|
||||||
"notify_threshold_minutes" => 60
|
|
||||||
);
|
|
||||||
}
|
|
||||||
?>
|
|
|
@ -6,265 +6,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
## [5.4.1] - 2024-08-29
|
## [3.1.48] - 2023-03-28
|
||||||
|
|
||||||
|
|
||||||
- Enable (and fix) unit tests for Windows [#1046](https://github.com/smarty-php/smarty/pull/1046)
|
|
||||||
- Fix the use of "extends:" to define the inheritance tree on Windows [#1018](https://github.com/smarty-php/smarty/issues/1018)
|
|
||||||
|
|
||||||
## [5.4.0] - 2024-08-14
|
|
||||||
- Fixing forced OpCache invalidation on every template include, which is resulting in fast raising wasted OpCache memory [#1007](https://github.com/smarty-php/smarty/issues/1007)
|
|
||||||
- Improvement of auto-escaping [#1030](https://github.com/smarty-php/smarty/pull/1030)
|
|
||||||
|
|
||||||
|
|
||||||
## [5.3.1] - 2024-06-16
|
|
||||||
- Fixed error when using section with nocache [#1034](https://github.com/smarty-php/smarty/issues/1034)
|
|
||||||
|
|
||||||
|
|
||||||
## [5.3.0] - 2024-05-30
|
|
||||||
- Fix warning when calling hasVariable for an undefined variable [#977](https://github.com/smarty-php/smarty/issues/977)
|
|
||||||
- Added `$smarty->prependTemplateDir()` method [#1022](https://github.com/smarty-php/smarty/issues/1022)
|
|
||||||
|
|
||||||
|
|
||||||
## [5.2.0] - 2024-05-28
|
|
||||||
- Fixed a code injection vulnerability in extends-tag. This addresses CVE-2024-35226.
|
|
||||||
- Added `$smarty->setCacheModifiedCheck()` setter for cache_modified_check
|
|
||||||
- Added a PSR-4 loading script to allow Smarty to be used without Composer [#1017](https://github.com/smarty-php/smarty/pull/1017)
|
|
||||||
|
|
||||||
|
|
||||||
## [5.1.0] - 2024-04-22
|
|
||||||
- Prevent deprecation notices during compilation in PHP8.3 [#996](https://github.com/smarty-php/smarty/issues/996)
|
|
||||||
- Fix that getTemplateVars would return an array of objects instead of the assigned variables values [#994](https://github.com/smarty-php/smarty/issues/994)
|
|
||||||
- Fix Smarty::assign() not returning $this when called with an array as first parameter [#972](https://github.com/smarty-php/smarty/pull/972)
|
|
||||||
- Documented support for `{if $element is in $array}` syntax [#937](https://github.com/smarty-php/smarty/issues/937)
|
|
||||||
- Added support for `{if $element is not in $array}` syntax [#937](https://github.com/smarty-php/smarty/issues/937)
|
|
||||||
- Using stream variables in templates now throws a deprecation notice [#933](https://github.com/smarty-php/smarty/pull/933)
|
|
||||||
- Internal compiler classes always return a string (the internal has_code flag has been removed for simplicity) [#918](https://github.com/smarty-php/smarty/pull/918)
|
|
||||||
- Fix invalid classnames in Runtime code for foreach [#1000](https://github.com/smarty-php/smarty/issues/1000)
|
|
||||||
|
|
||||||
## [5.0.2] - 2024-03-28
|
|
||||||
- Fix Smarty::assign() not returning $this when called with an array as first parameter [#972](https://github.com/smarty-php/smarty/pull/972)
|
|
||||||
|
|
||||||
## [5.0.1] - 2024-03-27
|
|
||||||
- Fix error in Smarty\Smarty::compileAllTemplates() by including missing FilesystemIterator class [#966](https://github.com/smarty-php/smarty/issues/966)
|
|
||||||
|
|
||||||
## [5.0.0] - 2024-03-25
|
|
||||||
- Fixed that scoped variables would overwrite parent scope [#952](https://github.com/smarty-php/smarty/issues/952)
|
|
||||||
- Removed publicly accessible `$tpl->_var_stack` variable
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Too many shorthand attributes error when using a modifier as a function with more than 3 parameters in an expression [#949](https://github.com/smarty-php/smarty/issues/949)
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
- Dropped support for undocumented `{time()}` added in v5.0.0 since we already have the documented `{$smarty.now}`
|
|
||||||
|
|
||||||
## [5.0.0-rc3] - 2024-02-26
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- PHP8.3 support [#925](https://github.com/smarty-php/smarty/issues/925)
|
|
||||||
- Backlink to GitHub in docs
|
|
||||||
- Explain how to do escaping and set-up auto-escaping in docs [#865](https://github.com/smarty-php/smarty/issues/865)
|
|
||||||
- Link to variable scope page in the documentation for the assign tag [#878](https://github.com/smarty-php/smarty/issues/878)
|
|
||||||
- Add support for implode, substr and json_encode as modifiers/functions in templates [#939](https://github.com/smarty-php/smarty/issues/939)
|
|
||||||
- Add template path to CompilerException to enable rich debug features [#935](https://github.com/smarty-php/smarty/issues/935)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- The {debug} tag was broken in v5 [#922](https://github.com/smarty-php/smarty/issues/922)
|
|
||||||
- Documentation on `{if $x is even by $y}` syntax
|
|
||||||
- Fix incorrect compilation of expressions when escape_html=true [#930](https://github.com/smarty-php/smarty/pull/930)
|
|
||||||
|
|
||||||
## [5.0.0-rc2] - 2023-11-11
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Registered output filters wouldn't run [#899](https://github.com/smarty-php/smarty/issues/899)
|
|
||||||
- Use of negative numbers in {math} equations [#895](https://github.com/smarty-php/smarty/issues/895)
|
|
||||||
- Do not auto-html-escape custom function results [#906](https://github.com/smarty-php/smarty/issues/906)
|
|
||||||
- Fix case-sensitive tag names [#907](https://github.com/smarty-php/smarty/issues/907)
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
- Removed `$smarty->registered_filters` array
|
|
||||||
|
|
||||||
## [5.0.0-rc1] - 2023-08-08
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Added support for PHP8.2
|
|
||||||
- Added a new way to extend Smarty functionality using `Smarty::addExtension()` or `Smarty::setExtensions()`. Please see the docs for more information.
|
|
||||||
- Custom tags can accept positional parameters, so you can write a block compiler that support this: `{trans "Jack" "dull boy"}All work and no play makes %s a %s.{/trans}` [#164](https://github.com/smarty-php/smarty/issues/164)
|
|
||||||
- Full support for ternary operator: `{$test ? $a : $b}` and `{$var ?: $value_if_falsy}` [#881](https://github.com/smarty-php/smarty/issues/881)
|
|
||||||
- Full support for null coalescing operator: `{$var ?? $value_if_null}` [#882](https://github.com/smarty-php/smarty/issues/882)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- All Smarty code is now in the \Smarty namespace. For simple use-cases, you only need to add
|
|
||||||
`use \Smarty\Smarty;` to your script and everything will work. If you extend Smarty or use
|
|
||||||
Smarty plug-ins, please review your code to see if they assume specific class or method names.
|
|
||||||
E.g.: `Smarty_Internal_Template` is now `\Smarty\Template\`, `SmartyException` is now `\Smarty\Exception`.
|
|
||||||
- Template variable scope bubbling has been simplified and made more consistent.
|
|
||||||
The global scope now equals the Smarty scope in order to avoid global state side effects. Please read
|
|
||||||
the documentation for more details.
|
|
||||||
- Lexers and Parsers PHP files are reliably generated from sources (.y and .plex) using the make file
|
|
||||||
- Smarty now always runs in multibyte mode, using `symfony/polyfill-mbstring` if required. Please use the
|
|
||||||
multibyte extension for optimal performance.
|
|
||||||
- Smarty no longer calls `mb_internal_encoding()` and doesn't check for deprecated `mbstring.func_overload` ini directive [#480](https://github.com/smarty-php/smarty/issues/480)
|
|
||||||
- Generated `<script>` tags lo longer have deprecated `type="text/javascript"` or `language="Javascript"` attributes [#815](https://github.com/smarty-php/smarty/issues/815)
|
|
||||||
- Smarty will throw a compiler exception instead of silently ignoring a modifier on a function call, like this: `{include|dot:"x-template-id" file="included.dot.tpl"}` [#526](https://github.com/smarty-php/smarty/issues/526)
|
|
||||||
- The documentation was largely rewritten
|
|
||||||
|
|
||||||
### Deprecated
|
|
||||||
- `$smarty->getPluginsDir()`
|
|
||||||
- `$smarty->loadFilter()`
|
|
||||||
- `$smarty->setPluginsDir()`
|
|
||||||
- `$smarty->assignGlobal()`
|
|
||||||
- Using `$smarty->registerFilter()` for registering variable filters will trigger a notice.
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
- Dropped support for PHP7.1
|
|
||||||
- Removed `$smarty->left_delimiter` and `$smarty->right_delimiter`, use `$smarty->getLeftDelimiter()`/`$smarty->setLeftDelimiter()` and `$smarty->getRightDelimiter()`/`$smarty->setRightDelimiter()`
|
|
||||||
- Removed support for the `$cache_attrs` parameter for registered plugins
|
|
||||||
- Removed support for undocumented `{make_nocache}` tag
|
|
||||||
- Removed support for deprecated `{insert}` tag, the 'insert' plugin type and the associated $smarty->trusted_dir variable
|
|
||||||
- Removed the undocumented `{block_parent}` and `{parent}` alternatives to `{$smarty.block.parent}`
|
|
||||||
- Removed the undocumented `{block_child}` and `{child}` alternatives to `{$smarty.block.child}`
|
|
||||||
- Removed support for loading config files into a non-local scope using `{config_load}` from a template
|
|
||||||
- Removed `$smarty->autoload_filters` in favor of `$smarty->registerFilter()`
|
|
||||||
- Removed `$smarty->trusted_dir` and `$smarty->allow_php_templates` since support for executing php scripts from templates has been dropped
|
|
||||||
- Removed `$smarty->php_functions` and `$smarty->php_modifiers`.
|
|
||||||
- You can no longer use native PHP-functions or userland functions in your templates without registering them. If you need a function in your templates,
|
|
||||||
register it first.
|
|
||||||
- Removed support for `$smarty->getTags()`
|
|
||||||
- Removed the abandoned `$smarty->direct_access_security` setting
|
|
||||||
- Dropped support for `$smarty->plugins_dir` and `$smarty->use_include_path`. If you must, use `$smarty->addPluginsDir()` instead,
|
|
||||||
but it's better to use Smarty::addExtension() to add an extension or Smarty::registerPlugin to
|
|
||||||
quickly register a plugin using a callback function.
|
|
||||||
- Removed constants such as SMARTY_DIR to prevent global side effects.
|
|
||||||
- Removed direct access to `$smarty->template_dir`. Use `$smarty->setTemplateDir()`.
|
|
||||||
- Removed direct access to `$smarty->cache_dir`. Use `$smarty->setCacheDir()`.
|
|
||||||
- Removed direct access to `$smarty->compile_dir`. Use `$smarty->setCompileDir()`.
|
|
||||||
- Removed `$smarty->loadPlugin()`, use `$smarty->registerPlugin()` instead.
|
|
||||||
- Removed `$smarty->appendByRef()` and `$smarty->assignByRef()`.
|
|
||||||
- Removed `$smarty->_current_file`
|
|
||||||
- Removed `$smarty->allow_ambiguous_resources` (ambiguous resources handlers should still work)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- `|strip_tags` does not work if the input is 0 [#890](https://github.com/smarty-php/smarty/issues/890)
|
|
||||||
|
|
||||||
## [4.3.2] - 2023-07-19
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- `$smarty->muteUndefinedOrNullWarnings()` now also mutes PHP8 warnings for undefined properties
|
|
||||||
|
|
||||||
## [4.3.1] - 2023-03-28
|
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
- Fixed Cross site scripting vulnerability in Javascript escaping. This addresses CVE-2023-28447.
|
- Fixed Cross site scripting vulnerability in Javascript escaping. This addresses CVE-2023-28447.
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- `$smarty->muteUndefinedOrNullWarnings()` now also mutes PHP7 notices for undefined array indexes [#736](https://github.com/smarty-php/smarty/issues/736)
|
|
||||||
- `$smarty->muteUndefinedOrNullWarnings()` now treats undefined vars and array access of a null or false variables
|
|
||||||
equivalent across all supported PHP versions
|
|
||||||
- `$smarty->muteUndefinedOrNullWarnings()` now allows dereferencing of non-objects across all supported PHP versions [#831](https://github.com/smarty-php/smarty/issues/831)
|
|
||||||
- PHP 8.1 deprecation warnings on null strings in modifiers [#834](https://github.com/smarty-php/smarty/pull/834)
|
|
||||||
|
|
||||||
## [4.3.0] - 2022-11-22
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- PHP8.2 compatibility [#775](https://github.com/smarty-php/smarty/pull/775)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Include docs and demo in the releases [#799](https://github.com/smarty-php/smarty/issues/799)
|
|
||||||
- Using PHP functions as modifiers now triggers a deprecation notice because we will drop support for this in the next major release [#813](https://github.com/smarty-php/smarty/issues/813)
|
|
||||||
- Dropped remaining references to removed PHP-support in Smarty 4 from docs, lexer and security class. [#816](https://github.com/smarty-php/smarty/issues/816)
|
|
||||||
- Support umask when writing (template) files and set dir permissions to 777 [#548](https://github.com/smarty-php/smarty/issues/548) [#819](https://github.com/smarty-php/smarty/issues/819)
|
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Output buffer is now cleaned for internal PHP errors as well, not just for Exceptions [#514](https://github.com/smarty-php/smarty/issues/514)
|
- Output buffer is now cleaned for internal PHP errors as well, not just for Exceptions [#514](https://github.com/smarty-php/smarty/issues/514)
|
||||||
- Fixed recursion and out of memory errors when caching in complicated template set-ups using inheritance and includes [#801](https://github.com/smarty-php/smarty/pull/801)
|
|
||||||
- Fixed PHP8.1 deprecation errors in strip_tags
|
|
||||||
- Fix Variable Usage in Exception message when unable to load subtemplate [#808](https://github.com/smarty-php/smarty/pull/808)
|
|
||||||
- Fixed PHP8.1 deprecation notices for strftime [#672](https://github.com/smarty-php/smarty/issues/672)
|
|
||||||
- Fixed PHP8.1 deprecation errors passing null to parameter in trim [#807](https://github.com/smarty-php/smarty/pull/807)
|
|
||||||
- Adapt Smarty upper/lower functions to be codesafe (e.g. for Turkish locale) [#586](https://github.com/smarty-php/smarty/pull/586)
|
|
||||||
- Bug fix for underscore and limited length in template name in custom resources [#581](https://github.com/smarty-php/smarty/pull/581)
|
|
||||||
|
|
||||||
## [4.2.1] - 2022-09-14
|
## [3.1.47] - 2022-09-14
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
- Applied appropriate javascript and html escaping in mailto plugin to counter injection attacks [#454](https://github.com/smarty-php/smarty/issues/454)
|
- Applied appropriate javascript and html escaping in mailto plugin to counter injection attacks [#454](https://github.com/smarty-php/smarty/issues/454)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed PHP8.1 deprecation notices in modifiers (upper, explode, number_format and replace) [#755](https://github.com/smarty-php/smarty/pull/755) and [#788](https://github.com/smarty-php/smarty/pull/788)
|
|
||||||
- Fixed PHP8.1 deprecation notices in capitalize modifier [#789](https://github.com/smarty-php/smarty/issues/789)
|
|
||||||
- Fixed use of `rand()` without a parameter in math function [#794](https://github.com/smarty-php/smarty/issues/794)
|
- Fixed use of `rand()` without a parameter in math function [#794](https://github.com/smarty-php/smarty/issues/794)
|
||||||
- Fixed unselected year/month/day not working in html_select_date [#395](https://github.com/smarty-php/smarty/issues/395)
|
- Fixed unselected year/month/day not working in html_select_date [#395](https://github.com/smarty-php/smarty/issues/395)
|
||||||
|
- Updated requirement contraint for 'php' in composer.json to correctly reflect that Smarty3 does not support PHP8. Please upgrade to Smarty4 to use PHP8.
|
||||||
|
|
||||||
## [4.2.0] - 2022-08-01
|
## [3.1.46] - 2022-08-01
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed problems with smarty_mb_str_replace [#549](https://github.com/smarty-php/smarty/issues/549)
|
- Fixed problems with smarty_mb_str_replace [#549](https://github.com/smarty-php/smarty/issues/549)
|
||||||
- Fixed second parameter of unescape modifier not working [#777](https://github.com/smarty-php/smarty/issues/777)
|
- Fixed second parameter of unescape modifier not working [#777](https://github.com/smarty-php/smarty/issues/777)
|
||||||
|
|
||||||
### Changed
|
## [3.1.45] - 2022-05-17
|
||||||
- Updated HTML of the debug template [#599](https://github.com/smarty-php/smarty/pull/599)
|
|
||||||
|
|
||||||
## [4.1.1] - 2022-05-17
|
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
- Prevent PHP injection through malicious block name or include file name. This addresses CVE-2022-29221
|
- Prevent PHP injection through malicious block name or include file name. This addresses CVE-2022-29221
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Exclude docs and demo from export and composer [#751](https://github.com/smarty-php/smarty/pull/751)
|
|
||||||
- PHP 8.1 deprecation notices in demo/plugins/cacheresource.pdo.php [#706](https://github.com/smarty-php/smarty/issues/706)
|
|
||||||
- PHP 8.1 deprecation notices in truncate modifier [#699](https://github.com/smarty-php/smarty/issues/699)
|
|
||||||
- Math equation `max(x, y)` didn't work anymore [#721](https://github.com/smarty-php/smarty/issues/721)
|
- Math equation `max(x, y)` didn't work anymore [#721](https://github.com/smarty-php/smarty/issues/721)
|
||||||
- Fix PHP 8.1 deprecated warning when calling rtrim [#743](https://github.com/smarty-php/smarty/pull/743)
|
|
||||||
- PHP 8.1: fix deprecation in escape modifier [#727](https://github.com/smarty-php/smarty/pull/727)
|
|
||||||
|
|
||||||
## [4.1.0] - 2022-02-06
|
## [3.1.44] - 2022-01-18
|
||||||
|
|
||||||
### Added
|
|
||||||
- PHP8.1 compatibility [#713](https://github.com/smarty-php/smarty/pull/713)
|
|
||||||
|
|
||||||
## [4.0.4] - 2022-01-18
|
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed illegal characters bug in math function security check [#702](https://github.com/smarty-php/smarty/issues/702)
|
- Fixed illegal characters bug in math function security check [#702](https://github.com/smarty-php/smarty/issues/702)
|
||||||
|
|
||||||
## [4.0.3] - 2022-01-10
|
## [3.1.43] - 2022-01-10
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
- Prevent evasion of the `static_classes` security policy. This addresses CVE-2021-21408
|
- Prevent evasion of the `static_classes` security policy. This addresses CVE-2021-21408
|
||||||
|
|
||||||
## [4.0.2] - 2022-01-10
|
## [3.1.42] - 2022-01-10
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
- Prevent arbitrary PHP code execution through maliciously crafted expression for the math function. This addresses CVE-2021-29454
|
- Prevent arbitrary PHP code execution through maliciously crafted expression for the math function. This addresses CVE-2021-29454
|
||||||
|
|
||||||
## [4.0.1] - 2022-01-09
|
## [3.1.41] - 2022-01-09
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
- Rewrote the mailto function to not use `eval` when encoding with javascript
|
- Rewrote the mailto function to not use `eval` when encoding with javascript
|
||||||
|
|
||||||
## [4.0.0] - 2021-11-25
|
|
||||||
|
|
||||||
## [4.0.0-rc.0] - 2021-10-13
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- You can now use `$smarty->muteUndefinedOrNullWarnings()` to activate convert warnings about undefined or null template vars to notices when running PHP8
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Switch CI from Travis to Github CI
|
|
||||||
- Updated unit tests to avoid skipped and risky test warnings
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
- Dropped support for PHP7.0 and below, so Smarty now requires PHP >=7.1
|
|
||||||
- Dropped support for php asp tags in templates (removed from php since php7.0)
|
|
||||||
- Dropped deprecated API calls that where only accessible through SmartyBC
|
|
||||||
- Dropped support for {php} and {include_php} tags and embedded PHP in templates. Embedded PHP will now be passed through as is.
|
|
||||||
- Removed all PHP_VERSION_ID and compare_version checks and conditional code blocks that are now no longer required
|
|
||||||
- Dropped deprecated SMARTY_RESOURCE_CHAR_SET and SMARTY_RESOURCE_DATE_FORMAT constants
|
|
||||||
- Dropped deprecated Smarty::muteExpectedErrors and Smarty::unmuteExpectedErrors API methods
|
|
||||||
- Dropped deprecated $smarty->getVariable() method. Use $smarty->getTemplateVars() instead.
|
|
||||||
- $smarty->registerResource() no longer accepts an array of callback functions
|
|
||||||
|
|
||||||
## [3.1.40] - 2021-10-13
|
## [3.1.40] - 2021-10-13
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -1928,7 +1721,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
27.09.2011
|
27.09.2011
|
||||||
- bugfix possible warning "attempt to modify property of non-object" in {section} (issue #34)
|
- bugfix possible warning "attempt to modify property of non-object" in {section} (issue #34)
|
||||||
- added chaining to \Smarty\Data so $smarty->assign('a',1)->assign('b',2); is possible now
|
- added chaining to Smarty_Internal_Data so $smarty->assign('a',1)->assign('b',2); is possible now
|
||||||
- bugfix remove race condition when a custom resource did change timestamp during compilation
|
- bugfix remove race condition when a custom resource did change timestamp during compilation
|
||||||
- bugfix variable property did not work on objects variable in template
|
- bugfix variable property did not work on objects variable in template
|
||||||
- bugfix smarty_make_timestamp() failed to process DateTime objects properly
|
- bugfix smarty_make_timestamp() failed to process DateTime objects properly
|
||||||
|
@ -2263,7 +2056,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- optimize smarty_modified_escape for hex, hexentity, decentity.
|
- optimize smarty_modified_escape for hex, hexentity, decentity.
|
||||||
|
|
||||||
28/12/2010
|
28/12/2010
|
||||||
- changed $tpl_vars, $config_vars and $parent to belong to \Smarty\Data
|
- changed $tpl_vars, $config_vars and $parent to belong to Smarty_Internal_Data
|
||||||
- added Smarty::registerCacheResource() for dynamic cache resource object registration
|
- added Smarty::registerCacheResource() for dynamic cache resource object registration
|
||||||
|
|
||||||
27/12/2010
|
27/12/2010
|
31
src/includes/smarty-3.1.48/COMPOSER_RELEASE_NOTES.txt
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
|
||||||
|
Starting with Smarty 3.1.21 Composer has been configured to load the packages from github.
|
||||||
|
|
||||||
|
*******************************************************************************
|
||||||
|
* *
|
||||||
|
* NOTE: Because of this change you must clear your local composer cache with *
|
||||||
|
* the "composer clearcache" command *
|
||||||
|
* *
|
||||||
|
*******************************************************************************
|
||||||
|
|
||||||
|
To get the latest stable version use
|
||||||
|
"require": {
|
||||||
|
"smarty/smarty": "~3.1"
|
||||||
|
}
|
||||||
|
in your composer.json file.
|
||||||
|
|
||||||
|
To get the trunk version use
|
||||||
|
"require": {
|
||||||
|
"smarty/smarty": "~3.1@dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
The "smarty/smarty" package will start at libs/.... subfolder.
|
||||||
|
|
||||||
|
To retrieve the development and documentation folders add
|
||||||
|
"require-dev": {
|
||||||
|
"smarty/smarty-dev": "~3.1@dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
If you are using (include) the composer generated autoloader.php which is located
|
||||||
|
in the /vendor folder it is no longer needed to require the Smarty.class.php file.
|
91
src/includes/smarty-3.1.48/INHERITANCE_RELEASE_NOTES.txt
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
3.1.3"
|
||||||
|
New tags for inheritance parent and chilD
|
||||||
|
{parent} == {$smarty.block.parent}
|
||||||
|
{child} == {$smarty.block.child}
|
||||||
|
Both tags support the assign attribute like
|
||||||
|
{child assign=foo}
|
||||||
|
|
||||||
|
3.1.31
|
||||||
|
New tags for inheritance parent and child
|
||||||
|
{block_parent} == {$smarty.block.parent}
|
||||||
|
{block_child} == {$smarty.block.child}
|
||||||
|
|
||||||
|
Since 3.1.28 you can mix inheritance by extends resource with the {extends} tag.
|
||||||
|
A template called by extends resource can extend a subtemplate or chain buy the {extends} tag.
|
||||||
|
Since 3.1.31 this feature can be turned off by setting the new Smarty property Smarty::$extends_recursion to false.
|
||||||
|
|
||||||
|
3.1.28
|
||||||
|
Starting with version 3.1.28 template inheritance is no longer a compile time process.
|
||||||
|
All {block} tag parent/child relations are resolved at run time.
|
||||||
|
This does resolve all known existing restrictions (see below).
|
||||||
|
|
||||||
|
The $smarty::$inheritance_merge_compiled_includes property has been removed.
|
||||||
|
Any access to it is ignored.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
|
||||||
|
Any code outside root {block} tags in child templates is now executed but any output will be ignored.
|
||||||
|
|
||||||
|
{extends 'foo.tpl'}
|
||||||
|
{$bar = 'on'} // assigns variable $bar seen in parent templates
|
||||||
|
{block 'buh'}{/block}
|
||||||
|
|
||||||
|
{extends 'foo.tpl'}
|
||||||
|
{$bar} // the output of variable bar is ignored
|
||||||
|
{block 'buh'}{/block}
|
||||||
|
|
||||||
|
{block} tags can be dynamically en/disabled by conditions.
|
||||||
|
|
||||||
|
{block 'root'}
|
||||||
|
{if $foo}
|
||||||
|
{block 'v1'}
|
||||||
|
....
|
||||||
|
{/block}
|
||||||
|
{else}
|
||||||
|
{block 'v1'}
|
||||||
|
....
|
||||||
|
{/block}
|
||||||
|
{/if}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block} tags can have variable names.
|
||||||
|
|
||||||
|
{block $foo}
|
||||||
|
....
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
Starting with 3.1.28 you can mix inheritance by extends resource with the {extends} tag.
|
||||||
|
A template called by extends resource can extend a subtemplate or chain buy the {extends} tag.
|
||||||
|
|
||||||
|
NOTE There is a BC break. If you used the extends resource {extends} tags have been ignored.
|
||||||
|
|
||||||
|
THE FOLLOWING RESTRICTIONS ARE NO LONGER EXISTING:
|
||||||
|
In Smarty 3.1 template inheritance is a compile time process. All the extending of {block} tags
|
||||||
|
is done at compile time and the parent and child templates are compiled in a single compiled template.
|
||||||
|
{include} subtemplate could also {block} tags. Such subtemplate could not compiled by it's own because
|
||||||
|
it could be used in other context where the {block} extended with a different result. For that reasion
|
||||||
|
the compiled code of {include} subtemplates gets also merged in compiled inheritance template.
|
||||||
|
|
||||||
|
Merging the code into a single compile template has some drawbacks.
|
||||||
|
1. You could not use variable file names in {include} Smarty would use the {include} of compilation time.
|
||||||
|
2. You could not use individual compile_id in {include}
|
||||||
|
3. Separate caching of subtemplate was not possible
|
||||||
|
4. Any change of the template directory structure between calls was not necessarily seen.
|
||||||
|
|
||||||
|
Starting with 3.1.15 some of the above conditions got checked and resulted in an exception. It turned out
|
||||||
|
that a couple of users did use some of above and now got exceptions.
|
||||||
|
|
||||||
|
To resolve this starting with 3.1.16 there is a new configuration parameter $inheritance_merge_compiled_includes.
|
||||||
|
For most backward compatibility its default setting is true.
|
||||||
|
With this setting all {include} subtemplate will be merge into the compiled inheritance template, but the above cases
|
||||||
|
could be rejected by exception.
|
||||||
|
|
||||||
|
|
||||||
|
If $smarty->inheritance_merge_compiled_includes = false; {include} subtemplate will not be merged.You must now manually merge all {include} subtemplate which do contain {block} tags. This is done by setting the "inline" option.
|
||||||
|
{include file='foo.bar' inline}
|
||||||
|
|
||||||
|
1. In case of a variable file name like {include file=$foo inline} you must use the variable in a compile_id $smarty->compile_id = $foo;
|
||||||
|
2. If you use individual compile_id in {include file='foo.tpl' compile_id=$bar inline} it must be used in the global compile_id as well $smarty->compile_id = $bar;
|
||||||
|
3. If call templates with different template_dir configurations and a parent could same named child template from different folders
|
||||||
|
you must make the folder name part of the compile_id.
|
||||||
|
|
291
src/includes/smarty-3.1.48/NEW_FEATURES.txt
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
|
||||||
|
|
||||||
|
This file contains a brief description of new features which have been added to Smarty 3.1
|
||||||
|
|
||||||
|
Smarty 3.1.33-dev
|
||||||
|
Variable capture name in Smarty special variable
|
||||||
|
================================================
|
||||||
|
{$smarty.capture.$foo} can now be used to access the content of a named
|
||||||
|
capture block
|
||||||
|
|
||||||
|
Smarty 3.1.32
|
||||||
|
New tags for inheritance parent and child
|
||||||
|
=========================================
|
||||||
|
{parent} == {$smarty.block.parent}
|
||||||
|
{child} == {$smarty.block.child}
|
||||||
|
Both tags support the assign attribute like
|
||||||
|
{child assign=foo}
|
||||||
|
|
||||||
|
Deprecate functions Smarty::muteExpectedErrors() and Smarty::unmuteExpectedErrors()
|
||||||
|
===================================================================================
|
||||||
|
These functions to start a special error handler are no longer needed as Smarty does
|
||||||
|
no longer use error suppression like @filemtime().
|
||||||
|
For backward compatibility the functions still can be called.
|
||||||
|
|
||||||
|
Using literals containing Smarty's left and right delimiter
|
||||||
|
===========================================================
|
||||||
|
New Methods
|
||||||
|
$smarty->setLiterals(array $literals)
|
||||||
|
$smarty->addLiterals(array $literals)
|
||||||
|
to define literals containing Smarty delimiter. This can avoid the need for extreme usage
|
||||||
|
of {literal} {/literal} tags.
|
||||||
|
A) Treat '{{' and '}}' as literal
|
||||||
|
If Smarty::$auto_literal is enabled
|
||||||
|
{{ foo }}
|
||||||
|
will be treated now as literal. (This does apply for any number of delimiter repeatations).
|
||||||
|
However {{foo}} is not an literal but will be interpreted as a recursive Smarty tag.
|
||||||
|
If you use
|
||||||
|
$smarty->setLiterals(array('{{','}}'));
|
||||||
|
{{foo}} is now a literal as well.
|
||||||
|
NOTE: In the last example nested Smarty tags starting with '{{' or ending with '}}' will not
|
||||||
|
work any longer, but this should be very very raw occouring restriction.
|
||||||
|
B) Example 2
|
||||||
|
Assume your delimiter are '<-' , '->' and '<--' , '-->' shall be literals
|
||||||
|
$smarty->setLiterals(array('<--','-->'));
|
||||||
|
|
||||||
|
|
||||||
|
The capture buffers can now be accessed as array
|
||||||
|
================================================
|
||||||
|
{capture name='foo'}
|
||||||
|
bah
|
||||||
|
{\capture}
|
||||||
|
{capture name='buh'}
|
||||||
|
blar
|
||||||
|
{\capture}
|
||||||
|
{foreach $smarty.capture as $name => $buffer}
|
||||||
|
....
|
||||||
|
{/foreach}
|
||||||
|
|
||||||
|
Smarty 3.1.31
|
||||||
|
New tags for inheritance parent and child
|
||||||
|
=========================================
|
||||||
|
{block_parent} == {$smarty.block.parent}
|
||||||
|
{block_child} == {$smarty.block.child}
|
||||||
|
|
||||||
|
Smarty 3.1.30
|
||||||
|
|
||||||
|
Loop optimization {foreach} and {section}
|
||||||
|
=========================================
|
||||||
|
Smarty does optimize the {foreach} and {section} loops by removing code for not needed loop
|
||||||
|
properties.
|
||||||
|
The compiler collects needed properties by scanning the current template for $item@property,
|
||||||
|
$smarty.foreach.name.property and $smarty.section.name.property.
|
||||||
|
The compiler does not know if additional properties will be needed outside the current template scope.
|
||||||
|
Additional properties can be generated by adding them with the property attribute.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
index.tpl
|
||||||
|
{foreach $from as $item properties=[iteration, index]}
|
||||||
|
{include 'sub.tpl'}
|
||||||
|
{$item.total}
|
||||||
|
{/foreach}
|
||||||
|
|
||||||
|
sub.tpl
|
||||||
|
{$item.index} {$item.iteration} {$item.total}
|
||||||
|
|
||||||
|
In above example code for the 'total' property is automatically generated as $item.total is used in
|
||||||
|
index.tpl. Code for 'iteration' and 'index' must be added with properties=[iteration, index].
|
||||||
|
|
||||||
|
New tag {make_nocache}
|
||||||
|
======================
|
||||||
|
Syntax: {make_nocache $foo}
|
||||||
|
|
||||||
|
This tag makes a variable which does exists normally only while rendering the compiled template
|
||||||
|
available in the cached template for use in not cached expressions.
|
||||||
|
|
||||||
|
Expample:
|
||||||
|
{foreach from=$list item=item}
|
||||||
|
<li>{$item.name} {make_nocache $item}{if $current==$item.id} ACTIVE{/if}</li>
|
||||||
|
{/foreach}
|
||||||
|
|
||||||
|
The {foreach} loop is rendered while processing the compiled template, but $current is a nocache
|
||||||
|
variable. Normally the {if $current==$item.id} would fail as the $item variable is unknown in the cached template. {make_nocache $item} does make the current $item value known in thee cached template.
|
||||||
|
|
||||||
|
{make_nocache} is ignored when caching is disabled or the variable does exists as nocache variable.
|
||||||
|
|
||||||
|
NOTE: if the variable value does contain objects these must have the __set_state method implemented.
|
||||||
|
|
||||||
|
|
||||||
|
Scope Attributes
|
||||||
|
================
|
||||||
|
The scope handling has been updated to cover all cases of variable assignments in templates.
|
||||||
|
|
||||||
|
The tags {assign}, {append} direct assignments like {$foo = ...}, {$foo[...]= ...} support
|
||||||
|
the following optional scope attributes:
|
||||||
|
scope='parent' - the variable will be assigned in the current template and if the template
|
||||||
|
was included by {include} the calling template
|
||||||
|
scope='tpl_root' - the variable will be assigned in the outermost root template called by $smarty->display()
|
||||||
|
or $smarty->fetch() and is bubbled up all {include} sub-templates to the current template.
|
||||||
|
scope='smarty' - the variable will be assigned in the Smarty object and is bubbled up all {include} sub-templates
|
||||||
|
to the current template.
|
||||||
|
scope='global' - the variable will be assigned as Smarty object global variable and is bubbled up all {include}
|
||||||
|
sub-templates to the current template.
|
||||||
|
scope='root' - the variable will be assigned if a data object was used for variable definitions in the data
|
||||||
|
object or in the Smarty object otherwise and is bubbled up all {include} sub-templates to the
|
||||||
|
current template.
|
||||||
|
scope='local' - this scope has only a meaning if the tag is called within a template {function}.
|
||||||
|
The variable will be assigned in the local scope of the template function and the
|
||||||
|
template which did call the template function.
|
||||||
|
|
||||||
|
|
||||||
|
The {config_load} tag supports all of the above except the global scope.
|
||||||
|
|
||||||
|
The scope attribute can be used also with the {include} tag.
|
||||||
|
Supported scope are parent, tpl_root, smarty, global and root.
|
||||||
|
A scope used together with the {include} tag will cause that with some exceptions any variable
|
||||||
|
assignment within that sub-template will update/assign the variable in other scopes according
|
||||||
|
to the above rules. It does include also variables assigned by plugins, tags supporting the assign=foo attribute and direct assignments in {if} and {while} like {if $foo=$bar}.
|
||||||
|
Excluded are the key and value variables of {foreach}, {for} loop variables , variables passed by attributes
|
||||||
|
in {include} and direct increments/decrements like {$foo++}, {$foo--}
|
||||||
|
|
||||||
|
Note: The scopes should be used only to the extend really need. If a variable value assigned in an included
|
||||||
|
sub-template should be returned to the calling sub-template just use {$foo='bar' scope='parent'}.
|
||||||
|
Use scopes only with variables for which it's realy needed. Avoid general scope settings with the
|
||||||
|
{include} tag as it can have a performance impact.
|
||||||
|
|
||||||
|
The {assign}, {append}, {config_load} and {$foo...=...} tags have a new option flag 'noscope'.Thi
|
||||||
|
Example: {$foo='bar' noscope} This will assign $foo only in the current template and any scope settings
|
||||||
|
at {include} is ignored.
|
||||||
|
|
||||||
|
|
||||||
|
Caching
|
||||||
|
=======
|
||||||
|
Caching does now observe the template_dir setting and will create separate cache files if required
|
||||||
|
|
||||||
|
Compiled Templates
|
||||||
|
==================
|
||||||
|
The template_dir setting is now encoded in the uid of the file name.
|
||||||
|
The content of the compiled template may depend on the template_dir search order
|
||||||
|
{include .... inline} is used or $smarty->merge_compiled_includes is enabled
|
||||||
|
|
||||||
|
APC
|
||||||
|
===
|
||||||
|
If APC is enabled force an apc_compile_file() when compiled or cached template was updated
|
||||||
|
|
||||||
|
Smarty 3.1.28
|
||||||
|
|
||||||
|
OPCACHE
|
||||||
|
=======
|
||||||
|
Smarty does now invalidate automatically updated and cleared compiled or cached template files in OPCACHE.
|
||||||
|
Correct operation is no longer dependent on OPCACHE configuration settings.
|
||||||
|
|
||||||
|
Template inheritance
|
||||||
|
====================
|
||||||
|
Template inheritance is now processed in run time.
|
||||||
|
See the INHERITANCE_RELEASE_NOTES
|
||||||
|
|
||||||
|
Modifier regex_replace
|
||||||
|
======================
|
||||||
|
An optional limit parameter was added
|
||||||
|
|
||||||
|
fetch() and display()
|
||||||
|
=====================
|
||||||
|
The fetch() and display() methods of the template object accept now optionally the same parameter
|
||||||
|
as the corresponding Smarty methods to get the content of another template.
|
||||||
|
Example:
|
||||||
|
$template->display(); Does display template of template object
|
||||||
|
$template->display('foo.tpl'); Does display template 'foo.bar'
|
||||||
|
|
||||||
|
File: resource
|
||||||
|
==============
|
||||||
|
Multiple template_dir entries can now be selected by a comma separated list of indices.
|
||||||
|
The template_dir array is searched in the order of the indices. (Could be used to change the default search order)
|
||||||
|
Example:
|
||||||
|
$smarty->display('[1],[0]foo.bar');
|
||||||
|
|
||||||
|
Filter support
|
||||||
|
==============
|
||||||
|
Optional filter names
|
||||||
|
An optional filter name was added to $smarty->registerFilter(). It can be used to unregister a filter by name.
|
||||||
|
- $smarty->registerFilter('output', $callback, 'name');
|
||||||
|
$smarty->unregister('output', 'name');
|
||||||
|
|
||||||
|
Closures
|
||||||
|
$smarty->registerFilter() does now accept closures.
|
||||||
|
- $smarty->registerFilter('pre', function($source) {return $source;});
|
||||||
|
If no optional filter name was specified it gets the default name 'closure'.
|
||||||
|
If you register multiple closures register each with a unique filter name.
|
||||||
|
- $smarty->registerFilter('pre', function($source) {return $source;}, 'closure_1');
|
||||||
|
- $smarty->registerFilter('pre', function($source) {return $source;}, 'closure_2');
|
||||||
|
|
||||||
|
|
||||||
|
Smarty 3.1.22
|
||||||
|
|
||||||
|
Namespace support within templates
|
||||||
|
==================================
|
||||||
|
Within templates you can now use namespace specifications on:
|
||||||
|
- Constants like foo\bar\FOO
|
||||||
|
- Class names like foo\bar\Baz::FOO, foo\bar\Baz::$foo, foo\bar\Baz::foo()
|
||||||
|
- PHP function names like foo\bar\baz()
|
||||||
|
|
||||||
|
Security
|
||||||
|
========
|
||||||
|
- disable special $smarty variable -
|
||||||
|
The Smarty_Security class has the new property $disabled_special_smarty_vars.
|
||||||
|
It's an array which can be loaded with the $smarty special variable names like
|
||||||
|
'template_object', 'template', 'current_dir' and others which will be disabled.
|
||||||
|
Note: That this security check is performed at compile time.
|
||||||
|
|
||||||
|
- limit template nesting -
|
||||||
|
Property $max_template_nesting of Smarty_Security does set the maximum template nesting level.
|
||||||
|
The main template is level 1. The nesting level is checked at run time. When the maximum will be exceeded
|
||||||
|
an Exception will be thrown. The default setting is 0 which does disable this check.
|
||||||
|
|
||||||
|
- trusted static methods -
|
||||||
|
The Smarty_Security class has the new property $trusted_static_methods to restrict access to static methods.
|
||||||
|
It's an nested array of trusted class and method names.
|
||||||
|
Format:
|
||||||
|
array (
|
||||||
|
'class_1' => array('method_1', 'method_2'), // allowed methods
|
||||||
|
'class_2' => array(), // all methods of class allowed
|
||||||
|
)
|
||||||
|
To disable access for all methods of all classes set $trusted_static_methods = null;
|
||||||
|
The default value is an empty array() which does enables all methods of all classes, but for backward compatibility
|
||||||
|
the setting of $static_classes will be checked.
|
||||||
|
Note: That this security check is performed at compile time.
|
||||||
|
|
||||||
|
- trusted static properties -
|
||||||
|
The Smarty_Security class has the new property $trusted_static_properties to restrict access to static properties.
|
||||||
|
It's an nested array of trusted class and property names.
|
||||||
|
Format:
|
||||||
|
array (
|
||||||
|
'class_1' => array('prop_1', 'prop_2'), // allowed properties listed
|
||||||
|
'class_2' => array(), // all properties of class allowed
|
||||||
|
}
|
||||||
|
To disable access for all properties of all classes set $trusted_static_properties = null;
|
||||||
|
The default value is an empty array() which does enables all properties of all classes, but for backward compatibility
|
||||||
|
the setting of $static_classes will be checked.
|
||||||
|
Note: That this security check is performed at compile time.
|
||||||
|
|
||||||
|
- trusted constants .
|
||||||
|
The Smarty_Security class has the new property $trusted_constants to restrict access to constants.
|
||||||
|
It's an array of trusted constant names.
|
||||||
|
Format:
|
||||||
|
array (
|
||||||
|
'SMARTY_DIR' , // allowed constant
|
||||||
|
}
|
||||||
|
If the array is empty (default) the usage of constants can be controlled with the
|
||||||
|
Smarty_Security::$allow_constants property (default true)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Compiled Templates
|
||||||
|
==================
|
||||||
|
Smarty does now automatically detects a change of the $merge_compiled_includes and $escape_html
|
||||||
|
property and creates different compiled templates files depending on the setting.
|
||||||
|
|
||||||
|
Same applies to config files and the $config_overwrite, $config_booleanize and
|
||||||
|
$config_read_hidden properties.
|
||||||
|
|
||||||
|
Debugging
|
||||||
|
=========
|
||||||
|
The layout of the debug window has been changed for better readability
|
||||||
|
|
||||||
|
New class constants
|
||||||
|
Smarty::DEBUG_OFF
|
||||||
|
Smarty::DEBUG_ON
|
||||||
|
Smarty::DEBUG_INDIVIDUAL
|
||||||
|
have been introduced for setting the $debugging property.
|
||||||
|
|
||||||
|
Smarty::DEBUG_INDIVIDUAL will create for each display() and fetch() call an individual debug window.
|
||||||
|
|
575
src/includes/smarty-3.1.48/README
Normal file
|
@ -0,0 +1,575 @@
|
||||||
|
Smarty 3.x
|
||||||
|
|
||||||
|
Author: Monte Ohrt <monte at ohrt dot com >
|
||||||
|
Author: Uwe Tews
|
||||||
|
|
||||||
|
AN INTRODUCTION TO SMARTY 3
|
||||||
|
|
||||||
|
NOTICE FOR 3.1 release:
|
||||||
|
|
||||||
|
Please see the SMARTY_3.1_NOTES.txt file that comes with the distribution.
|
||||||
|
|
||||||
|
NOTICE for 3.0.5 release:
|
||||||
|
|
||||||
|
Smarty now follows the PHP error_reporting level by default. If PHP does not mask E_NOTICE and you try to access an unset template variable, you will now get an E_NOTICE warning. To revert to the old behavior:
|
||||||
|
|
||||||
|
$smarty->error_reporting = E_ALL & ~E_NOTICE;
|
||||||
|
|
||||||
|
NOTICE for 3.0 release:
|
||||||
|
|
||||||
|
IMPORTANT: Some API adjustments have been made between the RC4 and 3.0 release.
|
||||||
|
We felt it is better to make these now instead of after a 3.0 release, then have to
|
||||||
|
immediately deprecate APIs in 3.1. Online documentation has been updated
|
||||||
|
to reflect these changes. Specifically:
|
||||||
|
|
||||||
|
---- API CHANGES RC4 -> 3.0 ----
|
||||||
|
|
||||||
|
$smarty->register->*
|
||||||
|
$smarty->unregister->*
|
||||||
|
$smarty->utility->*
|
||||||
|
$samrty->cache->*
|
||||||
|
|
||||||
|
Have all been changed to local method calls such as:
|
||||||
|
|
||||||
|
$smarty->clearAllCache()
|
||||||
|
$smarty->registerFoo()
|
||||||
|
$smarty->unregisterFoo()
|
||||||
|
$smarty->testInstall()
|
||||||
|
etc.
|
||||||
|
|
||||||
|
Registration of function, block, compiler, and modifier plugins have been
|
||||||
|
consolidated under two API calls:
|
||||||
|
|
||||||
|
$smarty->registerPlugin(...)
|
||||||
|
$smarty->unregisterPlugin(...)
|
||||||
|
|
||||||
|
Registration of pre, post, output and variable filters have been
|
||||||
|
consolidated under two API calls:
|
||||||
|
|
||||||
|
$smarty->registerFilter(...)
|
||||||
|
$smarty->unregisterFilter(...)
|
||||||
|
|
||||||
|
Please refer to the online documentation for all specific changes:
|
||||||
|
|
||||||
|
http://www.smarty.net/documentation
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
The Smarty 3 API has been refactored to a syntax geared
|
||||||
|
for consistency and modularity. The Smarty 2 API syntax is still supported, but
|
||||||
|
will throw a deprecation notice. You can disable the notices, but it is highly
|
||||||
|
recommended to adjust your syntax to Smarty 3, as the Smarty 2 syntax must run
|
||||||
|
through an extra rerouting wrapper.
|
||||||
|
|
||||||
|
Basically, all Smarty methods now follow the "fooBarBaz" camel case syntax. Also,
|
||||||
|
all Smarty properties now have getters and setters. So for example, the property
|
||||||
|
$smarty->cache_dir can be set with $smarty->setCacheDir('foo/') and can be
|
||||||
|
retrieved with $smarty->getCacheDir().
|
||||||
|
|
||||||
|
Some of the Smarty 3 APIs have been revoked such as the "is*" methods that were
|
||||||
|
just duplicate functions of the now available "get*" methods.
|
||||||
|
|
||||||
|
Here is a rundown of the Smarty 3 API:
|
||||||
|
|
||||||
|
$smarty->fetch($template, $cache_id = null, $compile_id = null, $parent = null)
|
||||||
|
$smarty->display($template, $cache_id = null, $compile_id = null, $parent = null)
|
||||||
|
$smarty->isCached($template, $cache_id = null, $compile_id = null)
|
||||||
|
$smarty->createData($parent = null)
|
||||||
|
$smarty->createTemplate($template, $cache_id = null, $compile_id = null, $parent = null)
|
||||||
|
$smarty->enableSecurity()
|
||||||
|
$smarty->disableSecurity()
|
||||||
|
$smarty->setTemplateDir($template_dir)
|
||||||
|
$smarty->addTemplateDir($template_dir)
|
||||||
|
$smarty->templateExists($resource_name)
|
||||||
|
$smarty->loadPlugin($plugin_name, $check = true)
|
||||||
|
$smarty->loadFilter($type, $name)
|
||||||
|
$smarty->setExceptionHandler($handler)
|
||||||
|
$smarty->addPluginsDir($plugins_dir)
|
||||||
|
$smarty->getGlobal($varname = null)
|
||||||
|
$smarty->getRegisteredObject($name)
|
||||||
|
$smarty->getDebugTemplate()
|
||||||
|
$smarty->setDebugTemplate($tpl_name)
|
||||||
|
$smarty->assign($tpl_var, $value = null, $nocache = false)
|
||||||
|
$smarty->assignGlobal($varname, $value = null, $nocache = false)
|
||||||
|
$smarty->assignByRef($tpl_var, &$value, $nocache = false)
|
||||||
|
$smarty->append($tpl_var, $value = null, $merge = false, $nocache = false)
|
||||||
|
$smarty->appendByRef($tpl_var, &$value, $merge = false)
|
||||||
|
$smarty->clearAssign($tpl_var)
|
||||||
|
$smarty->clearAllAssign()
|
||||||
|
$smarty->configLoad($config_file, $sections = null)
|
||||||
|
$smarty->getVariable($variable, $_ptr = null, $search_parents = true, $error_enable = true)
|
||||||
|
$smarty->getConfigVariable($variable)
|
||||||
|
$smarty->getStreamVariable($variable)
|
||||||
|
$smarty->getConfigVars($varname = null)
|
||||||
|
$smarty->clearConfig($varname = null)
|
||||||
|
$smarty->getTemplateVars($varname = null, $_ptr = null, $search_parents = true)
|
||||||
|
$smarty->clearAllCache($exp_time = null, $type = null)
|
||||||
|
$smarty->clearCache($template_name, $cache_id = null, $compile_id = null, $exp_time = null, $type = null)
|
||||||
|
|
||||||
|
$smarty->registerPlugin($type, $tag, $callback, $cacheable = true, $cache_attr = array())
|
||||||
|
|
||||||
|
$smarty->registerObject($object_name, $object_impl, $allowed = array(), $smarty_args = true, $block_methods = array())
|
||||||
|
|
||||||
|
$smarty->registerFilter($type, $function_name)
|
||||||
|
$smarty->registerResource($resource_type, $function_names)
|
||||||
|
$smarty->registerDefaultPluginHandler($function_name)
|
||||||
|
$smarty->registerDefaultTemplateHandler($function_name)
|
||||||
|
|
||||||
|
$smarty->unregisterPlugin($type, $tag)
|
||||||
|
$smarty->unregisterObject($object_name)
|
||||||
|
$smarty->unregisterFilter($type, $function_name)
|
||||||
|
$smarty->unregisterResource($resource_type)
|
||||||
|
|
||||||
|
$smarty->compileAllTemplates($extension = '.tpl', $force_compile = false, $time_limit = 0, $max_errors = null)
|
||||||
|
$smarty->clearCompiledTemplate($resource_name = null, $compile_id = null, $exp_time = null)
|
||||||
|
$smarty->testInstall()
|
||||||
|
|
||||||
|
// then all the getters/setters, available for all properties. Here are a few:
|
||||||
|
|
||||||
|
$caching = $smarty->getCaching(); // get $smarty->caching
|
||||||
|
$smarty->setCaching(true); // set $smarty->caching
|
||||||
|
$smarty->setDeprecationNotices(false); // set $smarty->deprecation_notices
|
||||||
|
$smarty->setCacheId($id); // set $smarty->cache_id
|
||||||
|
$debugging = $smarty->getDebugging(); // get $smarty->debugging
|
||||||
|
|
||||||
|
|
||||||
|
FILE STRUCTURE
|
||||||
|
|
||||||
|
The Smarty 3 file structure is similar to Smarty 2:
|
||||||
|
|
||||||
|
/libs/
|
||||||
|
Smarty.class.php
|
||||||
|
/libs/sysplugins/
|
||||||
|
internal.*
|
||||||
|
/libs/plugins/
|
||||||
|
function.mailto.php
|
||||||
|
modifier.escape.php
|
||||||
|
...
|
||||||
|
|
||||||
|
A lot of Smarty 3 core functionality lies in the sysplugins directory; you do
|
||||||
|
not need to change any files here. The /libs/plugins/ folder is where Smarty
|
||||||
|
plugins are located. You can add your own here, or create a separate plugin
|
||||||
|
directory, just the same as Smarty 2. You will still need to create your own
|
||||||
|
/cache/, /templates/, /templates_c/, /configs/ folders. Be sure /cache/ and
|
||||||
|
/templates_c/ are writable.
|
||||||
|
|
||||||
|
The typical way to use Smarty 3 should also look familiar:
|
||||||
|
|
||||||
|
require('Smarty.class.php');
|
||||||
|
$smarty = new Smarty;
|
||||||
|
$smarty->assign('foo','bar');
|
||||||
|
$smarty->display('index.tpl');
|
||||||
|
|
||||||
|
|
||||||
|
However, Smarty 3 works completely different on the inside. Smarty 3 is mostly
|
||||||
|
backward compatible with Smarty 2, except for the following items:
|
||||||
|
|
||||||
|
*) Smarty 3 is PHP 5 only. It will not work with PHP 4.
|
||||||
|
*) The {php} tag is disabled by default. Enable with $smarty->allow_php_tag=true.
|
||||||
|
*) Delimiters surrounded by whitespace are no longer treated as Smarty tags.
|
||||||
|
Therefore, { foo } will not compile as a tag, you must use {foo}. This change
|
||||||
|
Makes Javascript/CSS easier to work with, eliminating the need for {literal}.
|
||||||
|
This can be disabled by setting $smarty->auto_literal = false;
|
||||||
|
*) The Smarty 3 API is a bit different. Many Smarty 2 API calls are deprecated
|
||||||
|
but still work. You will want to update your calls to Smarty 3 for maximum
|
||||||
|
efficiency.
|
||||||
|
|
||||||
|
|
||||||
|
There are many things that are new to Smarty 3. Here are the notable items:
|
||||||
|
|
||||||
|
LEXER/PARSER
|
||||||
|
============
|
||||||
|
|
||||||
|
Smarty 3 now uses a lexing tokenizer for its parser/compiler. Basically, this
|
||||||
|
means Smarty has some syntax additions that make life easier such as in-template
|
||||||
|
math, shorter/intuitive function parameter options, infinite function recursion,
|
||||||
|
more accurate error handling, etc.
|
||||||
|
|
||||||
|
|
||||||
|
WHAT IS NEW IN SMARTY TEMPLATE SYNTAX
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Smarty 3 allows expressions almost anywhere. Expressions can include PHP
|
||||||
|
functions as long as they are not disabled by the security policy, object
|
||||||
|
methods and properties, etc. The {math} plugin is no longer necessary but
|
||||||
|
is still supported for BC.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
{$x+$y} will output the sum of x and y.
|
||||||
|
{$foo = strlen($bar)} function in assignment
|
||||||
|
{assign var=foo value= $x+$y} in attributes
|
||||||
|
{$foo = myfunct( ($x+$y)*3 )} as function parameter
|
||||||
|
{$foo[$x+3]} as array index
|
||||||
|
|
||||||
|
Smarty tags can be used as values within other tags.
|
||||||
|
Example: {$foo={counter}+3}
|
||||||
|
|
||||||
|
Smarty tags can also be used inside double quoted strings.
|
||||||
|
Example: {$foo="this is message {counter}"}
|
||||||
|
|
||||||
|
You can define arrays within templates.
|
||||||
|
Examples:
|
||||||
|
{assign var=foo value=[1,2,3]}
|
||||||
|
{assign var=foo value=['y'=>'yellow','b'=>'blue']}
|
||||||
|
Arrays can be nested.
|
||||||
|
{assign var=foo value=[1,[9,8],3]}
|
||||||
|
|
||||||
|
There is a new short syntax supported for assigning variables.
|
||||||
|
Example: {$foo=$bar+2}
|
||||||
|
|
||||||
|
You can assign a value to a specific array element. If the variable exists but
|
||||||
|
is not an array, it is converted to an array before the new values are assigned.
|
||||||
|
Examples:
|
||||||
|
{$foo['bar']=1}
|
||||||
|
{$foo['bar']['blar']=1}
|
||||||
|
|
||||||
|
You can append values to an array. If the variable exists but is not an array,
|
||||||
|
it is converted to an array before the new values are assigned.
|
||||||
|
Example: {$foo[]=1}
|
||||||
|
|
||||||
|
You can use a PHP-like syntax for accessing array elements, as well as the
|
||||||
|
original "dot" notation.
|
||||||
|
Examples:
|
||||||
|
{$foo[1]} normal access
|
||||||
|
{$foo['bar']}
|
||||||
|
{$foo['bar'][1]}
|
||||||
|
{$foo[$x+$x]} index may contain any expression
|
||||||
|
{$foo[$bar[1]]} nested index
|
||||||
|
{$foo[section_name]} smarty section access, not array access!
|
||||||
|
|
||||||
|
The original "dot" notation stays, and with improvements.
|
||||||
|
Examples:
|
||||||
|
{$foo.a.b.c} => $foo['a']['b']['c']
|
||||||
|
{$foo.a.$b.c} => $foo['a'][$b]['c'] with variable index
|
||||||
|
{$foo.a.{$b+4}.c} => $foo['a'][$b+4]['c'] with expression as index
|
||||||
|
{$foo.a.{$b.c}} => $foo['a'][$b['c']] with nested index
|
||||||
|
|
||||||
|
note that { and } are used to address ambiguties when nesting the dot syntax.
|
||||||
|
|
||||||
|
Variable names themselves can be variable and contain expressions.
|
||||||
|
Examples:
|
||||||
|
$foo normal variable
|
||||||
|
$foo_{$bar} variable name containing other variable
|
||||||
|
$foo_{$x+$y} variable name containing expressions
|
||||||
|
$foo_{$bar}_buh_{$blar} variable name with multiple segments
|
||||||
|
{$foo_{$x}} will output the variable $foo_1 if $x has a value of 1.
|
||||||
|
|
||||||
|
Object method chaining is implemented.
|
||||||
|
Example: {$object->method1($x)->method2($y)}
|
||||||
|
|
||||||
|
{for} tag added for looping (replacement for {section} tag):
|
||||||
|
{for $x=0, $y=count($foo); $x<$y; $x++} .... {/for}
|
||||||
|
Any number of statements can be used separated by comma as the first
|
||||||
|
initial expression at {for}.
|
||||||
|
|
||||||
|
{for $x = $start to $end step $step} ... {/for}is in the SVN now .
|
||||||
|
You can use also
|
||||||
|
{for $x = $start to $end} ... {/for}
|
||||||
|
In this case the step value will be automatically 1 or -1 depending on the start and end values.
|
||||||
|
Instead of $start and $end you can use any valid expression.
|
||||||
|
Inside the loop the following special vars can be accessed:
|
||||||
|
$x@iteration = number of iteration
|
||||||
|
$x@total = total number of iterations
|
||||||
|
$x@first = true on first iteration
|
||||||
|
$x@last = true on last iteration
|
||||||
|
|
||||||
|
|
||||||
|
The Smarty 2 {section} syntax is still supported.
|
||||||
|
|
||||||
|
New shorter {foreach} syntax to loop over an array.
|
||||||
|
Example: {foreach $myarray as $var}...{/foreach}
|
||||||
|
|
||||||
|
Within the foreach loop, properties are access via:
|
||||||
|
|
||||||
|
$var@key foreach $var array key
|
||||||
|
$var@iteration foreach current iteration count (1,2,3...)
|
||||||
|
$var@index foreach current index count (0,1,2...)
|
||||||
|
$var@total foreach $var array total
|
||||||
|
$var@first true on first iteration
|
||||||
|
$var@last true on last iteration
|
||||||
|
|
||||||
|
The Smarty 2 {foreach} tag syntax is still supported.
|
||||||
|
|
||||||
|
NOTE: {$bar[foo]} still indicates a variable inside of a {section} named foo.
|
||||||
|
If you want to access an array element with index foo, you must use quotes
|
||||||
|
such as {$bar['foo']}, or use the dot syntax {$bar.foo}.
|
||||||
|
|
||||||
|
while block tag is now implemented:
|
||||||
|
{while $foo}...{/while}
|
||||||
|
{while $x lt 10}...{/while}
|
||||||
|
|
||||||
|
Direct access to PHP functions:
|
||||||
|
Just as you can use PHP functions as modifiers directly, you can now access
|
||||||
|
PHP functions directly, provided they are permitted by security settings:
|
||||||
|
{time()}
|
||||||
|
|
||||||
|
There is a new {function}...{/function} block tag to implement a template function.
|
||||||
|
This enables reuse of code sequences like a plugin function. It can call itself recursively.
|
||||||
|
Template function must be called with the new {call name=foo...} tag.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
Template file:
|
||||||
|
{function name=menu level=0}
|
||||||
|
<ul class="level{$level}">
|
||||||
|
{foreach $data as $entry}
|
||||||
|
{if is_array($entry)}
|
||||||
|
<li>{$entry@key}</li>
|
||||||
|
{call name=menu data=$entry level=$level+1}
|
||||||
|
{else}
|
||||||
|
<li>{$entry}</li>
|
||||||
|
{/if}
|
||||||
|
{/foreach}
|
||||||
|
</ul>
|
||||||
|
{/function}
|
||||||
|
|
||||||
|
{$menu = ['item1','item2','item3' => ['item3-1','item3-2','item3-3' =>
|
||||||
|
['item3-3-1','item3-3-2']],'item4']}
|
||||||
|
|
||||||
|
{call name=menu data=$menu}
|
||||||
|
|
||||||
|
|
||||||
|
Generated output:
|
||||||
|
* item1
|
||||||
|
* item2
|
||||||
|
* item3
|
||||||
|
o item3-1
|
||||||
|
o item3-2
|
||||||
|
o item3-3
|
||||||
|
+ item3-3-1
|
||||||
|
+ item3-3-2
|
||||||
|
* item4
|
||||||
|
|
||||||
|
The function tag itself must have the "name" attribute. This name is the tag
|
||||||
|
name when calling the function. The function tag may have any number of
|
||||||
|
additional attributes. These will be default settings for local variables.
|
||||||
|
|
||||||
|
New {nocache} block function:
|
||||||
|
{nocache}...{/nocache} will declare a section of the template to be non-cached
|
||||||
|
when template caching is enabled.
|
||||||
|
|
||||||
|
New nocache attribute:
|
||||||
|
You can declare variable/function output as non-cached with the nocache attribute.
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
{$foo nocache=true}
|
||||||
|
{$foo nocache} /* same */
|
||||||
|
|
||||||
|
{foo bar="baz" nocache=true}
|
||||||
|
{foo bar="baz" nocache} /* same */
|
||||||
|
|
||||||
|
{time() nocache=true}
|
||||||
|
{time() nocache} /* same */
|
||||||
|
|
||||||
|
Or you can also assign the variable in your script as nocache:
|
||||||
|
$smarty->assign('foo',$something,true); // third param is nocache setting
|
||||||
|
{$foo} /* non-cached */
|
||||||
|
|
||||||
|
$smarty.current_dir returns the directory name of the current template.
|
||||||
|
|
||||||
|
You can use strings directly as templates with the "string" resource type.
|
||||||
|
Examples:
|
||||||
|
$smarty->display('string:This is my template, {$foo}!'); // php
|
||||||
|
{include file="string:This is my template, {$foo}!"} // template
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
VARIABLE SCOPE / VARIABLE STORAGE
|
||||||
|
=================================
|
||||||
|
|
||||||
|
In Smarty 2, all assigned variables were stored within the Smarty object.
|
||||||
|
Therefore, all variables assigned in PHP were accessible by all subsequent
|
||||||
|
fetch and display template calls.
|
||||||
|
|
||||||
|
In Smarty 3, we have the choice to assign variables to the main Smarty object,
|
||||||
|
to user-created data objects, and to user-created template objects.
|
||||||
|
These objects can be chained. The object at the end of a chain can access all
|
||||||
|
variables belonging to that template and all variables within the parent objects.
|
||||||
|
The Smarty object can only be the root of a chain, but a chain can be isolated
|
||||||
|
from the Smarty object.
|
||||||
|
|
||||||
|
All known Smarty assignment interfaces will work on the data and template objects.
|
||||||
|
|
||||||
|
Besides the above mentioned objects, there is also a special storage area for
|
||||||
|
global variables.
|
||||||
|
|
||||||
|
A Smarty data object can be created as follows:
|
||||||
|
$data = $smarty->createData(); // create root data object
|
||||||
|
$data->assign('foo','bar'); // assign variables as usual
|
||||||
|
$data->config_load('my.conf'); // load config file
|
||||||
|
|
||||||
|
$data= $smarty->createData($smarty); // create data object having a parent link to
|
||||||
|
the Smarty object
|
||||||
|
|
||||||
|
$data2= $smarty->createData($data); // create data object having a parent link to
|
||||||
|
the $data data object
|
||||||
|
|
||||||
|
A template object can be created by using the createTemplate method. It has the
|
||||||
|
same parameter assignments as the fetch() or display() method.
|
||||||
|
Function definition:
|
||||||
|
function createTemplate($template, $cache_id = null, $compile_id = null, $parent = null)
|
||||||
|
|
||||||
|
The first parameter can be a template name, a smarty object or a data object.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
$tpl = $smarty->createTemplate('mytpl.tpl'); // create template object not linked to any parent
|
||||||
|
$tpl->assign('foo','bar'); // directly assign variables
|
||||||
|
$tpl->config_load('my.conf'); // load config file
|
||||||
|
|
||||||
|
$tpl = $smarty->createTemplate('mytpl.tpl',$smarty); // create template having a parent link to the Smarty object
|
||||||
|
$tpl = $smarty->createTemplate('mytpl.tpl',$data); // create template having a parent link to the $data object
|
||||||
|
|
||||||
|
The standard fetch() and display() methods will implicitly create a template object.
|
||||||
|
If the $parent parameter is not specified in these method calls, the template object
|
||||||
|
is will link back to the Smarty object as it's parent.
|
||||||
|
|
||||||
|
If a template is called by an {include...} tag from another template, the
|
||||||
|
subtemplate links back to the calling template as it's parent.
|
||||||
|
|
||||||
|
All variables assigned locally or from a parent template are accessible. If the
|
||||||
|
template creates or modifies a variable by using the {assign var=foo...} or
|
||||||
|
{$foo=...} tags, these new values are only known locally (local scope). When the
|
||||||
|
template exits, none of the new variables or modifications can be seen in the
|
||||||
|
parent template(s). This is same behavior as in Smarty 2.
|
||||||
|
|
||||||
|
With Smarty 3, we can assign variables with a scope attribute which allows the
|
||||||
|
availablility of these new variables or modifications globally (ie in the parent
|
||||||
|
templates.)
|
||||||
|
|
||||||
|
Possible scopes are local, parent, root and global.
|
||||||
|
Examples:
|
||||||
|
{assign var=foo value='bar'} // no scope is specified, the default 'local'
|
||||||
|
{$foo='bar'} // same, local scope
|
||||||
|
{assign var=foo value='bar' scope='local'} // same, local scope
|
||||||
|
|
||||||
|
{assign var=foo value='bar' scope='parent'} // Values will be available to the parent object
|
||||||
|
{$foo='bar' scope='parent'} // (normally the calling template)
|
||||||
|
|
||||||
|
{assign var=foo value='bar' scope='root'} // Values will be exported up to the root object, so they can
|
||||||
|
{$foo='bar' scope='root'} // be seen from all templates using the same root.
|
||||||
|
|
||||||
|
{assign var=foo value='bar' scope='global'} // Values will be exported to global variable storage,
|
||||||
|
{$foo='bar' scope='global'} // they are available to any and all templates.
|
||||||
|
|
||||||
|
|
||||||
|
The scope attribute can also be attached to the {include...} tag. In this case,
|
||||||
|
the specified scope will be the default scope for all assignments within the
|
||||||
|
included template.
|
||||||
|
|
||||||
|
|
||||||
|
PLUGINS
|
||||||
|
=======
|
||||||
|
|
||||||
|
Smarty 3 plugins follow the same coding rules as in Smarty 2.
|
||||||
|
The main difference is that the template object is now passed in place of the smarty object.
|
||||||
|
The smarty object can be still be accessed through $template->smarty.
|
||||||
|
|
||||||
|
smarty_plugintype_name (array $params, Smarty_Internal_Template $template)
|
||||||
|
|
||||||
|
The Smarty 2 plugins are still compatible as long as they do not make use of specific Smarty 2 internals.
|
||||||
|
|
||||||
|
|
||||||
|
TEMPLATE INHERITANCE:
|
||||||
|
=====================
|
||||||
|
|
||||||
|
With template inheritance you can define blocks, which are areas that can be
|
||||||
|
overridden by child templates, so your templates could look like this:
|
||||||
|
|
||||||
|
parent.tpl:
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{block name='title'}My site name{/block}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>{block name='page-title'}Default page title{/block}</h1>
|
||||||
|
<div id="content">
|
||||||
|
{block name='content'}
|
||||||
|
Default content
|
||||||
|
{/block}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
child.tpl:
|
||||||
|
{extends file='parent.tpl'}
|
||||||
|
{block name='title'}
|
||||||
|
Child title
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
grandchild.tpl:
|
||||||
|
{extends file='child.tpl'}
|
||||||
|
{block name='title'}Home - {$smarty.block.parent}{/block}
|
||||||
|
{block name='page-title'}My home{/block}
|
||||||
|
{block name='content'}
|
||||||
|
{foreach $images as $img}
|
||||||
|
<img src="{$img.url}" alt="{$img.description}" />
|
||||||
|
{/foreach}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
We redefined all the blocks here, however in the title block we used {$smarty.block.parent},
|
||||||
|
which tells Smarty to insert the default content from the parent template in its place.
|
||||||
|
The content block was overridden to display the image files, and page-title has also be
|
||||||
|
overridden to display a completely different title.
|
||||||
|
|
||||||
|
If we render grandchild.tpl we will get this:
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Home - Child title</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>My home</h1>
|
||||||
|
<div id="content">
|
||||||
|
<img src="/example.jpg" alt="image" />
|
||||||
|
<img src="/example2.jpg" alt="image" />
|
||||||
|
<img src="/example3.jpg" alt="image" />
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
NOTE: In the child templates everything outside the {extends} or {block} tag sections
|
||||||
|
is ignored.
|
||||||
|
|
||||||
|
The inheritance tree can be as big as you want (meaning you can extend a file that
|
||||||
|
extends another one that extends another one and so on..), but be aware that all files
|
||||||
|
have to be checked for modifications at runtime so the more inheritance the more overhead you add.
|
||||||
|
|
||||||
|
Instead of defining the parent/child relationships with the {extends} tag in the child template you
|
||||||
|
can use the resource as follow:
|
||||||
|
|
||||||
|
$smarty->display('extends:parent.tpl|child.tpl|grandchild.tpl');
|
||||||
|
|
||||||
|
Child {block} tags may optionally have a append or prepend attribute. In this case the parent block content
|
||||||
|
is appended or prepended to the child block content.
|
||||||
|
|
||||||
|
{block name='title' append} My title {/block}
|
||||||
|
|
||||||
|
|
||||||
|
PHP STREAMS:
|
||||||
|
============
|
||||||
|
|
||||||
|
(see online documentation)
|
||||||
|
|
||||||
|
VARIBLE FILTERS:
|
||||||
|
================
|
||||||
|
|
||||||
|
(see online documentation)
|
||||||
|
|
||||||
|
|
||||||
|
STATIC CLASS ACCESS AND NAMESPACE SUPPORT
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
You can register a class with optional namespace for the use in the template like:
|
||||||
|
|
||||||
|
$smarty->register->templateClass('foo','name\name2\myclass');
|
||||||
|
|
||||||
|
In the template you can use it like this:
|
||||||
|
{foo::method()} etc.
|
||||||
|
|
||||||
|
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Please look through it and send any questions/suggestions/etc to the forums.
|
||||||
|
|
||||||
|
http://www.phpinsider.com/smarty-forum/viewtopic.php?t=14168
|
||||||
|
|
||||||
|
Monte and Uwe
|
78
src/includes/smarty-3.1.48/README.md
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
# Smarty 3 template engine
|
||||||
|
[smarty.net](https://www.smarty.net/)
|
||||||
|
|
||||||
|
[](https://travis-ci.org/smarty-php/smarty)
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
For documentation see
|
||||||
|
[www.smarty.net/docs/en/](https://www.smarty.net/docs/en/)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Smarty can be run with PHP 5.2 to PHP 7.4.
|
||||||
|
|
||||||
|
## Distribution repository
|
||||||
|
|
||||||
|
> Smarty 3.1.28 introduces run time template inheritance
|
||||||
|
|
||||||
|
> Read the NEW_FEATURES and INHERITANCE_RELEASE_NOTES file for recent extensions to Smarty 3.1 functionality
|
||||||
|
|
||||||
|
Smarty versions 3.1.11 or later are now on GitHub and can be installed with Composer.
|
||||||
|
|
||||||
|
|
||||||
|
The "smarty/smarty" package will start at libs/.... subfolder.
|
||||||
|
|
||||||
|
To get the latest stable version of Smarty 3.1 use:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"require": {
|
||||||
|
"smarty/smarty": "~3.1"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
in your composer.json file.
|
||||||
|
|
||||||
|
To get the trunk version use:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"require": {
|
||||||
|
"smarty/smarty": "~3.1@dev"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For a specific version use something like:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"require": {
|
||||||
|
"smarty/smarty": "3.1.19"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
PHPUnit test can be installed by corresponding composer entries like:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"require": {
|
||||||
|
"smarty/smarty-phpunit": "3.1.19"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Similar applies for the lexer/parser generator.
|
||||||
|
|
||||||
|
```json
|
||||||
|
"require": {
|
||||||
|
"smarty/smarty-lexer": "3.1.19"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or you could use:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"require": {
|
||||||
|
"smarty/smarty-dev": "3.1.19"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Which is a wrapper to install all 3 packages.
|
||||||
|
|
||||||
|
Composer can also be used for Smarty2 versions 2.6.24 to 2.6.30.
|
19
src/includes/smarty-3.1.48/SECURITY.md
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
Smarty currently supports the latest minor version of Smarty 3 and Smarty 4. (Smarty 4 has not been released yet.)
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 4.0.x | :white_check_mark: |
|
||||||
|
| 3.1.x | :white_check_mark: |
|
||||||
|
| < 3.1 | :x: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
If you have discovered a security issue with Smarty, please contact us at mail [at] simonwisselink.nl. Do not
|
||||||
|
disclose your findings publicly and PLEASE PLEASE do not file an Issue.
|
||||||
|
|
||||||
|
We will try to confirm the vulnerability and develop a fix if appropriate. When we release the fix, we will publish
|
||||||
|
a security release. Please let us know if you want to be credited.
|
109
src/includes/smarty-3.1.48/SMARTY_2_BC_NOTES.txt
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
= Known incompatibilities with Smarty 2 =
|
||||||
|
|
||||||
|
== Syntax ==
|
||||||
|
|
||||||
|
Smarty 3 API has a new syntax. Much of the Smarty 2 syntax is supported
|
||||||
|
by a wrapper but deprecated. See the README that comes with Smarty 3 for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
The {$array|@mod} syntax has always been a bit confusing, where an "@" is required
|
||||||
|
to apply a modifier to an array instead of the individual elements. Normally you
|
||||||
|
always want the modifier to apply to the variable regardless of its type. In Smarty 3,
|
||||||
|
{$array|mod} and {$array|@mod} behave identical. It is safe to drop the "@" and the
|
||||||
|
modifier will still apply to the array. If you really want the modifier to apply to
|
||||||
|
each array element, you must loop the array in-template, or use a custom modifier that
|
||||||
|
supports array iteration. Most smarty functions already escape values where necessary
|
||||||
|
such as {html_options}
|
||||||
|
|
||||||
|
== PHP Version ==
|
||||||
|
Smarty 3 is PHP 5 only. It will not work with PHP 4.
|
||||||
|
|
||||||
|
== {php} Tag ==
|
||||||
|
The {php} tag is disabled by default. The use of {php} tags is
|
||||||
|
deprecated. It can be enabled with $smarty->allow_php_tag=true.
|
||||||
|
|
||||||
|
But if you scatter PHP code which belongs together into several
|
||||||
|
{php} tags it may not work any longer.
|
||||||
|
|
||||||
|
== Delimiters and whitespace ==
|
||||||
|
Delimiters surrounded by whitespace are no longer treated as Smarty tags.
|
||||||
|
Therefore, { foo } will not compile as a tag, you must use {foo}. This change
|
||||||
|
Makes Javascript/CSS easier to work with, eliminating the need for {literal}.
|
||||||
|
This can be disabled by setting $smarty->auto_literal = false;
|
||||||
|
|
||||||
|
== Unquoted Strings ==
|
||||||
|
Smarty 2 was a bit more forgiving (and ambiguous) when it comes to unquoted strings
|
||||||
|
in parameters. Smarty3 is more restrictive. You can still pass strings without quotes
|
||||||
|
so long as they contain no special characters. (anything outside of A-Za-z0-9_)
|
||||||
|
|
||||||
|
For example filename strings must be quoted
|
||||||
|
<source lang="smarty">
|
||||||
|
{include file='path/foo.tpl'}
|
||||||
|
</source>
|
||||||
|
|
||||||
|
== Extending the Smarty class ==
|
||||||
|
Smarty 3 makes use of the __construct method for initialization. If you are extending
|
||||||
|
the Smarty class, its constructor is not called implicitly if the your child class defines
|
||||||
|
its own constructor. In order to run Smarty's constructor, a call to parent::__construct()
|
||||||
|
within your child constructor is required.
|
||||||
|
|
||||||
|
<source lang="php">
|
||||||
|
class MySmarty extends Smarty {
|
||||||
|
function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
// your initialization code goes here
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</source>
|
||||||
|
|
||||||
|
== Autoloader ==
|
||||||
|
Smarty 3 does register its own autoloader with spl_autoload_register. If your code has
|
||||||
|
an existing __autoload function then this function must be explicitly registered on
|
||||||
|
the __autoload stack. See http://us3.php.net/manual/en/function.spl-autoload-register.php
|
||||||
|
for further details.
|
||||||
|
|
||||||
|
== Plugin Filenames ==
|
||||||
|
Smarty 3 optionally supports the PHP spl_autoloader. The autoloader requires filenames
|
||||||
|
to be lower case. Because of this, Smarty plugin file names must also be lowercase.
|
||||||
|
In Smarty 2, mixed case file names did work.
|
||||||
|
|
||||||
|
== Scope of Special Smarty Variables ==
|
||||||
|
In Smarty 2 the special Smarty variables $smarty.section... and $smarty.foreach...
|
||||||
|
had global scope. If you had loops with the same name in subtemplates you could accidentally
|
||||||
|
overwrite values of parent template.
|
||||||
|
|
||||||
|
In Smarty 3 these special Smarty variable have only local scope in the template which
|
||||||
|
is defining the loop. If you need their value in a subtemplate you have to pass them
|
||||||
|
as parameter.
|
||||||
|
<source lang="smarty">
|
||||||
|
{include file='path/foo.tpl' index=$smarty.section.foo.index}
|
||||||
|
</source>
|
||||||
|
|
||||||
|
== SMARTY_RESOURCE_CHAR_SET ==
|
||||||
|
Smarty 3 sets the constant SMARTY_RESOURCE_CHAR_SET to utf-8 as default template charset.
|
||||||
|
This is now used also on modifiers like escape as default charset. If your templates use
|
||||||
|
other charsets make sure that you define the constant accordingly. Otherwise you may not
|
||||||
|
get any output.
|
||||||
|
|
||||||
|
== newline at {if} tags ==
|
||||||
|
A \n was added to the compiled code of the {if},{else},{elseif},{/if} tags to get output of newlines as expected by the template source.
|
||||||
|
If one of the {if} tags is at the line end you will now get a newline in the HTML output.
|
||||||
|
|
||||||
|
== trigger_error() ==
|
||||||
|
The API function trigger_error() has been removed because it did just map to PHP trigger_error.
|
||||||
|
However it's still included in the Smarty2 API wrapper.
|
||||||
|
|
||||||
|
== Smarty constants ==
|
||||||
|
The constants
|
||||||
|
SMARTY_PHP_PASSTHRU
|
||||||
|
SMARTY_PHP_QUOTE
|
||||||
|
SMARTY_PHP_REMOVE
|
||||||
|
SMARTY_PHP_ALLOW
|
||||||
|
have been replaced with class constants
|
||||||
|
Smarty::PHP_PASSTHRU
|
||||||
|
Smarty::PHP_QUOTE
|
||||||
|
Smarty::PHP_REMOVE
|
||||||
|
Smarty::PHP_ALLOW
|
||||||
|
|
24
src/includes/smarty-3.1.48/SMARTY_3.0_BC_NOTES.txt
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
== Smarty2 backward compatibility ==
|
||||||
|
All Smarty2 specific API functions and deprecated functionality has been moved
|
||||||
|
to the SmartyBC class.
|
||||||
|
|
||||||
|
== {php} Tag ==
|
||||||
|
The {php} tag is no longer available in the standard Smarty calls.
|
||||||
|
The use of {php} tags is deprecated and only available in the SmartyBC class.
|
||||||
|
|
||||||
|
== {include_php} Tag ==
|
||||||
|
The {include_php} tag is no longer available in the standard Smarty calls.
|
||||||
|
The use of {include_php} tags is deprecated and only available in the SmartyBC class.
|
||||||
|
|
||||||
|
== php template resource ==
|
||||||
|
The support of the php template resource is removed.
|
||||||
|
|
||||||
|
== $cache_dir, $compile_dir, $config_dir, $template_dir access ==
|
||||||
|
The mentioned properties can't be accessed directly any longer. You must use
|
||||||
|
corresponding getter/setters like addConfigDir(), setConfigDir(), getConfigDir()
|
||||||
|
|
||||||
|
== obsolete Smarty class properties ==
|
||||||
|
The following no longer used properties are removed:
|
||||||
|
$allow_php_tag
|
||||||
|
$allow_php_template
|
||||||
|
$deprecation_notices
|
306
src/includes/smarty-3.1.48/SMARTY_3.1_NOTES.txt
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
Smarty 3.1 Notes
|
||||||
|
================
|
||||||
|
|
||||||
|
Smarty 3.1 is a departure from 2.0 compatibility. Most notably, all
|
||||||
|
backward compatibility has been moved to a separate class file named
|
||||||
|
SmartyBC.class.php. If you require compatibility with 2.0, you will
|
||||||
|
need to use this class.
|
||||||
|
|
||||||
|
Some differences from 3.0 are also present. 3.1 begins the journey of
|
||||||
|
requiring setters/getters for property access. So far this is only
|
||||||
|
implemented on the five directory properties: template_dir,
|
||||||
|
plugins_dir, configs_dir, compile_dir and cache_dir. These properties
|
||||||
|
are now protected, it is required to use the setters/getters instead.
|
||||||
|
That said, direct property access will still work, however slightly
|
||||||
|
slower since they will now fall through __set() and __get() and in
|
||||||
|
turn passed through the setter/getter methods. 3.2 will exhibit a full
|
||||||
|
list of setter/getter methods for all (currently) public properties,
|
||||||
|
so code-completion in your IDE will work as expected.
|
||||||
|
|
||||||
|
There is absolutely no PHP allowed in templates any more. All
|
||||||
|
deprecated features of Smarty 2.0 are gone. Again, use the SmartyBC
|
||||||
|
class if you need any backward compatibility.
|
||||||
|
|
||||||
|
Internal Changes
|
||||||
|
|
||||||
|
Full UTF-8 Compatibility
|
||||||
|
|
||||||
|
The plugins shipped with Smarty 3.1 have been rewritten to fully
|
||||||
|
support UTF-8 strings if Multibyte String is available. Without
|
||||||
|
MBString UTF-8 cannot be handled properly. For those rare cases where
|
||||||
|
templates themselves have to juggle encodings, the new modifiers
|
||||||
|
to_charset and from_charset may come in handy.
|
||||||
|
|
||||||
|
Plugin API and Performance
|
||||||
|
|
||||||
|
All Plugins (modifiers, functions, blocks, resources,
|
||||||
|
default_template_handlers, etc) are now receiving the
|
||||||
|
Smarty_Internal_Template instance, where they were supplied with the
|
||||||
|
Smarty instance in Smarty 3.0. *. As The Smarty_Internal_Template
|
||||||
|
mimics the behavior of Smarty, this API simplification should not
|
||||||
|
require any changes to custom plugins.
|
||||||
|
|
||||||
|
The plugins shipped with Smarty 3.1 have been rewritten for better
|
||||||
|
performance. Most notably {html_select_date} and {html_select_time}
|
||||||
|
have been improved vastly. Performance aside, plugins have also been
|
||||||
|
reviewed and generalized in their API. {html_select_date} and
|
||||||
|
{html_select_time} now share almost all available options.
|
||||||
|
|
||||||
|
The escape modifier now knows the $double_encode option, which will
|
||||||
|
prevent entities from being encoded again.
|
||||||
|
|
||||||
|
The capitalize modifier now know the $lc_rest option, which makes sure
|
||||||
|
all letters following a capital letter are lower-cased.
|
||||||
|
|
||||||
|
The count_sentences modifier now accepts (.?!) as
|
||||||
|
legitimate endings of a sentence - previously only (.) was
|
||||||
|
accepted
|
||||||
|
|
||||||
|
The new unescape modifier is there to reverse the effects of the
|
||||||
|
escape modifier. This applies to the escape formats html, htmlall and
|
||||||
|
entity.
|
||||||
|
|
||||||
|
default_template_handler_func
|
||||||
|
|
||||||
|
The invocation of $smarty->$default_template_handler_func had to be
|
||||||
|
altered. Instead of a Smarty_Internal_Template, the fifth argument is
|
||||||
|
now provided with the Smarty instance. New footprint:
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Template Handler
|
||||||
|
*
|
||||||
|
* called when Smarty's file: resource is unable to load a requested file
|
||||||
|
*
|
||||||
|
* @param string $type resource type (e.g. "file", "string", "eval", "resource")
|
||||||
|
* @param string $name resource name (e.g. "foo/bar.tpl")
|
||||||
|
* @param string &$content template's content
|
||||||
|
* @param integer &$modified template's modification time
|
||||||
|
* @param Smarty $smarty Smarty instance
|
||||||
|
* @return string|boolean path to file or boolean true if $content and $modified
|
||||||
|
* have been filled, boolean false if no default template
|
||||||
|
* could be loaded
|
||||||
|
*/
|
||||||
|
function default_template_handler_func($type, $name, &$content, &$modified, Smarty $smarty) {
|
||||||
|
if (false) {
|
||||||
|
// return corrected filepath
|
||||||
|
return "/tmp/some/foobar.tpl";
|
||||||
|
} elseif (false) {
|
||||||
|
// return a template directly
|
||||||
|
$content = "the template source";
|
||||||
|
$modified = time();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// tell smarty that we failed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Stuff done to the compiler
|
||||||
|
|
||||||
|
Many performance improvements have happened internally. One notable
|
||||||
|
improvement is that all compiled templates are now handled as PHP
|
||||||
|
functions. This speeds up repeated templates tremendously, as each one
|
||||||
|
calls an (in-memory) PHP function instead of performing another file
|
||||||
|
include/scan.
|
||||||
|
|
||||||
|
New Features
|
||||||
|
|
||||||
|
Template syntax
|
||||||
|
|
||||||
|
{block}..{/block}
|
||||||
|
|
||||||
|
The {block} tag has a new hide option flag. It does suppress the block
|
||||||
|
content if no corresponding child block exists.
|
||||||
|
EXAMPLE:
|
||||||
|
parent.tpl
|
||||||
|
{block name=body hide} child content "{$smarty.block.child}" was
|
||||||
|
inserted {block}
|
||||||
|
In the above example the whole block will be suppressed if no child
|
||||||
|
block "body" is existing.
|
||||||
|
|
||||||
|
{setfilter}..{/setfilter}
|
||||||
|
|
||||||
|
The new {setfilter} block tag allows the definition of filters which
|
||||||
|
run on variable output.
|
||||||
|
SYNTAX:
|
||||||
|
{setfilter filter1|filter2|filter3....}
|
||||||
|
Smarty3 will lookup up matching filters in the following search order:
|
||||||
|
1. variable filter plugin in plugins_dir.
|
||||||
|
2. a valid modifier. A modifier specification will also accept
|
||||||
|
additional parameter like filter2:'foo'
|
||||||
|
3. a PHP function
|
||||||
|
{/setfilter} will turn previous filter setting off again.
|
||||||
|
{setfilter} tags can be nested.
|
||||||
|
EXAMPLE:
|
||||||
|
{setfilter filter1}
|
||||||
|
{$foo}
|
||||||
|
{setfilter filter2}
|
||||||
|
{$bar}
|
||||||
|
{/setfilter}
|
||||||
|
{$buh}
|
||||||
|
{/setfilter}
|
||||||
|
{$blar}
|
||||||
|
In the above example filter1 will run on the output of $foo, filter2
|
||||||
|
on $bar, filter1 again on $buh and no filter on $blar.
|
||||||
|
NOTES:
|
||||||
|
- {$foo nofilter} will suppress the filters
|
||||||
|
- These filters will run in addition to filters defined by
|
||||||
|
registerFilter('variable',...), autoLoadFilter('variable',...) and
|
||||||
|
defined default modifier.
|
||||||
|
- {setfilter} will effect only the current template, not included
|
||||||
|
subtemplates.
|
||||||
|
|
||||||
|
Resource API
|
||||||
|
|
||||||
|
Smarty 3.1 features a new approach to resource management. The
|
||||||
|
Smarty_Resource API allows simple, yet powerful integration of custom
|
||||||
|
resources for templates and configuration files. It offers simple
|
||||||
|
functions for loading data from a custom resource (e.g. database) as
|
||||||
|
well as define new template types adhering to the special
|
||||||
|
non-compiling (e,g, plain php) and non-compile-caching (e.g. eval:
|
||||||
|
resource type) resources.
|
||||||
|
|
||||||
|
See demo/plugins/resource.mysql.php for an example custom database
|
||||||
|
resource.
|
||||||
|
|
||||||
|
Note that old-fashioned registration of callbacks for resource
|
||||||
|
management has been deprecated but is still possible with SmartyBC.
|
||||||
|
|
||||||
|
CacheResource API
|
||||||
|
|
||||||
|
In line with the Resource API, the CacheResource API offers a more
|
||||||
|
comfortable handling of output-cache data. With the
|
||||||
|
Smarty_CacheResource_Custom accessing databases is made simple. With
|
||||||
|
the introduction of Smarty_CacheResource_KeyValueStore the
|
||||||
|
implementation of resources like memcache or APC became a no-brainer;
|
||||||
|
simple hash-based storage systems are now supporting hierarchical
|
||||||
|
output-caches.
|
||||||
|
|
||||||
|
See demo/plugins/cacheresource.mysql.php for an example custom
|
||||||
|
database CacheResource.
|
||||||
|
See demo/plugins/cacheresource.memcache.php for an example custom
|
||||||
|
memcache CacheResource using the KeyValueStore helper.
|
||||||
|
|
||||||
|
Note that old-fashioned registration of $cache_handler is not possible
|
||||||
|
anymore. As the functionality had not been ported to Smarty 3.0.x
|
||||||
|
properly, it has been dropped from 3.1 completely.
|
||||||
|
|
||||||
|
Locking facilities have been implemented to avoid concurrent cache
|
||||||
|
generation. Enable cache locking by setting
|
||||||
|
$smarty->cache_locking = true;
|
||||||
|
|
||||||
|
Relative Paths in Templates (File-Resource)
|
||||||
|
|
||||||
|
As of Smarty 3.1 {include file="../foo.tpl"} and {include
|
||||||
|
file="./foo.tpl"} will resolve relative to the template they're in.
|
||||||
|
Relative paths are available with {include file="..."} and
|
||||||
|
{extends file="..."}. As $smarty->fetch('../foo.tpl') and
|
||||||
|
$smarty->fetch('./foo.tpl') cannot be relative to a template, an
|
||||||
|
exception is thrown.
|
||||||
|
|
||||||
|
Addressing a specific $template_dir
|
||||||
|
|
||||||
|
Smarty 3.1 introduces the $template_dir index notation.
|
||||||
|
$smarty->fetch('[foo]bar.tpl') and {include file="[foo]bar.tpl"}
|
||||||
|
require the template bar.tpl to be loaded from $template_dir['foo'];
|
||||||
|
Smarty::setTemplateDir() and Smarty::addTemplateDir() offer ways to
|
||||||
|
define indexes along with the actual directories.
|
||||||
|
|
||||||
|
Mixing Resources in extends-Resource
|
||||||
|
|
||||||
|
Taking the php extends: template resource one step further, it is now
|
||||||
|
possible to mix resources within an extends: call like
|
||||||
|
$smarty->fetch("extends:file:foo.tpl|db:bar.tpl");
|
||||||
|
|
||||||
|
To make eval: and string: resources available to the inheritance
|
||||||
|
chain, eval:base64:TPL_STRING and eval:urlencode:TPL_STRING have been
|
||||||
|
introduced. Supplying the base64 or urlencode flags will trigger
|
||||||
|
decoding the TPL_STRING in with either base64_decode() or urldecode().
|
||||||
|
|
||||||
|
extends-Resource in template inheritance
|
||||||
|
|
||||||
|
Template based inheritance may now inherit from php's extends:
|
||||||
|
resource like {extends file="extends:foo.tpl|db:bar.tpl"}.
|
||||||
|
|
||||||
|
New Smarty property escape_html
|
||||||
|
|
||||||
|
$smarty->escape_html = true will autoescape all template variable
|
||||||
|
output by calling htmlspecialchars({$output}, ENT_QUOTES,
|
||||||
|
SMARTY_RESOURCE_CHAR_SET).
|
||||||
|
NOTE:
|
||||||
|
This is a compile time option. If you change the setting you must make
|
||||||
|
sure that the templates get recompiled.
|
||||||
|
|
||||||
|
New option at Smarty property compile_check
|
||||||
|
|
||||||
|
The automatic recompilation of modified templates can now be
|
||||||
|
controlled by the following settings:
|
||||||
|
$smarty->compile_check = COMPILECHECK_OFF (false) - template files
|
||||||
|
will not be checked
|
||||||
|
$smarty->compile_check = COMPILECHECK_ON (true) - template files will
|
||||||
|
always be checked
|
||||||
|
$smarty->compile_check = COMPILECHECK_CACHEMISS - template files will
|
||||||
|
be checked if caching is enabled and there is no existing cache file
|
||||||
|
or it has expired
|
||||||
|
|
||||||
|
Automatic recompilation on Smarty version change
|
||||||
|
|
||||||
|
Templates will now be automatically recompiled on Smarty version
|
||||||
|
changes to avoide incompatibillities in the compiled code. Compiled
|
||||||
|
template checked against the current setting of the SMARTY_VERSION
|
||||||
|
constant.
|
||||||
|
|
||||||
|
default_config_handler_func()
|
||||||
|
|
||||||
|
Analogous to the default_template_handler_func()
|
||||||
|
default_config_handler_func() has been introduced.
|
||||||
|
|
||||||
|
default_plugin_handler_func()
|
||||||
|
|
||||||
|
An optional default_plugin_handler_func() can be defined which gets called
|
||||||
|
by the compiler on tags which can't be resolved internally or by plugins.
|
||||||
|
The default_plugin_handler() can map tags to plugins on the fly.
|
||||||
|
|
||||||
|
New getters/setters
|
||||||
|
|
||||||
|
The following setters/getters will be part of the official
|
||||||
|
documentation, and will be strongly recommended. Direct property
|
||||||
|
access will still work for the foreseeable future... it will be
|
||||||
|
transparently routed through the setters/getters, and consequently a
|
||||||
|
bit slower.
|
||||||
|
|
||||||
|
array|string getTemplateDir( [string $index] )
|
||||||
|
replaces $smarty->template_dir; and $smarty->template_dir[$index];
|
||||||
|
Smarty setTemplateDir( array|string $path )
|
||||||
|
replaces $smarty->template_dir = "foo"; and $smarty->template_dir =
|
||||||
|
array("foo", "bar");
|
||||||
|
Smarty addTemplateDir( array|string $path, [string $index])
|
||||||
|
replaces $smarty->template_dir[] = "bar"; and
|
||||||
|
$smarty->template_dir[$index] = "bar";
|
||||||
|
|
||||||
|
array|string getConfigDir( [string $index] )
|
||||||
|
replaces $smarty->config_dir; and $smarty->config_dir[$index];
|
||||||
|
Smarty setConfigDir( array|string $path )
|
||||||
|
replaces $smarty->config_dir = "foo"; and $smarty->config_dir =
|
||||||
|
array("foo", "bar");
|
||||||
|
Smarty addConfigDir( array|string $path, [string $index])
|
||||||
|
replaces $smarty->config_dir[] = "bar"; and
|
||||||
|
$smarty->config_dir[$index] = "bar";
|
||||||
|
|
||||||
|
array getPluginsDir()
|
||||||
|
replaces $smarty->plugins_dir;
|
||||||
|
Smarty setPluginsDir( array|string $path )
|
||||||
|
replaces $smarty->plugins_dir = "foo";
|
||||||
|
Smarty addPluginsDir( array|string $path )
|
||||||
|
replaces $smarty->plugins_dir[] = "bar";
|
||||||
|
|
||||||
|
string getCompileDir()
|
||||||
|
replaces $smarty->compile_dir;
|
||||||
|
Smarty setCompileDir( string $path )
|
||||||
|
replaces $smarty->compile_dir = "foo";
|
||||||
|
|
||||||
|
string getCacheDir()
|
||||||
|
replaces $smarty->cache_dir;
|
||||||
|
Smarty setCacheDir( string $path )
|
||||||
|
replaces $smarty->cache_dir;
|
|
@ -5,7 +5,7 @@
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"templating"
|
"templating"
|
||||||
],
|
],
|
||||||
"homepage": "https://smarty-php.github.io/smarty/",
|
"homepage": "http://www.smarty.net",
|
||||||
"license": "LGPL-3.0",
|
"license": "LGPL-3.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@ -19,35 +19,28 @@
|
||||||
{
|
{
|
||||||
"name": "Rodney Rehm",
|
"name": "Rodney Rehm",
|
||||||
"email": "rodney.rehm@medialize.de"
|
"email": "rodney.rehm@medialize.de"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Simon Wisselink",
|
|
||||||
"homepage": "https://www.iwink.nl/"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
|
"irc": "irc://irc.freenode.org/smarty",
|
||||||
"issues": "https://github.com/smarty-php/smarty/issues",
|
"issues": "https://github.com/smarty-php/smarty/issues",
|
||||||
"forum": "https://github.com/smarty-php/smarty/discussions"
|
"forum": "http://www.smarty.net/forums/"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.2 || ^8.0",
|
"php": "^5.2 || ^7.0"
|
||||||
"symfony/polyfill-mbstring": "^1.27"
|
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4" : {
|
"classmap": [
|
||||||
"Smarty\\" : "src/"
|
"libs/"
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"src/functions.php"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "5.0.x-dev"
|
"dev-master": "3.1.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^8.5 || ^7.5",
|
"phpunit/phpunit": "^7.5 || ^6.5 || ^5.7 || ^4.8",
|
||||||
"smarty/smarty-lexer": "^4.0.2"
|
"smarty/smarty-lexer": "^3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,11 +2,11 @@
|
||||||
/**
|
/**
|
||||||
* Example Application
|
* Example Application
|
||||||
*
|
*
|
||||||
|
* @package Example-application
|
||||||
*/
|
*/
|
||||||
|
require '../libs/Smarty.class.php';
|
||||||
$smarty = new \Smarty\Smarty;
|
$smarty = new Smarty;
|
||||||
|
//$smarty->force_compile = true;
|
||||||
$smarty->debugging = true;
|
$smarty->debugging = true;
|
||||||
$smarty->caching = true;
|
$smarty->caching = true;
|
||||||
$smarty->cache_lifetime = 120;
|
$smarty->cache_lifetime = 120;
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APC CacheResource
|
||||||
|
* CacheResource Implementation based on the KeyValueStore API to use
|
||||||
|
* memcache as the storage resource for Smarty's output caching.
|
||||||
|
* *
|
||||||
|
*
|
||||||
|
* @package CacheResource-examples
|
||||||
|
* @author Uwe Tews
|
||||||
|
*/
|
||||||
|
class Smarty_CacheResource_Apc extends Smarty_CacheResource_KeyValueStore
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Smarty_CacheResource_Apc constructor.
|
||||||
|
*
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// test if APC is present
|
||||||
|
if (!function_exists('apc_cache_info')) {
|
||||||
|
throw new Exception('APC Template Caching Error: APC is not installed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read values for a set of keys from cache
|
||||||
|
*
|
||||||
|
* @param array $keys list of keys to fetch
|
||||||
|
*
|
||||||
|
* @return array list of values with the given keys used as indexes
|
||||||
|
* @return boolean true on success, false on failure
|
||||||
|
*/
|
||||||
|
protected function read(array $keys)
|
||||||
|
{
|
||||||
|
$_res = array();
|
||||||
|
$res = apc_fetch($keys);
|
||||||
|
foreach ($res as $k => $v) {
|
||||||
|
$_res[ $k ] = $v;
|
||||||
|
}
|
||||||
|
return $_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save values for a set of keys to cache
|
||||||
|
*
|
||||||
|
* @param array $keys list of values to save
|
||||||
|
* @param int $expire expiration time
|
||||||
|
*
|
||||||
|
* @return boolean true on success, false on failure
|
||||||
|
*/
|
||||||
|
protected function write(array $keys, $expire = null)
|
||||||
|
{
|
||||||
|
foreach ($keys as $k => $v) {
|
||||||
|
apc_store($k, $v, $expire);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove values from cache
|
||||||
|
*
|
||||||
|
* @param array $keys list of keys to delete
|
||||||
|
*
|
||||||
|
* @return boolean true on success, false on failure
|
||||||
|
*/
|
||||||
|
protected function delete(array $keys)
|
||||||
|
{
|
||||||
|
foreach ($keys as $k) {
|
||||||
|
apc_delete($k);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove *all* values from cache
|
||||||
|
*
|
||||||
|
* @return boolean true on success, false on failure
|
||||||
|
*/
|
||||||
|
protected function purge()
|
||||||
|
{
|
||||||
|
return apc_clear_cache('user');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memcache CacheResource
|
||||||
|
* CacheResource Implementation based on the KeyValueStore API to use
|
||||||
|
* memcache as the storage resource for Smarty's output caching.
|
||||||
|
* Note that memcache has a limitation of 256 characters per cache-key.
|
||||||
|
* To avoid complications all cache-keys are translated to a sha1 hash.
|
||||||
|
*
|
||||||
|
* @package CacheResource-examples
|
||||||
|
* @author Rodney Rehm
|
||||||
|
*/
|
||||||
|
class Smarty_CacheResource_Memcache extends Smarty_CacheResource_KeyValueStore
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* memcache instance
|
||||||
|
*
|
||||||
|
* @var Memcache
|
||||||
|
*/
|
||||||
|
protected $memcache = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smarty_CacheResource_Memcache constructor.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
if (class_exists('Memcached')) {
|
||||||
|
$this->memcache = new Memcached();
|
||||||
|
} else {
|
||||||
|
$this->memcache = new Memcache();
|
||||||
|
}
|
||||||
|
$this->memcache->addServer('127.0.0.1', 11211);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read values for a set of keys from cache
|
||||||
|
*
|
||||||
|
* @param array $keys list of keys to fetch
|
||||||
|
*
|
||||||
|
* @return array list of values with the given keys used as indexes
|
||||||
|
* @return boolean true on success, false on failure
|
||||||
|
*/
|
||||||
|
protected function read(array $keys)
|
||||||
|
{
|
||||||
|
$res = array();
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
$k = sha1($key);
|
||||||
|
$res[$key] = $this->memcache->get($k);
|
||||||
|
}
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save values for a set of keys to cache
|
||||||
|
*
|
||||||
|
* @param array $keys list of values to save
|
||||||
|
* @param int $expire expiration time
|
||||||
|
*
|
||||||
|
* @return boolean true on success, false on failure
|
||||||
|
*/
|
||||||
|
protected function write(array $keys, $expire = null)
|
||||||
|
{
|
||||||
|
foreach ($keys as $k => $v) {
|
||||||
|
$k = sha1($k);
|
||||||
|
if (class_exists('Memcached')) {
|
||||||
|
$this->memcache->set($k, $v, $expire);
|
||||||
|
} else {
|
||||||
|
$this->memcache->set($k, $v, 0, $expire);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove values from cache
|
||||||
|
*
|
||||||
|
* @param array $keys list of keys to delete
|
||||||
|
*
|
||||||
|
* @return boolean true on success, false on failure
|
||||||
|
*/
|
||||||
|
protected function delete(array $keys)
|
||||||
|
{
|
||||||
|
foreach ($keys as $k) {
|
||||||
|
$k = sha1($k);
|
||||||
|
$this->memcache->delete($k);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove *all* values from cache
|
||||||
|
*
|
||||||
|
* @return boolean true on success, false on failure
|
||||||
|
*/
|
||||||
|
protected function purge()
|
||||||
|
{
|
||||||
|
return $this->memcache->flush();
|
||||||
|
}
|
||||||
|
}
|
183
src/includes/smarty-3.1.48/demo/plugins/cacheresource.mysql.php
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MySQL CacheResource
|
||||||
|
* CacheResource Implementation based on the Custom API to use
|
||||||
|
* MySQL as the storage resource for Smarty's output caching.
|
||||||
|
* Table definition:
|
||||||
|
* <pre>CREATE TABLE IF NOT EXISTS `output_cache` (
|
||||||
|
* `id` CHAR(40) NOT NULL COMMENT 'sha1 hash',
|
||||||
|
* `name` VARCHAR(250) NOT NULL,
|
||||||
|
* `cache_id` VARCHAR(250) NULL DEFAULT NULL,
|
||||||
|
* `compile_id` VARCHAR(250) NULL DEFAULT NULL,
|
||||||
|
* `modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
* `content` LONGTEXT NOT NULL,
|
||||||
|
* PRIMARY KEY (`id`),
|
||||||
|
* INDEX(`name`),
|
||||||
|
* INDEX(`cache_id`),
|
||||||
|
* INDEX(`compile_id`),
|
||||||
|
* INDEX(`modified`)
|
||||||
|
* ) ENGINE = InnoDB;</pre>
|
||||||
|
*
|
||||||
|
* @package CacheResource-examples
|
||||||
|
* @author Rodney Rehm
|
||||||
|
*/
|
||||||
|
class Smarty_CacheResource_Mysql extends Smarty_CacheResource_Custom
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \PDO
|
||||||
|
*/
|
||||||
|
protected $db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PDOStatement
|
||||||
|
*/
|
||||||
|
protected $fetch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PDOStatement
|
||||||
|
*/
|
||||||
|
protected $fetchTimestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PDOStatement
|
||||||
|
*/
|
||||||
|
protected $save;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smarty_CacheResource_Mysql constructor.
|
||||||
|
*
|
||||||
|
* @throws \SmartyException
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->db = new PDO("mysql:dbname=test;host=127.0.0.1", "smarty");
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
throw new SmartyException('Mysql Resource failed: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
$this->fetch = $this->db->prepare('SELECT modified, content FROM output_cache WHERE id = :id');
|
||||||
|
$this->fetchTimestamp = $this->db->prepare('SELECT modified FROM output_cache WHERE id = :id');
|
||||||
|
$this->save = $this->db->prepare(
|
||||||
|
'REPLACE INTO output_cache (id, name, cache_id, compile_id, content)
|
||||||
|
VALUES (:id, :name, :cache_id, :compile_id, :content)'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fetch cached content and its modification time from data source
|
||||||
|
*
|
||||||
|
* @param string $id unique cache content identifier
|
||||||
|
* @param string $name template name
|
||||||
|
* @param string $cache_id cache id
|
||||||
|
* @param string $compile_id compile id
|
||||||
|
* @param string $content cached content
|
||||||
|
* @param integer $mtime cache modification timestamp (epoch)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function fetch($id, $name, $cache_id, $compile_id, &$content, &$mtime)
|
||||||
|
{
|
||||||
|
$this->fetch->execute(array('id' => $id));
|
||||||
|
$row = $this->fetch->fetch();
|
||||||
|
$this->fetch->closeCursor();
|
||||||
|
if ($row) {
|
||||||
|
$content = $row[ 'content' ];
|
||||||
|
$mtime = strtotime($row[ 'modified' ]);
|
||||||
|
} else {
|
||||||
|
$content = null;
|
||||||
|
$mtime = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch cached content's modification timestamp from data source
|
||||||
|
*
|
||||||
|
* @note implementing this method is optional. Only implement it if modification times can be accessed faster than
|
||||||
|
* loading the complete cached content.
|
||||||
|
*
|
||||||
|
* @param string $id unique cache content identifier
|
||||||
|
* @param string $name template name
|
||||||
|
* @param string $cache_id cache id
|
||||||
|
* @param string $compile_id compile id
|
||||||
|
*
|
||||||
|
* @return integer|boolean timestamp (epoch) the template was modified, or false if not found
|
||||||
|
*/
|
||||||
|
protected function fetchTimestamp($id, $name, $cache_id, $compile_id)
|
||||||
|
{
|
||||||
|
$this->fetchTimestamp->execute(array('id' => $id));
|
||||||
|
$mtime = strtotime($this->fetchTimestamp->fetchColumn());
|
||||||
|
$this->fetchTimestamp->closeCursor();
|
||||||
|
return $mtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save content to cache
|
||||||
|
*
|
||||||
|
* @param string $id unique cache content identifier
|
||||||
|
* @param string $name template name
|
||||||
|
* @param string $cache_id cache id
|
||||||
|
* @param string $compile_id compile id
|
||||||
|
* @param integer|null $exp_time seconds till expiration time in seconds or null
|
||||||
|
* @param string $content content to cache
|
||||||
|
*
|
||||||
|
* @return boolean success
|
||||||
|
*/
|
||||||
|
protected function save($id, $name, $cache_id, $compile_id, $exp_time, $content)
|
||||||
|
{
|
||||||
|
$this->save->execute(
|
||||||
|
array('id' => $id,
|
||||||
|
'name' => $name,
|
||||||
|
'cache_id' => $cache_id,
|
||||||
|
'compile_id' => $compile_id,
|
||||||
|
'content' => $content,)
|
||||||
|
);
|
||||||
|
return !!$this->save->rowCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete content from cache
|
||||||
|
*
|
||||||
|
* @param string $name template name
|
||||||
|
* @param string $cache_id cache id
|
||||||
|
* @param string $compile_id compile id
|
||||||
|
* @param integer|null $exp_time seconds till expiration or null
|
||||||
|
*
|
||||||
|
* @return integer number of deleted caches
|
||||||
|
*/
|
||||||
|
protected function delete($name, $cache_id, $compile_id, $exp_time)
|
||||||
|
{
|
||||||
|
// delete the whole cache
|
||||||
|
if ($name === null && $cache_id === null && $compile_id === null && $exp_time === null) {
|
||||||
|
// returning the number of deleted caches would require a second query to count them
|
||||||
|
$query = $this->db->query('TRUNCATE TABLE output_cache');
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// build the filter
|
||||||
|
$where = array();
|
||||||
|
// equal test name
|
||||||
|
if ($name !== null) {
|
||||||
|
$where[] = 'name = ' . $this->db->quote($name);
|
||||||
|
}
|
||||||
|
// equal test compile_id
|
||||||
|
if ($compile_id !== null) {
|
||||||
|
$where[] = 'compile_id = ' . $this->db->quote($compile_id);
|
||||||
|
}
|
||||||
|
// range test expiration time
|
||||||
|
if ($exp_time !== null) {
|
||||||
|
$where[] = 'modified < DATE_SUB(NOW(), INTERVAL ' . intval($exp_time) . ' SECOND)';
|
||||||
|
}
|
||||||
|
// equal test cache_id and match sub-groups
|
||||||
|
if ($cache_id !== null) {
|
||||||
|
$where[] =
|
||||||
|
'(cache_id = ' .
|
||||||
|
$this->db->quote($cache_id) .
|
||||||
|
' OR cache_id LIKE ' .
|
||||||
|
$this->db->quote($cache_id . '|%') .
|
||||||
|
')';
|
||||||
|
}
|
||||||
|
// run delete query
|
||||||
|
$query = $this->db->query('DELETE FROM output_cache WHERE ' . join(' AND ', $where));
|
||||||
|
return $query->rowCount();
|
||||||
|
}
|
||||||
|
}
|
346
src/includes/smarty-3.1.48/demo/plugins/cacheresource.pdo.php
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDO Cache Handler
|
||||||
|
* Allows you to store Smarty Cache files into your db.
|
||||||
|
* Example table :
|
||||||
|
* CREATE TABLE `smarty_cache` (
|
||||||
|
* `id` char(40) NOT NULL COMMENT 'sha1 hash',
|
||||||
|
* `name` varchar(250) NOT NULL,
|
||||||
|
* `cache_id` varchar(250) DEFAULT NULL,
|
||||||
|
* `compile_id` varchar(250) DEFAULT NULL,
|
||||||
|
* `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
* `expire` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||||
|
* `content` mediumblob NOT NULL,
|
||||||
|
* PRIMARY KEY (`id`),
|
||||||
|
* KEY `name` (`name`),
|
||||||
|
* KEY `cache_id` (`cache_id`),
|
||||||
|
* KEY `compile_id` (`compile_id`),
|
||||||
|
* KEY `modified` (`modified`),
|
||||||
|
* KEY `expire` (`expire`)
|
||||||
|
* ) ENGINE=InnoDB
|
||||||
|
* Example usage :
|
||||||
|
* $cnx = new PDO("mysql:host=localhost;dbname=mydb", "username", "password");
|
||||||
|
* $smarty->setCachingType('pdo');
|
||||||
|
* $smarty->loadPlugin('Smarty_CacheResource_Pdo');
|
||||||
|
* $smarty->registerCacheResource('pdo', new Smarty_CacheResource_Pdo($cnx, 'smarty_cache'));
|
||||||
|
*
|
||||||
|
* @author Beno!t POLASZEK - 2014
|
||||||
|
*/
|
||||||
|
class Smarty_CacheResource_Pdo extends Smarty_CacheResource_Custom
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
protected $fetchStatements = array('default' => 'SELECT %2$s
|
||||||
|
FROM %1$s
|
||||||
|
WHERE 1
|
||||||
|
AND id = :id
|
||||||
|
AND cache_id IS NULL
|
||||||
|
AND compile_id IS NULL',
|
||||||
|
'withCacheId' => 'SELECT %2$s
|
||||||
|
FROM %1$s
|
||||||
|
WHERE 1
|
||||||
|
AND id = :id
|
||||||
|
AND cache_id = :cache_id
|
||||||
|
AND compile_id IS NULL',
|
||||||
|
'withCompileId' => 'SELECT %2$s
|
||||||
|
FROM %1$s
|
||||||
|
WHERE 1
|
||||||
|
AND id = :id
|
||||||
|
AND compile_id = :compile_id
|
||||||
|
AND cache_id IS NULL',
|
||||||
|
'withCacheIdAndCompileId' => 'SELECT %2$s
|
||||||
|
FROM %1$s
|
||||||
|
WHERE 1
|
||||||
|
AND id = :id
|
||||||
|
AND cache_id = :cache_id
|
||||||
|
AND compile_id = :compile_id');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $insertStatement = 'INSERT INTO %s
|
||||||
|
|
||||||
|
SET id = :id,
|
||||||
|
name = :name,
|
||||||
|
cache_id = :cache_id,
|
||||||
|
compile_id = :compile_id,
|
||||||
|
modified = CURRENT_TIMESTAMP,
|
||||||
|
expire = DATE_ADD(CURRENT_TIMESTAMP, INTERVAL :expire SECOND),
|
||||||
|
content = :content
|
||||||
|
|
||||||
|
ON DUPLICATE KEY UPDATE
|
||||||
|
name = :name,
|
||||||
|
cache_id = :cache_id,
|
||||||
|
compile_id = :compile_id,
|
||||||
|
modified = CURRENT_TIMESTAMP,
|
||||||
|
expire = DATE_ADD(CURRENT_TIMESTAMP, INTERVAL :expire SECOND),
|
||||||
|
content = :content';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $deleteStatement = 'DELETE FROM %1$s WHERE %2$s';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $truncateStatement = 'TRUNCATE TABLE %s';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $fetchColumns = 'modified, content';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $fetchTimestampColumns = 'modified';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PDO
|
||||||
|
*/
|
||||||
|
protected $pdo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
protected $table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var null
|
||||||
|
*/
|
||||||
|
protected $database;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param PDO $pdo PDO : active connection
|
||||||
|
* @param string $table : table (or view) name
|
||||||
|
* @param string $database : optional - if table is located in another db
|
||||||
|
*
|
||||||
|
* @throws \SmartyException
|
||||||
|
*/
|
||||||
|
public function __construct(PDO $pdo, $table, $database = null)
|
||||||
|
{
|
||||||
|
if (is_null($table)) {
|
||||||
|
throw new SmartyException("Table name for caching can't be null");
|
||||||
|
}
|
||||||
|
$this->pdo = $pdo;
|
||||||
|
$this->table = $table;
|
||||||
|
$this->database = $database;
|
||||||
|
$this->fillStatementsWithTableName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the table name into the statements.
|
||||||
|
*
|
||||||
|
* @return $this Current Instance
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected function fillStatementsWithTableName()
|
||||||
|
{
|
||||||
|
foreach ($this->fetchStatements as &$statement) {
|
||||||
|
$statement = sprintf($statement, $this->getTableName(), '%s');
|
||||||
|
}
|
||||||
|
$this->insertStatement = sprintf($this->insertStatement, $this->getTableName());
|
||||||
|
$this->deleteStatement = sprintf($this->deleteStatement, $this->getTableName(), '%s');
|
||||||
|
$this->truncateStatement = sprintf($this->truncateStatement, $this->getTableName());
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the fetch statement, depending on what you specify
|
||||||
|
*
|
||||||
|
* @param string $columns : the column(s) name(s) you want to retrieve from the database
|
||||||
|
* @param string $id unique cache content identifier
|
||||||
|
* @param string|null $cache_id cache id
|
||||||
|
* @param string|null $compile_id compile id
|
||||||
|
*
|
||||||
|
* @access protected
|
||||||
|
* @return \PDOStatement
|
||||||
|
*/
|
||||||
|
protected function getFetchStatement($columns, $id, $cache_id = null, $compile_id = null)
|
||||||
|
{
|
||||||
|
$args = array();
|
||||||
|
if (!is_null($cache_id) && !is_null($compile_id)) {
|
||||||
|
$query = $this->fetchStatements[ 'withCacheIdAndCompileId' ] and
|
||||||
|
$args = array('id' => $id, 'cache_id' => $cache_id, 'compile_id' => $compile_id);
|
||||||
|
} elseif (is_null($cache_id) && !is_null($compile_id)) {
|
||||||
|
$query = $this->fetchStatements[ 'withCompileId' ] and
|
||||||
|
$args = array('id' => $id, 'compile_id' => $compile_id);
|
||||||
|
} elseif (!is_null($cache_id) && is_null($compile_id)) {
|
||||||
|
$query = $this->fetchStatements[ 'withCacheId' ] and $args = array('id' => $id, 'cache_id' => $cache_id);
|
||||||
|
} else {
|
||||||
|
$query = $this->fetchStatements[ 'default' ] and $args = array('id' => $id);
|
||||||
|
}
|
||||||
|
$query = sprintf($query, $columns);
|
||||||
|
$stmt = $this->pdo->prepare($query);
|
||||||
|
foreach ($args as $key => $value) {
|
||||||
|
$stmt->bindValue($key, $value);
|
||||||
|
}
|
||||||
|
return $stmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fetch cached content and its modification time from data source
|
||||||
|
*
|
||||||
|
* @param string $id unique cache content identifier
|
||||||
|
* @param string $name template name
|
||||||
|
* @param string|null $cache_id cache id
|
||||||
|
* @param string|null $compile_id compile id
|
||||||
|
* @param string $content cached content
|
||||||
|
* @param integer $mtime cache modification timestamp (epoch)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected function fetch($id, $name, $cache_id = null, $compile_id = null, &$content, &$mtime)
|
||||||
|
{
|
||||||
|
$stmt = $this->getFetchStatement($this->fetchColumns, $id, $cache_id, $compile_id);
|
||||||
|
$stmt->execute();
|
||||||
|
$row = $stmt->fetch();
|
||||||
|
$stmt->closeCursor();
|
||||||
|
if ($row) {
|
||||||
|
$content = $this->outputContent($row[ 'content' ]);
|
||||||
|
$mtime = strtotime($row[ 'modified' ]);
|
||||||
|
} else {
|
||||||
|
$content = null;
|
||||||
|
$mtime = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch cached content's modification timestamp from data source
|
||||||
|
* {@internal implementing this method is optional.
|
||||||
|
* Only implement it if modification times can be accessed faster than loading the complete cached content.}}
|
||||||
|
*
|
||||||
|
* @param string $id unique cache content identifier
|
||||||
|
* @param string $name template name
|
||||||
|
* @param string|null $cache_id cache id
|
||||||
|
* @param string|null $compile_id compile id
|
||||||
|
*
|
||||||
|
* @return integer|boolean timestamp (epoch) the template was modified, or false if not found
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
// protected function fetchTimestamp($id, $name, $cache_id = null, $compile_id = null) {
|
||||||
|
// $stmt = $this->getFetchStatement($this->fetchTimestampColumns, $id, $cache_id, $compile_id);
|
||||||
|
// $stmt -> execute();
|
||||||
|
// $mtime = strtotime($stmt->fetchColumn());
|
||||||
|
// $stmt -> closeCursor();
|
||||||
|
// return $mtime;
|
||||||
|
// }
|
||||||
|
/**
|
||||||
|
* Save content to cache
|
||||||
|
*
|
||||||
|
* @param string $id unique cache content identifier
|
||||||
|
* @param string $name template name
|
||||||
|
* @param string|null $cache_id cache id
|
||||||
|
* @param string|null $compile_id compile id
|
||||||
|
* @param integer|null $exp_time seconds till expiration time in seconds or null
|
||||||
|
* @param string $content content to cache
|
||||||
|
*
|
||||||
|
* @return boolean success
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected function save($id, $name, $cache_id = null, $compile_id = null, $exp_time, $content)
|
||||||
|
{
|
||||||
|
$stmt = $this->pdo->prepare($this->insertStatement);
|
||||||
|
$stmt->bindValue('id', $id);
|
||||||
|
$stmt->bindValue('name', $name);
|
||||||
|
$stmt->bindValue('cache_id', $cache_id, (is_null($cache_id)) ? PDO::PARAM_NULL : PDO::PARAM_STR);
|
||||||
|
$stmt->bindValue('compile_id', $compile_id, (is_null($compile_id)) ? PDO::PARAM_NULL : PDO::PARAM_STR);
|
||||||
|
$stmt->bindValue('expire', (int)$exp_time, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue('content', $this->inputContent($content));
|
||||||
|
$stmt->execute();
|
||||||
|
return !!$stmt->rowCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes the content before saving to database
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
*
|
||||||
|
* @return string $content
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected function inputContent($content)
|
||||||
|
{
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the content before saving to database
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
*
|
||||||
|
* @return string $content
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected function outputContent($content)
|
||||||
|
{
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete content from cache
|
||||||
|
*
|
||||||
|
* @param string|null $name template name
|
||||||
|
* @param string|null $cache_id cache id
|
||||||
|
* @param string|null $compile_id compile id
|
||||||
|
* @param integer|null|-1 $exp_time seconds till expiration or null
|
||||||
|
*
|
||||||
|
* @return integer number of deleted caches
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected function delete($name = null, $cache_id = null, $compile_id = null, $exp_time = null)
|
||||||
|
{
|
||||||
|
// delete the whole cache
|
||||||
|
if ($name === null && $cache_id === null && $compile_id === null && $exp_time === null) {
|
||||||
|
// returning the number of deleted caches would require a second query to count them
|
||||||
|
$this->pdo->query($this->truncateStatement);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// build the filter
|
||||||
|
$where = array();
|
||||||
|
// equal test name
|
||||||
|
if ($name !== null) {
|
||||||
|
$where[] = 'name = ' . $this->pdo->quote($name);
|
||||||
|
}
|
||||||
|
// equal test cache_id and match sub-groups
|
||||||
|
if ($cache_id !== null) {
|
||||||
|
$where[] =
|
||||||
|
'(cache_id = ' .
|
||||||
|
$this->pdo->quote($cache_id) .
|
||||||
|
' OR cache_id LIKE ' .
|
||||||
|
$this->pdo->quote($cache_id . '|%') .
|
||||||
|
')';
|
||||||
|
}
|
||||||
|
// equal test compile_id
|
||||||
|
if ($compile_id !== null) {
|
||||||
|
$where[] = 'compile_id = ' . $this->pdo->quote($compile_id);
|
||||||
|
}
|
||||||
|
// for clearing expired caches
|
||||||
|
if ($exp_time === Smarty::CLEAR_EXPIRED) {
|
||||||
|
$where[] = 'expire < CURRENT_TIMESTAMP';
|
||||||
|
} // range test expiration time
|
||||||
|
elseif ($exp_time !== null) {
|
||||||
|
$where[] = 'modified < DATE_SUB(NOW(), INTERVAL ' . intval($exp_time) . ' SECOND)';
|
||||||
|
}
|
||||||
|
// run delete query
|
||||||
|
$query = $this->pdo->query(sprintf($this->deleteStatement, join(' AND ', $where)));
|
||||||
|
return $query->rowCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the formatted table name
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected function getTableName()
|
||||||
|
{
|
||||||
|
return (is_null($this->database)) ? "`{$this->table}`" : "`{$this->database}`.`{$this->table}`";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
require_once 'cacheresource.pdo.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDO Cache Handler with GZIP support
|
||||||
|
* Example usage :
|
||||||
|
* $cnx = new PDO("mysql:host=localhost;dbname=mydb", "username", "password");
|
||||||
|
* $smarty->setCachingType('pdo_gzip');
|
||||||
|
* $smarty->loadPlugin('Smarty_CacheResource_Pdo_Gzip');
|
||||||
|
* $smarty->registerCacheResource('pdo_gzip', new Smarty_CacheResource_Pdo_Gzip($cnx, 'smarty_cache'));
|
||||||
|
*
|
||||||
|
* @require Smarty_CacheResource_Pdo class
|
||||||
|
* @author Beno!t POLASZEK - 2014
|
||||||
|
*/
|
||||||
|
class Smarty_CacheResource_Pdo_Gzip extends Smarty_CacheResource_Pdo
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Encodes the content before saving to database
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
*
|
||||||
|
* @return string $content
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected function inputContent($content)
|
||||||
|
{
|
||||||
|
return gzdeflate($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the content before saving to database
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
*
|
||||||
|
* @return string $content
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected function outputContent($content)
|
||||||
|
{
|
||||||
|
return gzinflate($content);
|
||||||
|
}
|
||||||
|
}
|