initial import of file base of my WIP

This commit is contained in:
Sebastian Grewe 2013-05-06 14:11:38 +02:00
commit 1b50f76f72
302 changed files with 58307 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/public/include/config/global.inc.php
/public/templates/compile/*.php

4
CHANGELOG.md Normal file
View File

@ -0,0 +1,4 @@
0.0.1 (Mar 7th 2013)
--------------------
* First release on GitHub, basic working version

202
LICENSE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

126
README.md Normal file
View File

@ -0,0 +1,126 @@
Description
===========
This is a simple PHP framework that I used in a few projects of mine. I
was getting annoyed how long it always took to get the basic setup of a
PHP website done (classes, pages, actions) so I wrote this framework to
help speed up my development process without using one of the big
frameworks out there.
Requirements
============
*No other software required*
Overview
========
Here a quick overview on how the framework works.
Classes
-------
* [[include/classes/]]
For classes used in your projects, a debug class is already included.
Pages
-----
* [include/pages](include/pages)/`pagename`.inc.php
For pages that are called by `index.php?page=<pagename>`. *pagename.inc.php*
must exist and will be included by the index.php file when required.
Actions
-------
* [include/pages](include/pages)/`pagename`/`action`.inc.php
For each page you can create a subdirectory that will be searched for callable
actions for a page: `index.php?page=<pagename>&action=<action>`. *action.inc.php*
must exist in the directory and will be included by the `index.php` file.
Default Page
------------
Currently the framework always defaults to `home`. This still needs to be made
configurable at some point but technical difficulties made this impossible as
a short term solution.
Default Action
--------------
The default action for all pages is unset which means by default the page
include file is loaded. Once an action is defined the page include file
is skipped and the action loaded instead.
Smarty Defaults
---------------
Smarty defaults are configured in the [include/smarty.inc.php](include/smarty.inc.php) file. Change
if need be but usually the defaults should work for you.
Themes
------
As it is the framework has simple theming support. If you wish to add a new
theme create a subdirectory in templates and define that new theme in the
global.inc.php configuration file. You will also need to place any images
and the CSS in the site_assets directory (which is always public accessible).
index.php
---------
The index file is taking care of including all your coded pages and actions.
Please prefix each class, function, action and page with a
if (!defined('SECURITY'))
die('Hacking attempt');
This check ensures all files are called through the `index.php` and not directly.
Setup
=====
To use this framework simply upload everything to your webserver and change
the permissions on the
`templates/compile`
`templates/cache`
to `777` (read/write by everyone) so the Webserver can create the compiled
templates and cache files (if configured, disabled by default).
Once installed just call the `index.php` and you should see the demo page.
Debugger
========
This framework comes with a debugger. Examples on how to use them are given
inside the example pages. You can enable the debugger by setting the defined
DEBUG variable to your debugging verbosity level. Locate the file in:
[include/config/global.inc.php](include/config/global.inc.php)
You can also add any other defines and configuration variables you use
throughout your scripts in this file. It will be included by `index.php`.
License and Author
==================
Author:: Sebastian Grewe (<sebastian.grewe@gmail.com>)
Copyright:: 2013, Sebastian Grewe
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.

22
cronjobs/README Normal file
View File

@ -0,0 +1,22 @@
Install:
--------
These scripts should not really be placed inside of the webroot. They should be run
from the shell via a cronjob. Set something up like this:
# m h dom mon dow command
* * * * * /full/path/to/pool_update.sh 1>/dev/null 2>/dev/null
Also be sure to define in each of these scripts the full path to the include directory.
See the top of each script in the cronjob directory for details.
Notes:
------
These scripts (from version 2.x.x forward) are intended to run every 60 secs. Best results will be achieved
if you configure your server to run them at the same interval. You risk missing new block information being
inserted into the database the longer you set the interval between these scripts running. Database load has
been significantly improved from version 2.x.x forward and it should now be perfectly safe to run these
scripts every 60 secs.

58
cronjobs/archive.php Normal file
View File

@ -0,0 +1,58 @@
<?php
//Set page starter variables//
$includeDirectory = "/sites/mmc/www/includes/";
//Include site functions
include($includeDirectory."requiredFunctions.php");
// get current block num from bitcoind - $num_blocks_old so we can leave some data in shares_history for hashrates
$bitcoinController = new BitcoinClient($rpcType, $rpcUsername, $rpcPassword, $rpcHost);
$currentBlockNumber = $bitcoinController->getblocknumber();
$num_blocks_old = ($currentBlockNumber - 10);
if (!$num_blocks_old) { die($num_blocks_old); }
// get all shares by user id from shares_history and move to shares_uncounted
$sql = "SELECT DISTINCT p.associatedUserId, blockNumber, sum(s.valid) as valid, IFNULL(sum(si.invalid),0) as invalid, max(maxId) as maxId FROM ".
"(SELECT DISTINCT username, max(blockNumber) as blockNumber, count(id) as valid, max(id) as maxId FROM shares_history ".
"WHERE counted='0' AND our_result='Y' AND blockNumber <= '" .$num_blocks_old. "' GROUP BY username) s ".
"LEFT JOIN ".
"(SELECT DISTINCT username, count(id) as invalid FROM shares_history ".
"WHERE counted='0' AND our_result='N' AND blockNumber <= '" .$num_blocks_old. "' GROUP BY username) si ".
"ON s.username=si.username ".
"INNER JOIN pool_worker p ON p.username = s.username ".
"GROUP BY associatedUserId";
$sharesQ = mysql_query($sql);
$i = 0;
$maxId = 0;
$shareInputSql = "";
while ($sharesR = mysql_fetch_object($sharesQ)) {
if ($sharesR->maxId > $maxId)
$maxId = $sharesR->maxId;
if ($i == 0) {
$shareInputSql = "INSERT INTO shares_uncounted (blockNumber, userId, count, invalid, counted, score) VALUES ";
}
if ($i > 0) {
$shareInputSql .= ",";
}
$i++;
$shareInputSql .= "($sharesR->blockNumber,$sharesR->associatedUserId,$sharesR->valid,$sharesR->invalid,0,0)";
if ($i > 20)
{
mysql_query($shareInputSql);
$shareInputSql = "";
$i = 0;
}
}
if (strlen($shareInputSql) > 0)
mysql_query($shareInputSql);
//Remove counted shares from shares_history
mysql_query("DELETE FROM shares_history WHERE counted = '0' AND id <= $maxId AND blockNumber <= '" .$num_blocks_old. "'");
?>

364
cronjobs/cronjob.php Normal file
View File

@ -0,0 +1,364 @@
<?php
//Set page starter variables//
$includeDirectory = "/sites/mmc/www/includes/";
//Include site functions
include($includeDirectory."requiredFunctions.php");
//Open a bitcoind connection
$bitcoinController = new BitcoinClient($rpcType, $rpcUsername, $rpcPassword, $rpcHost);
//Get current block number & difficulty
$currentBlockNumber = $bitcoinController->getblocknumber();
$difficulty = $bitcoinController->query("getdifficulty");
//Get site percentage
$sitePercent = 0;
$sitePercentQ = mysql_query("SELECT value FROM settings WHERE setting='sitepercent'");
if ($sitePercentR = mysql_fetch_object($sitePercentQ)) $sitePercent = $sitePercentR->value;
//Setup score variables
$c = .00001;
$f=1;
$f = $sitePercent / 100;
$p = 1.0/$difficulty;
$r = log(1.0-$p+$p/$c);
$B = 50;
$los = log(1/(exp($r)-1));
//Query bitcoind for list of transactions
$transactions = $bitcoinController->query('listtransactions', '', '240');
$numAccounts = count($transactions);
for($i = 0; $i < $numAccounts; $i++){
// Check for 50BTC in each transaction (even when immature so we can start tracking confirms)
if($transactions[$i]["amount"] >= 50 && ($transactions[$i]["category"] == "immature" || $transactions[$i]["category"] == "immature")) {
// At this point we may have found a block, Check to see if this accountAddres is already added to `networkBlocks`
$accountExistsQ = mysql_query("SELECT id FROM networkBlocks WHERE accountAddress = '".$transactions[$i]["txid"]."' ORDER BY blockNumber DESC LIMIT 0,1")or die(mysql_error());
$accountExists = mysql_num_rows($accountExistsQ);
// We have a new immature transaction for 50 BTC or more - make an entry in `networkBlocks` so we can start tracking the confirms
if(!$accountExists){
$assoc_block = ($currentBlockNumber + 1) - $transactions[$i]["confirmations"];
$assoc_timestamp = $transactions[$i]["time"];
$finder = mysql_fetch_object(mysql_query("SELECT DISTINCT id, username FROM shares where upstream_result = 'Y'"));
// save the winning share and username (if we know it)
if ($finder) {
$last_winning_share = $finder->id;
$username = $finder->username;
mysql_query("INSERT INTO winning_shares (blockNumber, username) VALUES ('" .$assoc_block. "', '" .$username. "')");
} else {
mysql_query("INSERT INTO winning_shares (blockNumber, username) VALUES ('" .$assoc_block. "', 'unknown')");
}
// save the block info so we can track confirms
mysql_query("INSERT INTO `networkBlocks` (`blockNumber`, `timestamp`, `accountAddress`, `confirms`, `difficulty`) ".
"VALUES ('$assoc_block', '$assoc_timestamp', '" .$transactions[$i]["txid"]. "', '" .$transactions[$i]["confirmations"]. "', '$difficulty')");
// score and move shares from this block to shares_history
$shareInputQ = "";
$i=0;
$lastId = 0;
$lastScore = 0;
if ($finder) {
$getAllShares = mysql_query("SELECT `id`, `rem_host`, `username`, `our_result`, `upstream_result`, `reason`, `solution`, time FROM `shares` WHERE id <='" .$last_winning_share. "' ORDER BY `id` ASC");
} else {
$getAllShares = mysql_query("SELECT `id`, `rem_host`, `username`, `our_result`, `upstream_result`, `reason`, `solution`, time FROM `shares` ORDER BY `id` ASC");
}
while($share = mysql_fetch_array($getAllShares)){
if ($i==0)
$shareInputQ = "INSERT INTO `shares_history` (`blockNumber`, `rem_host`, `username`, `our_result`, `upstream_result`, `reason`, `solution`, time, score) VALUES ";
$i++;
if($i > 1){
$shareInputQ .= ",";
}
$score = $lastScore + $r;
$shareInputQ .="('".$assoc_block."',
'".$share["rem_host"]."',
'".$share["username"]."',
'".$share["our_result"]."',
'".$share["upstream_result"]."',
'".$share["reason"]."',
'".$share["solution"]."',
'".$share["time"]."',
".$score.")";
$lastId = $share["id"];
$lastScore = $score;
if ($i > 5) {
//Add to `shares_history`
$shareHistoryQ = mysql_query($shareInputQ);
//If the add to shares_history was successful, lets clean up `shares` table
if($shareHistoryQ){
//Delete all from shares whoms "id" is less then $lastId (keep everything that didnt get moved. Its probably from the new round.
mysql_query("DELETE FROM shares WHERE id <= ".$lastId);
}
$i = 0;
}
}
// less than five share entries? still do the same as above.
$shareHistoryQ = mysql_query($shareInputQ);
if($shareHistoryQ){
//Delete all from shares whoms "id" is less then $lastId to prevent new "hard-earned" shares to be deleted
mysql_query("DELETE FROM shares WHERE id <= ".$lastId);
}
// Count number of shares we needed to solve this block
// get last block number we found
$last_winning_blockQ = mysql_query("SELECT DISTINCT blockNumber FROM winning_shares ORDER BY blockNumber DESC LIMIT 1,1");
$last_winning_blockObj = mysql_fetch_object($last_winning_blockQ);
$last_winning_block = $last_winning_blockObj->blockNumber;
$block_share_countQ = mysql_query("SELECT sum(su_count) as total FROM (".
"SELECT sum(count) as su_count FROM shares_uncounted where blockNumber > " .$last_winning_block. " ".
"and blockNumber <= " .$assoc_block. " ".
"UNION SELECT count(id) as sh_count from shares_history where blockNumber <= " .$assoc_block. " AND blockNumber > " .$last_winning_block. " AND our_result != 'N' ".
") a");
$block_share_countObj = mysql_fetch_object($block_share_countQ);
if($block_share_countObj) {
mysql_query("UPDATE `winning_shares` SET `shareCount` = " .$block_share_countObj->total. " WHERE blockNumber = " .$assoc_block);
}
}
}
}
///// Update confirms /////
// run thru list of transactions we got from bitcoind and update their confirms (when immature)
for($i = 0; $i < $numAccounts; $i++){
//if ($transactions[$i]["category"] = "receive")
if (($transactions[$i]["category"] = "immature") || ($transactions[$i]["category"] = "immature")){
//Check to see if this account was one of the winning accounts from `networkBlocks`
$arrayAddress = $transactions[$i]["txid"];
$winningAccountQ = mysql_query("SELECT id FROM networkBlocks WHERE accountAddress = '".$arrayAddress."' LIMIT 0,1");
$winningAccount = mysql_num_rows($winningAccountQ);
if($winningAccount > 0){
//This is a winning account
$winningAccountObj = mysql_fetch_object($winningAccountQ);
$winningId = $winningAccountObj->id;
$confirms = $transactions[$i]["confirmations"];
//Update X amount of confirms
mysql_query("UPDATE networkBlocks SET confirms = '".$confirms."' WHERE id = ".$winningId);
}
}
}
///// Check for new network block and score and move shares to shares_history if true ///
// refresh the current block number data
$currentBlockNumber = $bitcoinController->getblocknumber();
// check if we have it in the database (if so we exit because we already did this and we were the block finder)
$inDatabaseQ = mysql_query("SELECT `id` FROM `networkBlocks` WHERE `blockNumber` = '$currentBlockNumber' LIMIT 0,1");
$inDatabase = mysql_num_rows($inDatabaseQ);
$finder = mysql_fetch_object(mysql_query("SELECT DISTINCT id, username FROM shares where upstream_result = 'Y'"));
if(!$inDatabase){
// make an entry in the DB for this new block
$currentTime = time();
mysql_query("INSERT INTO `networkBlocks` (`blockNumber`, `timestamp`, `difficulty`) VALUES ('$currentBlockNumber', '$currentTime', '$difficulty')");
// score and move shares from this block to shares_history
$shareInputQ = "";
$i=0;
$lastId = 0;
$lastScore = 0;
$getAllShares = mysql_query("SELECT `id`, `rem_host`, `username`, `our_result`, `upstream_result`, `reason`, `solution`, time FROM `shares` ORDER BY `id` ASC");
while($share = mysql_fetch_array($getAllShares)){
if ($i==0)
$shareInputQ = "INSERT INTO `shares_history` (`blockNumber`, `rem_host`, `username`, `our_result`, `upstream_result`, `reason`, `solution`, time, score) VALUES ";
$i++;
if($i > 1){
$shareInputQ .= ",";
}
$score = $lastScore + $r;
$shareInputQ .="('".$currentBlockNumber."',
'".$share["rem_host"]."',
'".$share["username"]."',
'".$share["our_result"]."',
'".$share["upstream_result"]."',
'".$share["reason"]."',
'".$share["solution"]."',
'".$share["time"]."',
".$score.")";
$lastId = $share["id"];
$lastScore = $score;
if ($i > 5) {
//Add to `shares_history`
$shareHistoryQ = mysql_query($shareInputQ);
//If the add to shares_history was successful, lets clean up `shares` table
if($shareHistoryQ){
//Delete all from shares whoms "id" is less then $lastId (keep everything that didnt get moved. Its probably from the new round.
mysql_query("DELETE FROM shares WHERE id <= ".$lastId);
}
$i = 0;
}
}
// less than five share entries? still do the same as above.
$shareHistoryQ = mysql_query($shareInputQ);
if($shareHistoryQ) {
//Delete all from shares whoms "id" is less then $lastId to prevent new "hard-earned" shares to be deleted
mysql_query("DELETE FROM shares WHERE id <= ".$lastId);
//exec("cd /sites/mmc/cronjobs/; /usr/bin/php archive.php");
}
}
///// Proportional Payout Method /////
// Get uncounted share total
$overallReward = 0;
$blocksQ = mysql_query("SELECT DISTINCT s.blockNumber FROM shares_uncounted s, networkBlocks n WHERE s.blockNumber = n.blocknumber AND s.counted=0 AND n.confirms > 119 ORDER BY s.blockNumber ASC");
while ($blocks = mysql_fetch_object($blocksQ)) {
$block = $blocks->blockNumber;
// LastNshares - mark all shares below the $lastNshares threshold counted
$l_bound = 0;
$total = 0;
$lastNshares = 1000000;
$sql = mysql_query("SELECT blockNumber, count FROM ( ".
"SELECT blockNumber, count FROM `shares_uncounted` WHERE blockNumber <= " .$block. " ".
"UNION SELECT blockNumber, count FROM `shares_counted` WHERE blockNumber <= " .$block. " AND blockNumber > ".($block - 1000)." ".
")a ORDER BY blockNumber DESC");
while ($result = mysql_fetch_object($sql)) {
// increment $total with each row returned
$total = $total + $result->count;
// if $lastNshares criteria is met, and $l_bound is not our whole count, set everything below $l_bound as counted = 1
if ($total >= $lastNshares) {
$l_bound = $result->blockNumber;
if ($l_bound < $block) {
mysql_query("UPDATE shares_uncounted SET counted = 1 WHERE blockNumber < ".$l_bound);
}
break;
}
}
$totalRoundSharesQ = mysql_query("SELECT sum(id) as id FROM ( ".
"SELECT sum(count) as id FROM shares_uncounted WHERE blockNumber <= ".$block." AND blockNumber >= ".$l_bound." ".
"UNION SELECT sum(count) as id FROM shares_counted WHERE blockNumber <= " .$block. " AND blockNumber >= ".$l_bound."".
" )a");
if ($totalRoundSharesR = mysql_fetch_object($totalRoundSharesQ)) {
$totalRoundShares = $totalRoundSharesR->id;
$userListCountQ = mysql_query("SELECT userId, sum(id) as id FROM ( ".
"SELECT DISTINCT userId, sum(count) as id FROM shares_uncounted WHERE blockNumber <= ".$block." AND blockNumber >= ".$l_bound." GROUP BY userId ".
"UNION DISTINCT SELECT userId, sum(count) as id FROM shares_counted WHERE blockNumber <= " .$block. " AND blockNumber >= ".$l_bound." GROUP BY userId ".
" )a GROUP BY userId");
while ($userListCountR = mysql_fetch_object($userListCountQ)) {
$userInfoR = mysql_fetch_object(mysql_query("SELECT DISTINCT username, donate_percent FROM webUsers WHERE id = '" .$userListCountR->userId. "'"));
$username = $userInfoR->username;
$uncountedShares = $userListCountR->id;
$shareRatio = $uncountedShares/$totalRoundShares;
$ownerId = $userListCountR->userId;
$donatePercent = $userInfoR->donate_percent;
//Take out site percent unless user is of early adopter account type
$account_type = account_type($ownerId);
if ($account_type == 0) {
// is normal account
$predonateAmount = (1-$f)*(50*$shareRatio);
$predonateAmount = rtrim(sprintf("%f",$predonateAmount ),"0");
$totalReward = $predonateAmount - ($predonateAmount * ($sitePercent/100));
} else {
// is early adopter round 1 0% lifetime fees
$predonateAmount = 0.9999*(50*$shareRatio);
$predonateAmount = rtrim(sprintf("%f",$predonateAmount ),"0");
$totalReward = $predonateAmount;
}
if ($predonateAmount > 0.00000001) {
//Take out donation
$totalReward = $totalReward - ($totalReward * ($donatePercent/100));
//Round Down to 8 digits
$totalReward = $totalReward * 100000000;
$totalReward = floor($totalReward);
$totalReward = $totalReward/100000000;
//Get total site reward
$donateAmount = round(($predonateAmount - $totalReward), 8);
$overallReward += $totalReward;
//Update account balance & site ledger
mysql_query("UPDATE accountBalance SET balance = balance + ".$totalReward." WHERE userId = ".$ownerId);
mysql_query("INSERT INTO ledger (userId, transType, amount, feeAmount, assocBlock) ".
" VALUES ".
"('$ownerId', 'Credit', '$totalReward', '$donateAmount', '$block')");
}
mysql_query("UPDATE shares_uncounted SET counted = 1 WHERE userId='".$ownerId."' AND blockNumber <= ".$block);
}
// update site wallet with our reward from this block
if (isset($B)) {
$poolReward = $B -$overallReward;
}
//mysql_query("UPDATE settings SET value = value +".$poolReward." WHERE setting='sitebalance'");
mv_uncountedToCounted();
}
}
function mv_uncountedToCounted() {
// clean counted shares_uncounted and move to shares_counted
$sql = "SELECT DISTINCT * FROM shares_uncounted WHERE counted=1";
$sharesQ = mysql_query($sql);
$i = 0;
//$maxId = 0;
$shareInputSql = "";
while ($sharesR = mysql_fetch_object($sharesQ)) {
//if ($sharesR->maxId > $maxId)
// $maxId = $sharesR->maxId;
if ($i == 0) {
$shareInputSql = "INSERT INTO shares_counted (blockNumber, userId, count, invalid, counted, score) VALUES ";
}
if ($i > 0) {
$shareInputSql .= ",";
}
$i++;
$shareInputSql .= "($sharesR->blockNumber,$sharesR->userId,$sharesR->count,$sharesR->invalid,$sharesR->counted,$sharesR->score)";
if ($i > 20)
{
mysql_query($shareInputSql);
$shareInputSql = "";
$i = 0;
}
}
// if not empty, Insert
if (strlen($shareInputSql) > 0)
mysql_query($shareInputSql);
//Remove counted shares from shares_uncounted (this should empty it completely or something went wrong.
mysql_query("DELETE FROM shares_uncounted WHERE counted = '1'");
}
?>

63
cronjobs/hashrate.php Normal file
View File

@ -0,0 +1,63 @@
<?php
$includeDirectory = "/sites/mmc/www/includes/";
include($includeDirectory."requiredFunctions.php");
//Hashrate by worker
$sql = "SELECT IFNULL(sum(a.id),0) as id, p.username FROM pool_worker p LEFT JOIN ".
"((SELECT count(id) as id, username ".
"FROM shares ".
"WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE) ".
"GROUP BY username) ".
"UNION ".
"(SELECT count(id) as id, username ".
"FROM shares_history ".
"WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE) ".
"GROUP BY username)) a ".
"ON p.username=a.username ".
"GROUP BY username";
$result = mysql_query($sql);
while ($resultrow = mysql_fetch_object($result)) {
$hashrate = $resultrow->id;
$hashrate = round((($hashrate*4294967296)/600)/1000000, 0);
mysql_query("UPDATE pool_worker SET hashrate = $hashrate WHERE username = '$resultrow->username'");
}
//Total Hashrate (more exact than adding)
$sql = "SELECT sum(a.id) as id FROM ".
"((SELECT count(id) as id FROM shares WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)) ".
"UNION ".
"(SELECT count(id) as id FROM shares_history WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)) ".
") a ";
$result = mysql_query($sql);
if ($resultrow = mysql_fetch_object($result)) {
$hashrate = $resultrow->id;
$hashrate = round((($hashrate*4294967296)/600)/1000000, 0);
mysql_query("UPDATE settings SET value = '$hashrate' WHERE setting='currenthashrate'");
}
//Hashrate by user
$sql = "SELECT u.id, IFNULL(sum(p.hashrate),0) as hashrate ".
"FROM webUsers u LEFT JOIN pool_worker p ".
"ON p.associatedUserId = u.id ".
"GROUP BY id";
$result = mysql_query($sql);
while ($resultrow = mysql_fetch_object($result)) {
mysql_query("UPDATE webUsers SET hashrate = $resultrow->hashrate WHERE id = $resultrow->id");
// Enable this for lots of stats for graphing
if ($resultrow->hashrate > 0) {
mysql_query("INSERT INTO userHashrates (userId, hashrate) VALUES ($resultrow->id, $resultrow->hashrate)"); // active users hashrate
}
}
mysql_query("INSERT INTO userHashrates (userId, hashrate) VALUES (0, $hashrate)"); // the pool total hashrate
$currentTime = time();
mysql_query("update settings set value='$currentTime' where setting='statstime'");
// Clean up the userHashrate table (anything older than 4 days)
mysql_query("DELETE FROM userHashrates WHERE timestamp < DATE_SUB(now(), INTERVAL 96 HOUR)");
?>

40
cronjobs/payout.php Normal file
View File

@ -0,0 +1,40 @@
<?php
$includeDirectory = "/sites/mmc/www/includes/";
include($includeDirectory."requiredFunctions.php");
$bitcoinController = new BitcoinClient($rpcType, $rpcUsername, $rpcPassword, $rpcHost);
// Pay users who have exceeded their threshold setting
$resultQ = mysql_query("SELECT userId, balance, IFNULL(paid, 0) as paid, IFNULL(sendAddress,'') as sendAddress FROM accountBalance WHERE threshold >= 0.10 AND balance > threshold");
while ($resultR = mysql_fetch_object($resultQ)) {
$currentBalance = $resultR->balance;
$paid = $resultR->paid;
$paymentAddress = $resultR->sendAddress;
$userId = $resultR->userId;
if ($paymentAddress != '')
{
$isValidAddress = $bitcoinController->validateaddress($paymentAddress);
if($isValidAddress){
// Subtract TX fee & calculate total amount the pool will pay
$currentBalance = $currentBalance - 0.0005;
$tot_paid = $resultR->paid + $currentBalance;
// Send the BTC!
// debug
// echo "sending: ". $currentBalance . " to ". $paymentAddress;
if($bitcoinController->sendtoaddress($paymentAddress, $currentBalance)) {
// Reduce balance amount to zero, update total paid amount, and make a ledger entry
mysql_query("UPDATE `accountBalance` SET balance = '0', paid = '".$tot_paid."' WHERE `userId` = '".$userId."'");
mysql_query("INSERT INTO ledger (userId, transType, amount, sendAddress) ".
" VALUES ".
"('$userId', 'Debit_ATP', '$currentBalance', '$paymentAddress')");
}
}
}
}

30
cronjobs/pool_update.sh Normal file
View File

@ -0,0 +1,30 @@
#!/bin/bash
#
# This is where all the magic happens. These scripts count shares, calculate payouts,
# calculate user hashrates, decide when we have found a block and what to do about it,
# and determine if workers are alive or dead. They are the the meat of this package.
#
## Make sure this matches the location of your
## of your php binary.
PHP_BIN="/usr/bin/php";
####################################################################################
PID=$$;
PIDFILE=/var/run/pool_update.pid
if [ -e $PIDFILE ]; then
echo "Already running. I cannot be twice invoked.";
exit
else
echo $PID > $PIDFILE
cd /sites/mmc/cronjobs/
echo -e "\ncronjob.php\n-------------"; time $PHP_BIN cronjob.php; sleep 1;
echo -e "\nshares.php\n-------------"; time $PHP_BIN shares.php; sleep 1;
echo -e "\npayout.php\n-------------"; time $PHP_BIN payout.php; sleep 1;
echo -e "\nworkers.php\n-------------"; time $PHP_BIN workers.php; sleep 1;
echo -e "\nhashrate.php\n-------------"; time $PHP_BIN hashrate.php; sleep 1;
echo -e "\narchive.php\n-------------"; time $PHP_BIN archive.php; sleep 1;
$PHP_BIN tickers.php &
rm -rf $PIDFILE
fi

56
cronjobs/shares.php Normal file
View File

@ -0,0 +1,56 @@
<?php
$includeDirectory = "/sites/mmc/www/includes/";
include($includeDirectory."requiredFunctions.php");
////Update share counts
//Update past shares
try {
$pastSharesQ = mysql_query("SELECT DISTINCT userId, sum(count) AS valid, sum(invalid) AS invalid, id FROM shares_counted GROUP BY userId");
while ($pastSharesR = mysql_fetch_object($pastSharesQ)) {
mysql_query("UPDATE webUsers SET share_count = $pastSharesR->valid, stale_share_count = $pastSharesR->invalid WHERE id = $pastSharesR->userId");
}
} catch (Exception $ex) {}
///// Update current round shares
// reset counters
mysql_query("UPDATE webUsers SET shares_this_round=0");
try {
$sql = "SELECT SUM( id ) AS id, a.associatedUserId ".
"FROM ( ".
"SELECT COUNT( s.id ) AS id, p.associatedUserId ".
"FROM shares s, pool_worker p ".
"WHERE p.username = s.username ".
"AND s.our_result = 'Y' ".
"GROUP BY p.associatedUserId ".
"UNION SELECT COUNT( s.id ) AS id, p.associatedUserId ".
"FROM shares_history s, pool_worker p ".
"WHERE p.username = s.username ".
"AND s.our_result = 'Y' ".
"AND s.counted = '0' ".
"GROUP BY p.associatedUserId ".
")a ".
"GROUP BY associatedUserId";
$result = mysql_query($sql);
$totalsharesthisround = 0;
while ($row = mysql_fetch_object($result)) {
mysql_query("UPDATE webUsers SET shares_this_round = $row->id WHERE id = $row->associatedUserId");
$totalsharesthisround += $row->id;
}
$currentSharesQ = mysql_query("SELECT DISTINCT userId, sum(count) AS valid, sum(invalid) AS invalid, id FROM shares_uncounted GROUP BY userId");
while ($currentSharesR = mysql_fetch_object($currentSharesQ)) {
mysql_query("UPDATE webUsers SET shares_this_round = (shares_this_round + $currentSharesR->valid) ".
"WHERE id = $currentSharesR->userId");
$totalsharesthisround += $currentSharesR->valid;
}
mysql_query("UPDATE settings SET value = '$totalsharesthisround' WHERE setting='currentroundshares'");
} catch (Exception $ex) {}
?>

33
cronjobs/tickers.php Normal file
View File

@ -0,0 +1,33 @@
<?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 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//Set page starter variables//
$includeDirectory = "/sites/mmc/www/includes/";
//Include site functions
include($includeDirectory."requiredFunctions.php");
// Update MtGox last price via curl, 3 second timeout on connection
$mtgox_ticker = exec("/usr/bin/curl -q -s --connect-timeout 3 'https://mtgox.com/code/data/ticker.php'");
if (!is_null($mtgox_ticker)) {
$ticker_obj = json_decode($mtgox_ticker);
if (intval($ticker_obj->ticker->last) > 0) {
$settings->setsetting('mtgoxlast', round($ticker_obj->ticker->last, 4));
}
}
?>

56
cronjobs/workers.php Normal file
View File

@ -0,0 +1,56 @@
<?php
$includeDirectory = "/sites/mmc/www/includes/";
include($includeDirectory."requiredFunctions.php");
//Update workers
$bitcoinController = new BitcoinClient($rpcType, $rpcUsername, $rpcPassword, $rpcHost);
//Get difficulty
$difficulty = $bitcoinController->query("getdifficulty");
//$difficulty = '1';
//Get site percentage fee
$sitePercent = 0;
$sitePercentQ = mysql_query("SELECT value FROM settings WHERE setting='sitepercent'");
if ($sitePercentR = mysql_fetch_object($sitePercentQ)) $sitePercent = $sitePercentR->value;
// set up some scoring variables
$c = .00000001;
$f = $sitePercent / 100;
$p = 1.0/$difficulty;
$r = log(1.0-$p+$p/$c);
$B = 50;
$los = log(1/(exp($r)-1));
// Check for if worker is active (submitted shares in the last 10 mins)
$currentWorkers = 0;
try {
$sql ="SELECT sum(a.id) IS NOT NULL AS active, p.username FROM pool_worker p LEFT JOIN ".
"(SELECT count(id) AS id, username FROM shares WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE) group by username ".
"UNION ".
"SELECT count(id) AS id, username FROM shares_history WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE) group by username) a ON p.username=a.username group by username";
$result = mysql_query($sql);
while ($resultObj = mysql_fetch_object($result)) {
if ($resultObj->active == 1)
$currentWorkers += 1;
mysql_query("UPDATE pool_worker p SET active=".$resultObj->active." WHERE username='".$resultObj->username."'");
}
// Update number of workers in our pool status
$settings->setsetting('currentworkers', $currentWorkers);
} catch (Exception $e) {}
// Calculate estimated round earnings for each user
//Proportional estimate
$totalRoundShares = $settings->getsetting("currentroundshares");
//if ($totalRoundShares < $difficulty) $totalRoundShares = $difficulty;
mysql_query("UPDATE webUsers SET round_estimate = round((1-".$f.")*50*(shares_this_round/".$totalRoundShares.")*(1-(donate_percent/100)), 8)");
// comment the one line below out if you want to disable 0% fees for first 35 users
mysql_query("UPDATE webUsers SET round_estimate = round(0.9999*50*(shares_this_round/".$totalRoundShares.")*(1-(donate_percent/100)), 8) WHERE account_type = '9'");

10
public/.htaccess Normal file
View File

@ -0,0 +1,10 @@
RedirectMatch 404 /templates(/|$)
RedirectMatch 404 /include(/|$)
RedirectMatch 404 /.git(/|$)
php_value error_reporting 30711
php_flag display_startup_errors on
php_flag display_errors on
php_flag html_errors on
php_value docref_root 1
php_value docref_ext 1

0
public/favicon.ico Normal file
View File

View File

@ -0,0 +1,903 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
/**
* Bitcoin classes
*
* By Mike Gogulski - All rights reversed http://www.unlicense.org/ (public domain)
*
* If you find this library useful, your donation of Bitcoins to address
* 1E3d6EWLgwisXY2CWXDcdQQP2ivRN7e9r9 would be greatly appreciated. Thanks!
*
* PHPDoc is available at http://code.gogulski.com/
*
* @author Mike Gogulski - http://www.nostate.com/ http://www.gogulski.com/
* @author theymos - theymos @ http://bitcoin.org/smf
*/
define("BITCOIN_ADDRESS_VERSION", "00");// this is a hex byte
/**
* Bitcoin utility functions class
*
* @author theymos (functionality)
* @author Mike Gogulski
* http://www.gogulski.com/ http://www.nostate.com/
* (encapsulation, string abstraction, PHPDoc)
*/
class Bitcoin {
/*
* Bitcoin utility functions by theymos
* Via http://www.bitcoin.org/smf/index.php?topic=1844.0
* hex input must be in uppercase, with no leading 0x
*/
private static $hexchars = "0123456789ABCDEF";
private static $base58chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
/**
* Convert a hex string into a (big) integer
*
* @param string $hex
* @return int
* @access private
*/
private function decodeHex($hex) {
$hex = strtoupper($hex);
$return = "0";
for ($i = 0; $i < strlen($hex); $i++) {
$current = (string) strpos(self::$hexchars, $hex[$i]);
$return = (string) bcmul($return, "16", 0);
$return = (string) bcadd($return, $current, 0);
}
return $return;
}
/**
* Convert an integer into a hex string
*
* @param int $dec
* @return string
* @access private
*/
private function encodeHex($dec) {
$return = "";
while (bccomp($dec, 0) == 1) {
$dv = (string) bcdiv($dec, "16", 0);
$rem = (integer) bcmod($dec, "16");
$dec = $dv;
$return = $return . self::$hexchars[$rem];
}
return strrev($return);
}
/**
* Convert a Base58-encoded integer into the equivalent hex string representation
*
* @param string $base58
* @return string
* @access private
*/
private function decodeBase58($base58) {
$origbase58 = $base58;
$return = "0";
for ($i = 0; $i < strlen($base58); $i++) {
$current = (string) strpos(Bitcoin::$base58chars, $base58[$i]);
$return = (string) bcmul($return, "58", 0);
$return = (string) bcadd($return, $current, 0);
}
$return = self::encodeHex($return);
//leading zeros
for ($i = 0; $i < strlen($origbase58) && $origbase58[$i] == "1"; $i++) {
$return = "00" . $return;
}
if (strlen($return) % 2 != 0) {
$return = "0" . $return;
}
return $return;
}
/**
* Convert a hex string representation of an integer into the equivalent Base58 representation
*
* @param string $hex
* @return string
* @access private
*/
private function encodeBase58($hex) {
if (strlen($hex) % 2 != 0) {
die("encodeBase58: uneven number of hex characters");
}
$orighex = $hex;
$hex = self::decodeHex($hex);
$return = "";
while (bccomp($hex, 0) == 1) {
$dv = (string) bcdiv($hex, "58", 0);
$rem = (integer) bcmod($hex, "58");
$hex = $dv;
$return = $return . self::$base58chars[$rem];
}
$return = strrev($return);
//leading zeros
for ($i = 0; $i < strlen($orighex) && substr($orighex, $i, 2) == "00"; $i += 2) {
$return = "1" . $return;
}
return $return;
}
/**
* Convert a 160-bit Bitcoin hash to a Bitcoin address
*
* @author theymos
* @param string $hash160
* @param string $addressversion
* @return string Bitcoin address
* @access public
*/
public static function hash160ToAddress($hash160, $addressversion = BITCOIN_ADDRESS_VERSION) {
$hash160 = $addressversion . $hash160;
$check = pack("H*", $hash160);
$check = hash("sha256", hash("sha256", $check, true));
$check = substr($check, 0, 8);
$hash160 = strtoupper($hash160 . $check);
return self::encodeBase58($hash160);
}
/**
* Convert a Bitcoin address to a 160-bit Bitcoin hash
*
* @author theymos
* @param string $addr
* @return string Bitcoin hash
* @access public
*/
public static function addressToHash160($addr) {
$addr = self::decodeBase58($addr);
$addr = substr($addr, 2, strlen($addr) - 10);
return $addr;
}
/**
* Determine if a string is a valid Bitcoin address
*
* @author theymos
* @param string $addr String to test
* @param string $addressversion
* @return boolean
* @access public
*/
public static function checkAddress($addr, $addressversion = BITCOIN_ADDRESS_VERSION) {
$addr = self::decodeBase58($addr);
if (strlen($addr) != 50) {
return false;
}
$version = substr($addr, 0, 2);
if (hexdec($version) > hexdec($addressversion)) {
return false;
}
$check = substr($addr, 0, strlen($addr) - 8);
$check = pack("H*", $check);
$check = strtoupper(hash("sha256", hash("sha256", $check, true)));
$check = substr($check, 0, 8);
return $check == substr($addr, strlen($addr) - 8);
}
/**
* Convert the input to its 160-bit Bitcoin hash
*
* @param string $data
* @return string
* @access private
*/
private function hash160($data) {
$data = pack("H*", $data);
return strtoupper(hash("ripemd160", hash("sha256", $data, true)));
}
/**
* Convert a Bitcoin public key to a 160-bit Bitcoin hash
*
* @param string $pubkey
* @return string
* @access public
*/
public static function pubKeyToAddress($pubkey) {
return self::hash160ToAddress($this->hash160($pubkey));
}
/**
* Remove leading "0x" from a hex value if present.
*
* @param string $string
* @return string
* @access public
*/
public static function remove0x($string) {
if (substr($string, 0, 2) == "0x" || substr($string, 0, 2) == "0X") {
$string = substr($string, 2);
}
return $string;
}
}
/**
* Exception class for BitcoinClient
*
* @author Mike Gogulski
* http://www.gogulski.com/ http://www.nostate.com/
*/
class BitcoinClientException extends ErrorException {
// Redefine the exception so message isn't optional
public function __construct($message, $code = 0, $severity = E_USER_NOTICE, Exception $previous = null) {
parent::__construct($message, $code, $severity, $previous);
}
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
}
require_once(INCLUDE_DIR . "/xmlrpc.inc.php");
require_once(INCLUDE_DIR . "/jsonrpc.inc.php");
/**
* Bitcoin client class for access to a Bitcoin server via JSON-RPC-HTTP[S]
*
* Implements the methods documented at https://www.bitcoin.org/wiki/doku.php?id=api
*
* @version 0.3.19
* @author Mike Gogulski
* http://www.gogulski.com/ http://www.nostate.com/
*/
class BitcoinClient extends jsonrpc_client {
/**
* Create a jsonrpc_client object to talk to the bitcoin server and return it,
* or false on failure.
*
* @param string $scheme
* "http" or "https"
* @param string $username
* User name to use in connection the Bitcoin server's JSON-RPC interface
* @param string $password
* Server password
* @param string $address
* Server hostname or IP address
* @param mixed $port
* Server port (string or integer)
* @param string $certificate_path
* Path on the local filesystem to server's PEM certificate (ignored if $scheme != "https")
* @param integer $debug_level
* 0 (default) = no debugging;
* 1 = echo JSON-RPC messages received to stdout;
* 2 = log transmitted messages also
* @return jsonrpc_client
* @access public
* @throws BitcoinClientException
*/
public function __construct($scheme, $username, $password, $address = "localhost", $port = 8332, $certificate_path = '', $debug_level = 0) {
$scheme = strtolower($scheme);
if ($scheme != "http" && $scheme != "https")
throw new BitcoinClientException("Scheme must be http or https");
if (empty($username))
throw new BitcoinClientException("Username must be non-blank");
if (empty($password))
throw new BitcoinClientException("Password must be non-blank");
$port = (string) $port;
if (!$port || empty($port) || !is_numeric($port) || $port < 1 || $port > 65535 || floatval($port) != intval($port))
throw new BitcoinClientException("Port must be an integer and between 1 and 65535");
if (!empty($certificate_path) && !is_readable($certificate_path))
throw new BitcoinClientException("Certificate file " . $certificate_path . " is not readable");
$uri = $scheme . "://" . $username . ":" . $password . "@" . $address . ":" . $port . "/";
parent::__construct($uri);
$this->setDebug($debug_level);
$this->setSSLVerifyHost(0);
if ($scheme == "https")
if (!empty($certificate_path))
$this->setCaCertificate($certificate_path);
else
$this->setSSLVerifyPeer(false);
}
/**
* Test if the connection to the Bitcoin JSON-RPC server is working
*
* The check is done by calling the server's getinfo() method and checking
* for a fault.
*
* @return mixed boolean TRUE if successful, or a fault string otherwise
* @access public
* @throws none
*/
public function can_connect() {
try {
$r = $this->getinfo();
} catch (BitcoinClientException $e) {
return $e->getMessage();
}
return true;
}
/**
* Convert a Bitcoin server query argument to a jsonrpcval
*
* @param mixed $argument
* @return jsonrpcval
* @throws none
* @todo Make this method private.
*/
public function query_arg_to_parameter($argument) {
$type = "";// "string" is encoded as this default type value in xmlrpc.inc
if (is_numeric($argument)) {
if (intval($argument) != floatval($argument)) {
$argument = floatval($argument);
$type = "double";
} else {
$argument = intval($argument);
$type = "int";
}
}
if (is_bool($argument))
$type = "boolean";
if (is_int($argument))
$type = "int";
if (is_float($argument))
$type = "double";
if (is_array($argument))
$type = "array";
return new jsonrpcval($argument, $type);
}
/**
* Send a JSON-RPC message and optional parameter arguments to the server.
*
* Use the API functions if possible. This method remains public to support
* changes being made to the API before this libarary can be updated.
*
* @param string $message
* @param mixed $args, ...
* @return mixed
* @throws BitcoinClientException
* @see xmlrpc.inc:php_xmlrpc_decode()
*/
public function query($message) {
if (!$message || empty($message))
throw new BitcoinClientException("Bitcoin client query requires a message");
$msg = new jsonrpcmsg($message);
if (func_num_args() > 1) {
for ($i = 1; $i < func_num_args(); $i++) {
$msg->addParam(self::query_arg_to_parameter(func_get_arg($i)));
}
}
$response = $this->send($msg);
if ($response->faultCode()) {
throw new BitcoinClientException($response->faultString());
}
return php_xmlrpc_decode($response->value());
}
/*
* The following functions implement the Bitcoin RPC API as documented at https://www.bitcoin.org/wiki/doku.php?id=api
*/
/**
* Safely copies wallet.dat to destination, which can be a directory or
* a path with filename.
*
* @param string $destination
* @return mixed Nothing, or an error array
* @throws BitcoinClientException
*/
public function backupwallet($destination) {
if (!$destination || empty($destination))
throw new BitcoinClientException("backupwallet requires a destination");
return $this->query("backupwallet", $destination);
}
/**
* Returns the server's available balance, or the balance for $account with
* at least $minconf confirmations.
*
* @param string $account Account to check. If not provided, the server's
* total available balance is returned.
* @param integer $minconf If specified, only transactions with at least
* $minconf confirmations will be included in the returned total.
* @return float Bitcoin balance
* @throws BitcoinClientException
*/
public function getbalance($account = NULL, $minconf = 1) {
if (!is_numeric($minconf) || $minconf < 0)
throw new BitcoinClientException('getbalance requires a numeric minconf >= 0');
if ($account == NULL)
return $this->query("getbalance");
return $this->query("getbalance", $account, $minconf);
}
/**
* Returns the number of blocks in the longest block chain.
*
* @return integer Current block count
* @throws BitcoinClientException
*/
public function getblockcount() {
return $this->query("getblockcount");
}
/**
* Returns the block number of the latest block in the longest block chain.
*
* @return integer Block number
* @throws BitcoinClientException
*/
public function getblocknumber() {
return $this->query("getblocknumber");
}
/**
* Returns the number of connections to other nodes.
*
* @return integer Connection count
* @throws BitcoinClientException
*/
public function getconnectioncount() {
return $this->query("getconnectioncount");
}
/**
* Returns the proof-of-work difficulty as a multiple of the minimum difficulty.
*
* @return float Difficulty
* @throws BitcoinClientException
*/
public function getdifficulty() {
return $this->query("getdifficulty");
}
/**
* Returns boolean true if server is trying to generate bitcoins, false otherwise.
*
* @return boolean Generation status
* @throws BitcoinClientException
*/
public function getgenerate() {
return $this->query("getgenerate");
}
/**
* Tell Bitcoin server to generate Bitcoins or not, and how many processors
* to use.
*
* @param boolean $generate
* @param integer $maxproc
* Limit generation to $maxproc processors, unlimited if -1
* @return mixed Nothing if successful, error array if not
* @throws BitcoinClientException
*/
public function setgenerate($generate = TRUE, $maxproc = -1) {
if (!is_numeric($maxproc) || $maxproc < -1)
throw new BitcoinClientException('setgenerate: $maxproc must be numeric and >= -1');
return $this->query("setgenerate", $generate, $maxproc);
}
/**
* Returns an array containing server information.
*
* @return array Server information
* @throws BitcoinClientException
*/
public function getinfo() {
return $this->query("getinfo");
}
/**
* Returns the account associated with the given address.
*
* @param string $address
* @return string Account
* @throws BitcoinClientException
* @since 0.3.17
*/
public function getaccount($address) {
if (!$address || empty($address))
throw new BitcoinClientException("getaccount requires an address");
return $this->query("getaccount", $address);
}
/**
* Returns the label associated with the given address.
*
* @param string $address
* @return string Label
* @throws BitcoinClientException
* @deprecated Since 0.3.17
*/
public function getlabel($address) {
if (!$address || empty($address))
throw new BitcoinClientException("getlabel requires an address");
return $this->query("getlabel", $address);
}
/**
* Sets the account associated with the given address.
* $account may be omitted to remove an account from an address.
*
* @param string $address
* @param string $account
* @return NULL
* @throws BitcoinClientException
* @since 0.3.17
*/
public function setaccount($address, $account = "") {
if (!$address || empty($address))
throw new BitcoinClientException("setaccount requires an address");
return $this->query("setaccount", $address, $account);
}
/**
* Sets the label associated with the given address.
* $label may be omitted to remove a label from an address.
*
* @param string $address
* @param string $label
* @return NULL
* @throws BitcoinClientException
* @deprecated Since 0.3.17
*/
public function setlabel($address, $label = "") {
if (!$address || empty($address))
throw new BitcoinClientException("setlabel requires an address");
return $this->query("setlabel", $address, $label);
}
/**
* Returns a new bitcoin address for receiving payments.
*
* If $account is specified (recommended), it is added to the address book so
* payments received with the address will be credited to $account.
*
* @param string $account Label to apply to the new address
* @return string Bitcoin address
* @throws BitcoinClientException
*/
public function getnewaddress($account = NULL) {
if (!$account || empty($account))
return $this->query("getnewaddress");
return $this->query("getnewaddress", $account);
}
/**
* Returns the total amount received by $address in transactions with at least
* $minconf confirmations.
*
* @param string $address
* Bitcoin address
* @param integer $minconf
* Minimum number of confirmations for transactions to be counted
* @return float Bitcoin total
* @throws BitcoinClientException
*/
public function getreceivedbyaddress($address, $minconf = 1) {
if (!is_numeric($minconf) || $minconf < 0)
throw new BitcoinClientException('getreceivedbyaddress requires a numeric minconf >= 0');
if (!$address || empty($address))
throw new BitcoinClientException("getreceivedbyaddress requires an address");
return $this->query("getreceivedbyaddress", $address, $minconf);
}
/**
* Returns the total amount received by addresses associated with $account
* in transactions with at least $minconf confirmations.
*
* @param string $account
* @param integer $minconf
* Minimum number of confirmations for transactions to be counted
* @return float Bitcoin total
* @throws BitcoinClientException
* @since 0.3.17
*/
public function getreceivedbyaccount($account, $minconf = 1) {
if (!is_numeric($minconf) || $minconf < 0)
throw new BitcoinClientException('getreceivedbyaccount requires a numeric minconf >= 0');
if (!$account || empty($account))
throw new BitcoinClientException("getreceivedbyaccount requires an account");
return $this->query("getreceivedbyaccount", $account, $minconf);
}
/**
* Returns the total amount received by addresses with $label in
* transactions with at least $minconf confirmations.
*
* @param string $label
* @param integer $minconf
* Minimum number of confirmations for transactions to be counted
* @return float Bitcoin total
* @throws BitcoinClientException
* @deprecated Since 0.3.17
*/
public function getreceivedbylabel($label, $minconf = 1) {
if (!is_numeric($minconf) || $minconf < 0)
throw new BitcoinClientException('getreceivedbylabel requires a numeric minconf >= 0');
if (!$label || empty($label))
throw new BitcoinClientException("getreceivedbylabel requires a label");
return $this->query("getreceivedbylabel", $label, $minconf);
}
/**
* Return a list of server RPC commands or help for $command, if specified.
*
* @param string $command
* @return string Help text
* @throws BitcoinClientException
*/
public function help($command = NULL) {
if (!$command || empty($command))
return $this->query("help");
return $this->query("help", $command);
}
/**
* Return an array of arrays showing how many Bitcoins have been received by
* each address in the server's wallet.
*
* @param integer $minconf Minimum number of confirmations before payments are included.
* @param boolean $includeempty Whether to include addresses that haven't received any payments.
* @return array An array of arrays. The elements are:
* "address" => receiving address
* "account" => the account of the receiving address
* "amount" => total amount received by the address
* "confirmations" => number of confirmations of the most recent transaction included
* @throws BitcoinClientException
*/
public function listreceivedbyaddress($minconf = 1, $includeempty = FALSE) {
if (!is_numeric($minconf) || $minconf < 0)
throw new BitcoinClientException('listreceivedbyaddress requires a numeric minconf >= 0');
return $this->query("listreceivedbyaddress", $minconf, $includeempty);
}
/**
* Return an array of arrays showing how many Bitcoins have been received by
* each account in the server's wallet.
*
* @param integer $minconf
* Minimum number of confirmations before payments are included.
* @param boolean $includeempty
* Whether to include addresses that haven't received any payments.
* @return array An array of arrays. The elements are:
* "account" => the label of the receiving address
* "amount" => total amount received by the address
* "confirmations" => number of confirmations of the most recent transaction included
* @throws BitcoinClientException
* @since 0.3.17
*/
public function listreceivedbyaccount($minconf = 1, $includeempty = FALSE) {
if (!is_numeric($minconf) || $minconf < 0)
throw new BitcoinClientException('listreceivedbyaccount requires a numeric minconf >= 0');
return $this->query("listreceivedbyaccount", $minconf, $includeempty);
}
/**
* Return an array of arrays showing how many Bitcoins have been received by
* each label in the server's wallet.
*
* @param integer $minconf Minimum number of confirmations before payments are included.
* @param boolean $includeempty Whether to include addresses that haven't received any payments.
* @return array An array of arrays. The elements are:
* "label" => the label of the receiving address
* "amount" => total amount received by the address
* "confirmations" => number of confirmations of the most recent transaction included
* @throws BitcoinClientException
* @deprecated Since 0.3.17
*/
public function listreceivedbylabel($minconf = 1, $includeempty = FALSE) {
if (!is_numeric($minconf) || $minconf < 0)
throw new BitcoinClientException('listreceivedbylabel requires a numeric minconf >= 0');
return $this->query("listreceivedbylabel", $minconf, $includeempty);
}
/**
* Send amount from the server's available balance.
*
* $amount is a real and is rounded to the nearest 0.01. Returns string "sent" on success.
*
* @param string $address Destination Bitcoin address or IP address
* @param float $amount Amount to send. Will be rounded to the nearest 0.01.
* @param string $comment
* @param string $comment_to
* @return string Hexadecimal transaction ID on success.
* @throws BitcoinClientException
* @todo Document the comment arguments better.
*/
public function sendtoaddress($address, $amount, $comment = NULL, $comment_to = NULL) {
if (!$address || empty($address))
throw new BitcoinClientException("sendtoaddress requires a destination address");
if (!$amount || empty($amount))
throw new BitcoinClientException("sendtoaddress requires an amount to send");
if (!is_numeric($amount) || $amount <= 0)
throw new BitcoinClientException("sendtoaddress requires the amount sent to be a number > 0");
$amount = floatval($amount);
if (!$comment && !$comment_to)
return $this->query("sendtoaddress", $address, $amount);
if (!$comment_to)
return $this->query("sendtoaddress", $address, $amount, $comment);
return $this->query("sendtoaddress", $address, $amount, $comment, $comment_to);
}
/**
* Stop the Bitcoin server.
*
* @throws BitcoinClientException
*/
public function stop() {
return $this->query("stop");
}
/**
* Check that $address looks like a proper Bitcoin address.
*
* @param string $address String to test for validity as a Bitcoin address
* @return array An array containing:
* "isvalid" => true or false
* "ismine" => true if the address is in the server's wallet
* "address" => bitcoinaddress
* Note: ismine and address are only returned if the address is valid.
* @throws BitcoinClientException
*/
public function validateaddress($address) {
if (!$address || empty($address))
throw new BitcoinClientException("validateaddress requires a Bitcoin address");
return $this->query("validateaddress", $address);
}
/**
* Return information about a specific transaction.
*
* @param string $txid 64-digit hexadecimal transaction ID
* @return array An error array, or an array containing:
* "amount" => float Transaction amount
* "fee" => float Transaction fee
* "confirmations" => integer Network confirmations of this transaction
* "txid" => string The transaction ID
* "message" => string Transaction "comment" message
* "to" => string Transaction "to" message
* @throws BitcoinClientException
* @since 0.3.18
*/
public function gettransaction($txid) {
if (!$txid || empty($txid) || strlen($txid) != 64 || !preg_match('/^[0-9a-fA-F]+$/', $txid))
throw new BitcoinClientException("gettransaction requires a valid hexadecimal transaction ID");
return $this->query("getttransaction", $txid);
}
/**
* Move bitcoins between accounts.
*
* @param string $fromaccount
* Account to move from. If given as an empty string ("") or NULL, bitcoins will
* be moved from the wallet balance to the target account.
* @param string $toaccount
* Account to move to
* @param float $amount
* Amount to move
* @param integer $minconf
* Minimum number of confirmations on bitcoins being moved
* @param string $comment
* Transaction comment
* @throws BitcoinClientException
* @since 0.3.18
*/
public function move($fromaccount = "", $toaccount, $amount, $minconf = 1, $comment = NULL) {
if (!$fromaccount)
$fromaccount = "";
if (!$toaccount || empty($toaccount) || !$amount || !is_numeric($amount) || $amount <= 0)
throw new BitcoinClientException("move requires a from account, to account and numeric amount > 0");
if (!is_numeric($minconf) || $minconf < 0)
throw new BitcoinClientException('move requires a numeric $minconf >= 0');
if (!$comment || empty($comment))
return $this->query("move", $fromaccount, $toaccount, $amount, $minconf);
return $this->query("move", $fromaccount, $toaccount, $amount, $minconf, $comment);
}
/**
* Send $amount from $account's balance to $toaddress. This method will fail
* if there is less than $amount bitcoins with $minconf confirmations in the
* account's balance (unless $account is the empty-string-named default
* account; it behaves like the sendtoaddress method). Returns transaction
* ID on success.
*
* @param string $account Account to send from
* @param string $toaddress Bitcoin address to send to
* @param float $amount Amount to send
* @param integer $minconf Minimum number of confirmations on bitcoins being sent
* @param string $comment
* @param string $comment_to
* @return string Hexadecimal transaction ID
* @throws BitcoinClientException
* @since 0.3.18
*/
public function sendfrom($account, $toaddress, $amount, $minconf = 1, $comment = NULL, $comment_to = NULL) {
if (!$account || !$toaddress || empty($toaddress) || !$amount || !is_numeric($amount) || $amount <= 0)
throw new BitcoinClientException("sendfrom requires a from account, to account and numeric amount > 0");
if (!is_numeric($minconf) || $minconf < 0)
throw new BitcoinClientException('sendfrom requires a numeric $minconf >= 0');
if (!$comment && !$comment_to)
return $this->query("sendfrom", $account, $toaddress, $amount, $minconf);
if (!$comment_to)
return $this->query("sendfrom", $account, $toaddress, $amount, $minconf, $comment);
$this->query("sendfrom", $account, $toaddress, $amount, $minconf, $comment, $comment_to);
}
/**
* Return formatted hash data to work on, or try to solve specified block.
*
* If $data is provided, tries to solve the block and returns true if successful.
* If $data is not provided, returns formatted hash data to work on.
*
* @param string $data Block data
* @return mixed
* boolean TRUE if $data provided and block solving successful
* array otherwise, containing:
* "midstate" => string, precomputed hash state after hashing the first half of the data
* "data" => string, block data
* "hash1" => string, formatted hash buffer for second hash
* "target" => string, little endian hash target
* @throws BitcoinClientException
* @since 0.3.18
*/
public function getwork($data = NULL) {
if (!$data)
return $this->query("getwork");
return $this->query("getwork", $data);
}
/**
* Return the current bitcoin address for receiving payments to $account.
* The account and address will be created if $account doesn't exist.
*
* @param string $account Account name
* @return string Bitcoin address for $account
* @throws BitcoinClientException
* @since 0.3.18
*/
public function getaccountaddress($account) {
if (!$account || empty($account))
throw new BitcoinClientException("getaccountaddress requires an account");
return $this->query("getaccountaddress", $account);
}
/**
* Return a recent hashes per second performance measurement.
*
* @return integer Hashes per second
* @throws BitcoinClientException
*/
public function gethashespersec() {
return $this->query("gethashespersec");
}
/**
* Returns the list of addresses associated with the given account.
*
* @param string $account
* @return array
* A simple array of Bitcoin addresses associated with $account, empty
* if the account doesn't exist.
* @throws BitcoinClientException
*/
public function getaddressesbyaccount($account) {
if (!$account || empty($account))
throw new BitcoinClientException("getaddressesbyaccount requires an account");
return $this->query("getaddressesbyaccount", $account);
}
}
// Auto-load this class
$bitcoin = new BitcoinClient($config['wallet']['type'], $config['wallet']['username'], $config['wallet']['password'], $config['wallet']['host']);

View File

@ -0,0 +1,115 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
/**
* This file defines the debug class used in this site to enable
* verbose deugging outout.
* @package debug
* @author Sebastian 'Seraph' Grewe
* @copyright Sebastian Grewe
* @version 1.0
* */
class Debug {
/**
* @var integer $DEBUG enable (1) or disable (0) debugging
*/
private static $DEBUG;
/**
* @var array $debugInfo Data array with debugging information
*/
private $arrDebugInfo;
/**
* @var float $startTime Start time of our debugger
*/
private static $floatStartTime;
/**
* Construct our class
* @param integer $DEBUG [optional] Enable (>=1) or disable (0) debugging
* @return none
*/
function __construct($DEBUG=0) {
$this->DEBUG = $DEBUG;
if ($DEBUG >= 1) {
$this->floatStartTime = microtime(true);
$this->append("Debugging enabled", 1);
}
}
/**
* If we want to set our debugging level in a child class this allows us to do so
* @param integer $DEBUG our debugging level
*/
function setDebug($DEBUG) {
$this->DEBUG = $DEBUG;
}
/**
* Return a backtrace strin
* @return string Full backtrace <file>:<line> but no refereces to debug class
*/
public function getBacktrace() {
$bth = debug_backtrace();
while (strpos($bth[0]['file'], "classes/debug") != false) array_shift($bth);
foreach ($bth as $x) {
$backtrace[] = array(
'file' => substr($x['file'], strrpos($x['file'], '/') + 1),
'line' => $x['line'],
'function' => $x['function'],
);
}
return $backtrace;
}
/**
* We fill our data array here
* @param string $msg Debug Message
* @param string $file [optional] File name
* @param integer $line [optional] Line inside the $file
* @param integer $debug [optional] Debugging level, default 1
* @param string $class [optional] Class this is called from
* @param string $method [optional] Method this is called from
* @return none
*/
function append($msg, $debug=1) {
if ($this->DEBUG >= $debug) {
$this->arrDebugInfo[] = array(
'level' => $debug,
'time' => round((microtime(true) - $this->floatStartTime) * 1000, 2),
'backtrace' => $this->getBacktrace(),
'message' => $msg,
);
}
}
/**
* Return the created strDebugInfo array
* @return none
*/
public function getDebugInfo() {
return $this->arrDebugInfo;
}
/**
* Directly print the debugging information, table formatted
* @return none
*/
function printDebugInfo() {
echo "<table><tr><td>Timestamp</td><td>File</td><td>Line</td><td>Class</td><td>Method</td><td>Message</td></tr>";
foreach ($this->getDebugInfo() as $content) {
echo "<tr><td>" . $content['time'] . "</td><td>" . $content['backtrace'] . "</td><td>" . $content['message'] . "</td></tr>";
}
echo "</table>";
}
}
// Instantiate this class
$debug = new Debug(DEBUG);
?>

View File

@ -0,0 +1,26 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
class Settings {
public function __construct($debug, $mysqli, $salt) {
$this->debug = $debug;
$this->mysqli = $mysqli;
$this->salt = $salt;
$this->table = 'settings';
}
public function getValue($name) {
$query = $this->mysqli->prepare("SELECT value FROM $this->table WHERE setting=? LIMIT 1");
$query->bind_param('s', $name);
$query->execute();
$query->bind_result($value);
$query->fetch();
$query->close();
return $value;
}
}
$settings = new Settings($debug, $mysqli, SALT);

View File

@ -0,0 +1,311 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
class User {
public function __construct($debug, $mysqli, $salt) {
$this->error = '';
$this->userID = false;
$this->debug = $debug;
$this->mysqli = $mysqli;
$this->salt = $salt;
$this->table = 'webUsers';
$this->user = array();
$this->tableAccountBalance = 'accountBalance';
$this->tablePoolWorker = 'pool_worker';
$this->tableLedger = 'ledger';
}
public function checkLogin($username, $password) {
if ( $this->checkUserPassword($username, $password) ) {
$this->createSession($username);
return true;
}
return false;
}
public function checkPin($userId, $pin=false) {
$stmt = $this->mysqli->prepare("SELECT pin FROM $this->table WHERE id=? AND pin=? LIMIT 1");
$pin_hash = hash('sha256', $pin.$this->salt);
$stmt->bind_param('is', $userId, $pin_hash);
$stmt->execute();
$stmt->bind_result($row_pin);
$stmt->fetch();
$stmt->close();
return $pin_hash === $row_pin;
}
private function getSingle($userID, $search='id', $field='id', $table='') {
if ( empty($table) ) {
$table = $this->table;
}
// Hack for inconsistent field names
$stmt = $this->mysqli->prepare("SELECT $field FROM $table WHERE $search=? LIMIT 1");
if ($this->checkStmt($stmt)) {
$stmt->bind_param('i', $userID);
$stmt->execute();
$stmt->bind_result($value);
$stmt->fetch();
$stmt->close();
return $value;
}
return false;
}
private function updateSingle($userID, $field, $table) {
$stmt = $this->mysqli->prepare("UPDATE $table SET " . $field['name'] . " = ? WHERE userId = ? LIMIT 1");
$stmt->bind_param($field['type'].'i', $field['value'], $userID);
$stmt->execute();
$stmt->close();
return true;
}
public function addLedger($userID, $balance, $address, $fee=0.1) {
$stmt = $this->mysqli->prepare("INSERT INTO $this->tableLedger (userId, transType, amount, sendAddress, feeAmount) VALUES (?, 'Debit_MP', ?, ?, ?)");
$stmt->bind_param('idsd', $userID, $balance, $address, $fee);
$stmt->execute();
$stmt->close();
return true;
}
private function checkStmt($bState) {
if ($bState ===! true) {
$this->debug->append("Failed to prepare statement: " . $this->mysqli->error);
$this->error = 'Unable to prepare database statement';
return false;
}
return true;
}
public function updatePassword($userID, $current, $new1, $new2) {
if ($new1 !== $new2) {
$this->error = 'New passwords do not match';
return false;
}
if ( strlen($new1) < 8 ) {
$this->error = 'New password is too short, please use more than 8 chars';
return false;
}
$current = hash('sha256', $current.$this->salt);
$new = hash('sha256', $new1.$this->salt);
$stmt = $this->mysqli->prepare("UPDATE $this->table SET pass = ? WHERE ( id = ? AND pass = ? )");
if ($this->checkStmt($stmt)) {
$stmt->bind_param('sis', $new, $userID, $current);
$stmt->execute();
if ($stmt->errno == 0 && $stmt->affected_rows === 1) {
return true;
}
$stmt->close();
}
$this->error = 'Unable to update password, current password wrong?';
return false;
}
public function updateAccount($userID, $address, $threshold, $donate) {
$bUser = false;
$bAccount = false;
$threshold = min(250, max(0, floatval($threshold)));
if ($threshold < 1) $threshold = 0.0;
$donate = min(100, max(0, floatval($donate)));
$stmt = $this->mysqli->prepare("UPDATE $this->tableAccountBalance SET sendAddress = ?, threshold = ? WHERE userId = ?");
$stmt->bind_param('ssi', $address, $threshold, $userID);
$stmt->execute();
if ( $stmt->errno == 0 ) {
$bAccount = true;
}
$stmt->close();
$stmt = $this->mysqli->prepare("UPDATE $this->table SET donate_percent = ? WHERE id = ?");
$stmt->bind_param('di', $donate, $userID);
$stmt->execute();
if ( $stmt->errno == 0 ) {
$bUser = true;
}
$stmt->close();
if ($bAccount && $bUser) return true;
return false;
}
// set/get methods
public function getPaid($userID) {
return $this->getSingle($userID, 'userId', 'paid', $this->tableAccountBalance);
}
public function getBalance($userID) {
return $this->getSingle($userID, 'userId', 'balance', $this->tableAccountBalance);
}
public function getLtcAddress($userID) {
return $this->getSingle($userID, 'userId', 'sendAddress', $this->tableAccountBalance);
}
public function getUserName($userID) {
return $this->getSingle($userID, 'id', 'username', $this->table);
}
public function setPaid($userID, $paid) {
$field = array('name' => 'paid', 'type' => 'd', 'value' => $paid);
return $this->updateSingle($userID, $field, $this->tableAccountBalance);
}
public function setBalance($userID, $balance) {
$field = array('name' => 'balance', 'type' => 'd', 'value' => $balance);
return $this->updateSingle($userID, $field, $this->tableAccountBalance);
}
private function checkUserPassword($username, $password) {
$user = array();
$stmt = $this->mysqli->prepare("SELECT username, id FROM $this->table WHERE username=? AND pass=? LIMIT 1");
$stmt->bind_param('ss', $username, hash('sha256', $password.$this->salt));
$stmt->execute();
$stmt->bind_result($row_username, $row_id);
$stmt->fetch();
$stmt->close();
// Store the basic login information
$this->user = array('username' => $row_username, 'id' => $row_id);
return $username === $row_username;
}
private function createSession($username) {
$this->debug->append("Log in user to _SESSION", 2);
session_regenerate_id(true);
$_SESSION['AUTHENTICATED'] = '1';
// $this->user from checkUserPassword
$_SESSION['USERDATA'] = $this->user;
}
public function logoutUser() {
session_destroy();
session_regenerate_id(true);
return true;
}
public function getUserData($userID) {
$this->debug->append("Fetching user information for user id: $userID");
$stmt = $this->mysqli->prepare("
SELECT
u.id, u.username, u.pin, u.pass, u.admin, u.share_count, u.stale_share_count, u.shares_this_round, u.hashrate, u.api_key,
IFNULL(u.donate_percent, '0') as donate_percent, IFNULL(u.round_estimate, '0') as round_estimate, a.sendAddress, a.threshold,
a.balance
FROM $this->table as u LEFT JOIN $this->tableAccountBalance as a
ON u.id = a.userId
WHERE u.id=? LIMIT 0,1");
if ($this->checkStmt($stmt)) {
$stmt->bind_param('i', $userID);
$stmt->execute();
$result = $stmt->get_result();
$stmt->close();
return $result->fetch_array();
} else {
echo $this->mysqli->error;
echo "FAIL";
}
}
// Get 15 most recent transactions
public function getTransactions($userID, $start=0) {
$stmt = $this->mysqli->prepare("SELECT * FROM $this->tableLedger where userId = ? ORDER BY timestamp DESC LIMIT ?,15");
if ($this->checkStmt($stmt)) {
if(!$stmt->bind_param('ii', $userID, $start)) return false;
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_all(MYSQLI_ASSOC);
}
return false;
}
// Worker code, could possibly be moved to it's own class someday
public function updateWorkers($userID, $data) {
$username = $this->getUserName($userID);
foreach ($data as $key => $value) {
// Prefix the WebUser to Worker name
$value['username'] = "$username." . $value['username'];
$stmt = $this->mysqli->prepare("UPDATE $this->tablePoolWorker SET password = ?, username = ? WHERE associatedUserId = ? AND id = ?");
if ($this->checkStmt($stmt)) {
if (!$stmt->bind_param('ssii', $value['password'], $value['username'], $userID, $key)) return false;
if (!$stmt->execute()) return false;
$stmt->close();
}
}
return true;
}
public function getWorkers($userID) {
$stmt = $this->mysqli->prepare("SELECT id, username, password, active, hashrate FROM $this->tablePoolWorker WHERE associatedUserId = ? ORDER BY username ASC");
if ($this->checkStmt($stmt)) {
if (!$stmt->bind_param('i', $userID)) return false;
if (!$stmt->execute()) return false;
$result = $stmt->get_result();
$stmt->close();
return $result->fetch_all(MYSQLI_ASSOC);
}
return false;
}
public function addWorker($userID, $workerName, $workerPassword) {
$username = $this->getUserName($userID);
$workerName = "$username.$workerName";
$stmt = $this->mysqli->prepare("INSERT INTO pool_worker (associatedUserId, username, password) VALUES(?, ?, ?)");
if ($this->checkStmt($stmt)) {
$stmt->bind_param('iss', $userID, $workerName, $workerPassword);
if (!$stmt->execute()) {
$this->error = 'Failed to add worker';
if ($stmt->sqlstate == '23000') $this->error = 'Worker already exists';
return false;
}
return true;
}
return false;
}
public function deleteWorker($userID, $workerID) {
$stmt = $this->mysqli->prepare("DELETE FROM $this->tablePoolWorker WHERE associatedUserId = ? AND id = ?");
if ($this->checkStmt($stmt)) {
$stmt->bind_param('ii', $userID, $workerID);
if ($stmt->execute() && $stmt->affected_rows == 1) {
$stmt->close;
return true;
} else {
$this->error = 'Unable to delete worker';
}
}
return false;
}
public function register($username, $password1, $password2, $pin, $email1='', $email2='') {
if (strlen($password1) < 8) {
$this->error = 'Password is too short, minimum of 8 characters required';
return false;
}
if ($password1 !== $password2) {
$this->error = 'Password do not match';
return false;
}
if (!empty($email1) && !filter_var($email1, FILTER_VALIDATE_EMAIL)) {
$this->error = 'Invalid e-mail address';
return false;
}
if ($email1 !== $email2) {
$this->error = 'E-mail do not match';
return false;
}
if (!is_numeric($pin) || strlen($pin) > 4) {
$this->error = 'Invalid PIN';
return false;
}
$apikey = hash("sha256",$username.$salt);
$stmt = $this->mysqli->prepare("
INSERT INTO $this->table (
admin, username, pass, email,
loggedIp, sessionTimeoutStamp, accountLocked, accountFailedAttempts,
pin, share_count, stale_share_count, shares_this_round, api_key)
VALUES (
0, ?, ?, ?,
'0', '0', '0', '0',
?, '0', '0', '0', ?)
");
$stmt->bind_param('sssis', $username, hash("sha256", $password1.$this->salt), $email1, $pin, $apikey);
if (!$stmt->execute()) {
$this->error = 'Unable to register';
if ($stmt->sqlstate == '23000') $this->error = 'Username already exists';
return false;
}
$stmt->close();
return true;
}
}
$user = new User($debug, $mysqli, SALT);

View File

@ -0,0 +1,47 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// What is our overall theme
define('THEME', 'mmcFE');
// Our include directory for additional features
define('INCLUDE_DIR', 'include');
// Our class directory
define('CLASS_DIR', INCLUDE_DIR . '/classes');
// Our pages directory which takes care of
define('PAGES_DIR', INCLUDE_DIR . '/pages');
// Set debugging level for our debug class
define('DEBUG', 5);
define('SALT', 'LJKEHFuhgu7%&¤Hg783tr7gf¤%¤fyegfredfoGHYFGYe(%/(&%6');
$config = array(
'wallet' => array(
'type' => 'http', // http or https are supported
'host' => 'localhost:9332',
'username' => 'litecoinrpc',
'password' => 'somepass'
),
'cashout' => array(
'min_balance' => 0.0 // Minimal balance to cash out
),
'cookie' => array(
'path' => '/',
'name' => 'POOLERCOOKIE',
'domain' => ''
),
'cache' => 0, // 1 to enable smarty cache in templates/cache
'db' => array(
'host' => 'localhost',
'user' => 'someuser',
'pass' => 'somepass',
'port' => '3306',
'name' => 'litecoin',
),
);
?>

View File

@ -0,0 +1,26 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// Instantiate class, we are using mysqli
$mysqli = new mysqli($config['db']['host'], $config['db']['user'], $config['db']['pass'], $config['db']['name']);
/* check connection */
if (mysqli_connect_errno()) {
$debug->append("Failed to connect to database as non fatal error", 1);
}
/* Example for a query
$query = $mysqli->prepare("SELECT CountryCode, Percentage FROM Language WHERE Language=?");
$lang = "English";
$query->bind_param("s", $lang);
$query->execute();
$query->bind_result($countrycode, $percentage);
while ($query->fetch()) {
printf("%s lang is in CountryCode %s with Percentage %s\n", $lang, $countrycode, $percentage);
}
$query->close();
*/
?>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,9 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,9 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,13 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
if (!$_SESSION['AUTHENTICATED']) {
header('Location: index.php?page=home');
}
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,66 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
if (!$_SESSION['AUTHENTICATED']) {
header('Location: index.php?page=home');
}
if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST['do']) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Invalid PIN','TYPE' => 'errormsg');
} else {
switch ($_POST['do']) {
case 'cashOut':
$dUserBalance = $user->getBalance($_SESSION['USERDATA']['id']);
$sUserSendAddress = $user->getLtcAddress($_SESSION['USERDATA']['id']);
$dUserPaid = $user->getPaid($_SESSION['USERDATA']['id']);
if ($dUserBalance > 0.1) {
if ($bitcoin->can_connect() === true) {
try {
$bitcoin->validateaddress($sUserSendAddress);
} catch (BitcoinClientException $e) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Invalid payment address: ' . $sUserSendAddress, 'TYPE' => 'errormsg');
}
// Remove the transfer fee
$dUserBalance = $dUserBalance - 0.1;
try {
$bitcoin->sendtoaddress($sUserSendAddress, $dUserBalance);
} catch (BitcoinClientException $e) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Failed to send LTC, please contact site support immidiately', 'TYPE' => 'errormsg');
}
// Set balance to 0, add to paid out, insert to ledger
if ( $user->setBalance($_SESSION['USERDATA']['id'], 0) &&
$user->setPaid($_SESSION['USERDATA']['id'], $dUserPaid + $dUserBalance) &&
$user->addLedger($_SESSION['USERDATA']['id'], $dUserBalance, $sUserSendAddress) ) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Transaction completed', 'TYPE' => 'success');
}
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to pushpool service', 'TYPE' => 'errormsg');
}
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than 0.1 LTC to cover transaction fees', 'TYPE' => 'errormsg');
}
break;
case 'updateAccount':
if ($user->updateAccount($_SESSION['USERDATA']['id'], $_POST['paymentAddress'], $_POST['payoutThreshold'], $_POST['donatePercent'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account details updated', 'TYPE' => 'success');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account', 'TYPE' => 'errormsg');
}
break;
case 'updatePassword':
if ($user->updatePassword($_SESSION['USERDATA']['id'], $_POST['currentPassword'], $_POST['newPassword'], $_POST['newPassword2'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Password updated', 'TYPE' => 'success');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => $user->error, 'TYPE' => 'errormsg');
}
break;
}
}
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,12 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
if (!$_SESSION['AUTHENTICATED']) header('Location: index.php?page=home');
$aTransactions = $user->getTransactions($_SESSION['USERDATA']['id']);
if (!$aTransactions) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any transaction', 'TYPE' => 'errormsg');
$smarty->assign('TRANSACTIONS', $aTransactions);
$smarty->assign('CONTENT', 'default.tpl');
?>

View File

@ -0,0 +1,36 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
if (!$_SESSION['AUTHENTICATED']) header('Location: index.php?page=home');
switch ($_REQUEST['do']) {
case 'delete':
if ($user->deleteWorker($_SESSION['USERDATA']['id'], $_GET['id'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Worker removed');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => $user->error, 'TYPE' => 'errormsg');
}
break;
case 'add':
if ($user->addWorker($_SESSION['USERDATA']['id'], $_POST['username'], $_POST['password'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Worker added');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => $user->error, 'TYPE' => 'errormsg');
}
break;
case 'update':
if ($user->updateWorkers($_SESSION['USERDATA']['id'], $_POST['data'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Worker updated');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => $user->error, 'TYPE' => 'errormsg');
}
break;
}
$aWorkers = $user->getWorkers($_SESSION['USERDATA']['id']);
if (!$aWorkers) $_SESSION['POPUP'][] = array('CONTENT' => 'You have no workers configured', 'TYPE' => 'errormsg');
$smarty->assign('CONTENT', 'default.tpl');
$smarty->assign('WORKERS', $aWorkers);
?>

View File

@ -0,0 +1,9 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,9 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,13 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
if ( $user->checkLogin($_POST['username'],$_POST['password']) ) {
header('Location: index.php?page=home');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Invalid username or password', 'TYPE' => 'errormsg');
}
$smarty->assign('CONTENT', 'default.tpl');
?>

View File

@ -0,0 +1,10 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// This probably (?) never fails
$user->logoutUser();
header('Location: index.php?page=home');
?>

View File

@ -0,0 +1,9 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,9 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,16 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
if ($user->register($_POST['username'], $_POST['password1'], $_POST['password2'], $_POST['pin'], $_POST['email1'], $_POST['email2'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account created, please login');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to create account: ' . $user->error, 'TYPE' => 'errormsg');
}
// We load the default registration template instead of an action specific one
$smarty->assign("CONTENT", "../default.tpl");
?>

View File

@ -0,0 +1,18 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
if ($bitcoin->can_connect() === true){
$iDifficulty = $bitcoin->query('getdifficulty');
$iBlock = $bitcoin->query('getblockcount');
} else {
$iDifficulty = 1;
$iBlock = 0;
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to pushpool service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg');
}
$smarty->assign("CURRENTBLOCK", $iBlock);
$smarty->assign("CURRENTDIFFICULTY", $iDifficulty);
$smarty->assign("CONTENT", "pool/default.tpl");

View File

@ -0,0 +1,24 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
if ($bitcoin->can_connect() === true){
$iDifficulty = $bitcoin->query('getdifficulty');
$iBlock = $bitcoin->query('getblockcount');
} else {
$iDifficulty = 1;
$iBlock = 0;
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to pushpool service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg');
}
$smarty->assign("CURRENTBLOCK", $iBlock);
$smarty->assign("DIFFICULTY", $iDifficulty);
if ($_SESSION['AUTHENTICATED']) {
$smarty->assign("CONTENT", "authenticated.tpl");
} else {
$smarty->assign("CONTENT", "default.tpl");
}
?>

View File

@ -0,0 +1,9 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,25 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
$debug->append('Loading Smarty libraries', 2);
define('SMARTY_DIR', INCLUDE_DIR . '/smarty/libs/');
// Include the actual smarty class file
include(INCLUDE_DIR . '/smarty/libs/Smarty.class.php');
// We initialize smarty here
$debug->append('Instantiating Smarty Object', 3);
$smarty = new Smarty;
// Assign our local paths
$debug->append('Define Smarty Paths', 3);
$smarty->template_dir = 'templates/' . THEME . '/';
$smarty->compile_dir = 'templates/compile/';
// Optional smarty caching, check Smarty documentation for details
$smarty->caching = $config['cache'];
$smarty->cache_dir = "templates/cache";
?>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,460 @@
<?php
/**
* Project: Smarty: the PHP compiling template engine
* File: SmartyBC.class.php
* SVN: $Id: $
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* For questions, help, comments, discussion, etc., please join the
* Smarty mailing list. Send a blank e-mail to
* smarty-discussion-subscribe@googlegroups.com
*
* @link http://www.smarty.net/
* @copyright 2008 New Digital Group, Inc.
* @author Monte Ohrt <monte at ohrt dot com>
* @author Uwe Tews
* @author Rodney Rehm
* @package Smarty
*/
/**
* @ignore
*/
require(dirname(__FILE__) . '/Smarty.class.php');
/**
* Smarty Backward Compatability Wrapper Class
*
* @package Smarty
*/
class SmartyBC extends Smarty {
/**
* Smarty 2 BC
* @var string
*/
public $_version = self::SMARTY_VERSION;
/**
* Initialize new SmartyBC object
*
* @param array $options options to set during initialization, e.g. array( 'forceCompile' => false )
*/
public function __construct(array $options=array())
{
parent::__construct($options);
// register {php} tag
$this->registerPlugin('block', 'php', 'smarty_php_tag');
}
/**
* wrapper for assign_by_ref
*
* @param string $tpl_var the template variable name
* @param mixed &$value the referenced value to assign
*/
public function assign_by_ref($tpl_var, &$value)
{
$this->assignByRef($tpl_var, $value);
}
/**
* wrapper for append_by_ref
*
* @param string $tpl_var the template variable name
* @param mixed &$value the referenced value to append
* @param boolean $merge flag if array elements shall be merged
*/
public function append_by_ref($tpl_var, &$value, $merge = false)
{
$this->appendByRef($tpl_var, $value, $merge);
}
/**
* clear the given assigned template variable.
*
* @param string $tpl_var the template variable to clear
*/
public function clear_assign($tpl_var)
{
$this->clearAssign($tpl_var);
}
/**
* Registers custom function to be used in templates
*
* @param string $function the name of the template function
* @param string $function_impl the name of the PHP function to register
* @param bool $cacheable
* @param mixed $cache_attrs
*/
public function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null)
{
$this->registerPlugin('function', $function, $function_impl, $cacheable, $cache_attrs);
}
/**
* Unregisters custom function
*
* @param string $function name of template function
*/
public function unregister_function($function)
{
$this->unregisterPlugin('function', $function);
}
/**
* Registers object to be used in templates
*
* @param string $object name of template object
* @param object $object_impl the referenced PHP object to register
* @param array $allowed list of allowed methods (empty = all)
* @param boolean $smarty_args smarty argument format, else traditional
* @param array $block_functs list of methods that are block format
*/
public function register_object($object, $object_impl, $allowed = array(), $smarty_args = true, $block_methods = array())
{
settype($allowed, 'array');
settype($smarty_args, 'boolean');
$this->registerObject($object, $object_impl, $allowed, $smarty_args, $block_methods);
}
/**
* Unregisters object
*
* @param string $object name of template object
*/
public function unregister_object($object)
{
$this->unregisterObject($object);
}
/**
* Registers block function to be used in templates
*
* @param string $block name of template block
* @param string $block_impl PHP function to register
* @param bool $cacheable
* @param mixed $cache_attrs
*/
public function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null)
{
$this->registerPlugin('block', $block, $block_impl, $cacheable, $cache_attrs);
}
/**
* Unregisters block function
*
* @param string $block name of template function
*/
public function unregister_block($block)
{
$this->unregisterPlugin('block', $block);
}
/**
* Registers compiler function
*
* @param string $function name of template function
* @param string $function_impl name of PHP function to register
* @param bool $cacheable
*/
public function register_compiler_function($function, $function_impl, $cacheable=true)
{
$this->registerPlugin('compiler', $function, $function_impl, $cacheable);
}
/**
* Unregisters compiler function
*
* @param string $function name of template function
*/
public function unregister_compiler_function($function)
{
$this->unregisterPlugin('compiler', $function);
}
/**
* Registers modifier to be used in templates
*
* @param string $modifier name of template modifier
* @param string $modifier_impl name of PHP function to register
*/
public function register_modifier($modifier, $modifier_impl)
{
$this->registerPlugin('modifier', $modifier, $modifier_impl);
}
/**
* Unregisters modifier
*
* @param string $modifier name of template modifier
*/
public function unregister_modifier($modifier)
{
$this->unregisterPlugin('modifier', $modifier);
}
/**
* Registers a resource to fetch a template
*
* @param string $type name of resource
* @param array $functions array of functions to handle resource
*/
public function register_resource($type, $functions)
{
$this->registerResource($type, $functions);
}
/**
* Unregisters a resource
*
* @param string $type name of resource
*/
public function unregister_resource($type)
{
$this->unregisterResource($type);
}
/**
* Registers a prefilter function to apply
* to a template before compiling
*
* @param callable $function
*/
public function register_prefilter($function)
{
$this->registerFilter('pre', $function);
}
/**
* Unregisters a prefilter function
*
* @param callable $function
*/
public function unregister_prefilter($function)
{
$this->unregisterFilter('pre', $function);
}
/**
* Registers a postfilter function to apply
* to a compiled template after compilation
*
* @param callable $function
*/
public function register_postfilter($function)
{
$this->registerFilter('post', $function);
}
/**
* Unregisters a postfilter function
*
* @param callable $function
*/
public function unregister_postfilter($function)
{
$this->unregisterFilter('post', $function);
}
/**
* Registers an output filter function to apply
* to a template output
*
* @param callable $function
*/
public function register_outputfilter($function)
{
$this->registerFilter('output', $function);
}
/**
* Unregisters an outputfilter function
*
* @param callable $function
*/
public function unregister_outputfilter($function)
{
$this->unregisterFilter('output', $function);
}
/**
* load a filter of specified type and name
*
* @param string $type filter type
* @param string $name filter name
*/
public function load_filter($type, $name)
{
$this->loadFilter($type, $name);
}
/**
* clear cached content for the given template and cache id
*
* @param string $tpl_file name of template file
* @param string $cache_id name of cache_id
* @param string $compile_id name of compile_id
* @param string $exp_time expiration time
* @return boolean
*/
public function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null)
{
return $this->clearCache($tpl_file, $cache_id, $compile_id, $exp_time);
}
/**
* clear the entire contents of cache (all templates)
*
* @param string $exp_time expire time
* @return boolean
*/
public function clear_all_cache($exp_time = null)
{
return $this->clearCache(null, null, null, $exp_time);
}
/**
* test to see if valid cache exists for this template
*
* @param string $tpl_file name of template file
* @param string $cache_id
* @param string $compile_id
* @return boolean
*/
public function is_cached($tpl_file, $cache_id = null, $compile_id = null)
{
return $this->isCached($tpl_file, $cache_id, $compile_id);
}
/**
* clear all the assigned template variables.
*/
public function clear_all_assign()
{
$this->clearAllAssign();
}
/**
* clears compiled version of specified template resource,
* or all compiled template files if one is not specified.
* This function is for advanced use only, not normally needed.
*
* @param string $tpl_file
* @param string $compile_id
* @param string $exp_time
* @return boolean results of {@link smarty_core_rm_auto()}
*/
public function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null)
{
return $this->clearCompiledTemplate($tpl_file, $compile_id, $exp_time);
}
/**
* Checks whether requested template exists.
*
* @param string $tpl_file
* @return boolean
*/
public function template_exists($tpl_file)
{
return $this->templateExists($tpl_file);
}
/**
* Returns an array containing template variables
*
* @param string $name
* @return array
*/
public function get_template_vars($name=null)
{
return $this->getTemplateVars($name);
}
/**
* Returns an array containing config variables
*
* @param string $name
* @return array
*/
public function get_config_vars($name=null)
{
return $this->getConfigVars($name);
}
/**
* load configuration values
*
* @param string $file
* @param string $section
* @param string $scope
*/
public function config_load($file, $section = null, $scope = 'global')
{
$this->ConfigLoad($file, $section, $scope);
}
/**
* return a reference to a registered object
*
* @param string $name
* @return object
*/
public function get_registered_object($name)
{
return $this->getRegisteredObject($name);
}
/**
* clear configuration values
*
* @param string $var
*/
public function clear_config($var = null)
{
$this->clearConfig($var);
}
/**
* trigger Smarty error
*
* @param string $error_msg
* @param integer $error_type
*/
public function trigger_error($error_msg, $error_type = E_USER_WARNING)
{
trigger_error("Smarty error: $error_msg", $error_type);
}
}
/**
* Smarty {php}{/php} block function
*
* @param array $params parameter list
* @param string $content contents of the block
* @param object $template template object
* @param boolean &$repeat repeat flag
* @return string content re-formatted
*/
function smarty_php_tag($params, $content, $template, &$repeat)
{
eval($content);
return '';
}
?>

View File

@ -0,0 +1,133 @@
{capture name='_smarty_debug' assign=debug_output}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Smarty Debug Console</title>
<style type="text/css">
{literal}
body, h1, h2, td, th, p {
font-family: sans-serif;
font-weight: normal;
font-size: 0.9em;
margin: 1px;
padding: 0;
}
h1 {
margin: 0;
text-align: left;
padding: 2px;
background-color: #f0c040;
color: black;
font-weight: bold;
font-size: 1.2em;
}
h2 {
background-color: #9B410E;
color: white;
text-align: left;
font-weight: bold;
padding: 2px;
border-top: 1px solid black;
}
body {
background: black;
}
p, table, div {
background: #f0ead8;
}
p {
margin: 0;
font-style: italic;
text-align: center;
}
table {
width: 100%;
}
th, td {
font-family: monospace;
vertical-align: top;
text-align: left;
width: 50%;
}
td {
color: green;
}
.odd {
background-color: #eeeeee;
}
.even {
background-color: #fafafa;
}
.exectime {
font-size: 0.8em;
font-style: italic;
}
#table_assigned_vars th {
color: blue;
}
#table_config_vars th {
color: maroon;
}
{/literal}
</style>
</head>
<body>
<h1>Smarty Debug Console - {if isset($template_name)}{$template_name|debug_print_var nofilter}{else}Total Time {$execution_time|string_format:"%.5f"}{/if}</h1>
{if !empty($template_data)}
<h2>included templates &amp; config files (load time in seconds)</h2>
<div>
{foreach $template_data as $template}
<font color=brown>{$template.name}</font>
<span class="exectime">
(compile {$template['compile_time']|string_format:"%.5f"}) (render {$template['render_time']|string_format:"%.5f"}) (cache {$template['cache_time']|string_format:"%.5f"})
</span>
<br>
{/foreach}
</div>
{/if}
<h2>assigned template variables</h2>
<table id="table_assigned_vars">
{foreach $assigned_vars as $vars}
<tr class="{if $vars@iteration % 2 eq 0}odd{else}even{/if}">
<th>${$vars@key|escape:'html'}</th>
<td>{$vars|debug_print_var nofilter}</td></tr>
{/foreach}
</table>
<h2>assigned config file variables (outer template scope)</h2>
<table id="table_config_vars">
{foreach $config_vars as $vars}
<tr class="{if $vars@iteration % 2 eq 0}odd{else}even{/if}">
<th>{$vars@key|escape:'html'}</th>
<td>{$vars|debug_print_var nofilter}</td></tr>
{/foreach}
</table>
</body>
</html>
{/capture}
<script type="text/javascript">
{$id = $template_name|default:''|md5}
_smarty_console = window.open("","console{$id}","width=680,height=600,resizable,scrollbars=yes");
_smarty_console.document.write("{$debug_output|escape:'javascript' nofilter}");
_smarty_console.document.close();
</script>

View File

@ -0,0 +1,113 @@
<?php
/**
* Smarty plugin to format text blocks
*
* @package Smarty
* @subpackage PluginsBlock
*/
/**
* Smarty {textformat}{/textformat} block plugin
*
* Type: block function<br>
* Name: textformat<br>
* Purpose: format text a certain way with preset styles
* or custom wrap/indent settings<br>
* Params:
* <pre>
* - style - string (email)
* - indent - integer (0)
* - wrap - integer (80)
* - wrap_char - string ("\n")
* - indent_char - string (" ")
* - wrap_boundary - boolean (true)
* </pre>
*
* @link http://www.smarty.net/manual/en/language.function.textformat.php {textformat}
* (Smarty online manual)
* @param array $params parameters
* @param string $content contents of the block
* @param Smarty_Internal_Template $template template object
* @param boolean &$repeat repeat flag
* @return string content re-formatted
* @author Monte Ohrt <monte at ohrt dot com>
*/
function smarty_block_textformat($params, $content, $template, &$repeat)
{
if (is_null($content)) {
return;
}
$style = null;
$indent = 0;
$indent_first = 0;
$indent_char = ' ';
$wrap = 80;
$wrap_char = "\n";
$wrap_cut = false;
$assign = null;
foreach ($params as $_key => $_val) {
switch ($_key) {
case 'style':
case 'indent_char':
case 'wrap_char':
case 'assign':
$$_key = (string)$_val;
break;
case 'indent':
case 'indent_first':
case 'wrap':
$$_key = (int)$_val;
break;
case 'wrap_cut':
$$_key = (bool)$_val;
break;
default:
trigger_error("textformat: unknown attribute '$_key'");
}
}
if ($style == 'email') {
$wrap = 72;
}
// split into paragraphs
$_paragraphs = preg_split('![\r\n]{2}!', $content);
$_output = '';
foreach ($_paragraphs as &$_paragraph) {
if (!$_paragraph) {
continue;
}
// convert mult. spaces & special chars to single space
$_paragraph = preg_replace(array('!\s+!' . Smarty::$_UTF8_MODIFIER, '!(^\s+)|(\s+$)!' . Smarty::$_UTF8_MODIFIER), array(' ', ''), $_paragraph);
// indent first line
if ($indent_first > 0) {
$_paragraph = str_repeat($indent_char, $indent_first) . $_paragraph;
}
// wordwrap sentences
if (Smarty::$_MBSTRING) {
require_once(SMARTY_PLUGINS_DIR . 'shared.mb_wordwrap.php');
$_paragraph = smarty_mb_wordwrap($_paragraph, $wrap - $indent, $wrap_char, $wrap_cut);
} else {
$_paragraph = wordwrap($_paragraph, $wrap - $indent, $wrap_char, $wrap_cut);
}
// indent lines
if ($indent > 0) {
$_paragraph = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraph);
}
}
$_output = implode($wrap_char . $wrap_char, $_paragraphs);
if ($assign) {
$template->assign($assign, $_output);
} else {
return $_output;
}
}
?>

View File

@ -0,0 +1,78 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {counter} function plugin
*
* Type: function<br>
* Name: counter<br>
* Purpose: print out a counter value
*
* @author Monte Ohrt <monte at ohrt dot com>
* @link http://www.smarty.net/manual/en/language.function.counter.php {counter}
* (Smarty online manual)
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
* @return string|null
*/
function smarty_function_counter($params, $template)
{
static $counters = array();
$name = (isset($params['name'])) ? $params['name'] : 'default';
if (!isset($counters[$name])) {
$counters[$name] = array(
'start'=>1,
'skip'=>1,
'direction'=>'up',
'count'=>1
);
}
$counter =& $counters[$name];
if (isset($params['start'])) {
$counter['start'] = $counter['count'] = (int)$params['start'];
}
if (!empty($params['assign'])) {
$counter['assign'] = $params['assign'];
}
if (isset($counter['assign'])) {
$template->assign($counter['assign'], $counter['count']);
}
if (isset($params['print'])) {
$print = (bool)$params['print'];
} else {
$print = empty($counter['assign']);
}
if ($print) {
$retval = $counter['count'];
} else {
$retval = null;
}
if (isset($params['skip'])) {
$counter['skip'] = $params['skip'];
}
if (isset($params['direction'])) {
$counter['direction'] = $params['direction'];
}
if ($counter['direction'] == "down")
$counter['count'] -= $counter['skip'];
else
$counter['count'] += $counter['skip'];
return $retval;
}
?>

View File

@ -0,0 +1,106 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {cycle} function plugin
*
* Type: function<br>
* Name: cycle<br>
* Date: May 3, 2002<br>
* Purpose: cycle through given values<br>
* Params:
* <pre>
* - name - name of cycle (optional)
* - values - comma separated list of values to cycle, or an array of values to cycle
* (this can be left out for subsequent calls)
* - reset - boolean - resets given var to true
* - print - boolean - print var or not. default is true
* - advance - boolean - whether or not to advance the cycle
* - delimiter - the value delimiter, default is ","
* - assign - boolean, assigns to template var instead of printed.
* </pre>
* Examples:<br>
* <pre>
* {cycle values="#eeeeee,#d0d0d0d"}
* {cycle name=row values="one,two,three" reset=true}
* {cycle name=row}
* </pre>
*
* @link http://www.smarty.net/manual/en/language.function.cycle.php {cycle}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @author credit to Mark Priatel <mpriatel@rogers.com>
* @author credit to Gerard <gerard@interfold.com>
* @author credit to Jason Sweat <jsweat_php@yahoo.com>
* @version 1.3
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
* @return string|null
*/
function smarty_function_cycle($params, $template)
{
static $cycle_vars;
$name = (empty($params['name'])) ? 'default' : $params['name'];
$print = (isset($params['print'])) ? (bool)$params['print'] : true;
$advance = (isset($params['advance'])) ? (bool)$params['advance'] : true;
$reset = (isset($params['reset'])) ? (bool)$params['reset'] : false;
if (!isset($params['values'])) {
if(!isset($cycle_vars[$name]['values'])) {
trigger_error("cycle: missing 'values' parameter");
return;
}
} else {
if(isset($cycle_vars[$name]['values'])
&& $cycle_vars[$name]['values'] != $params['values'] ) {
$cycle_vars[$name]['index'] = 0;
}
$cycle_vars[$name]['values'] = $params['values'];
}
if (isset($params['delimiter'])) {
$cycle_vars[$name]['delimiter'] = $params['delimiter'];
} elseif (!isset($cycle_vars[$name]['delimiter'])) {
$cycle_vars[$name]['delimiter'] = ',';
}
if(is_array($cycle_vars[$name]['values'])) {
$cycle_array = $cycle_vars[$name]['values'];
} else {
$cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']);
}
if(!isset($cycle_vars[$name]['index']) || $reset ) {
$cycle_vars[$name]['index'] = 0;
}
if (isset($params['assign'])) {
$print = false;
$template->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]);
}
if($print) {
$retval = $cycle_array[$cycle_vars[$name]['index']];
} else {
$retval = null;
}
if($advance) {
if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) {
$cycle_vars[$name]['index'] = 0;
} else {
$cycle_vars[$name]['index']++;
}
}
return $retval;
}
?>

View File

@ -0,0 +1,214 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {fetch} plugin
*
* Type: function<br>
* Name: fetch<br>
* Purpose: fetch file, web or ftp data and display results
*
* @link http://www.smarty.net/manual/en/language.function.fetch.php {fetch}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
* @return string|null if the assign parameter is passed, Smarty assigns the result to a template variable
*/
function smarty_function_fetch($params, $template)
{
if (empty($params['file'])) {
trigger_error("[plugin] fetch parameter 'file' cannot be empty",E_USER_NOTICE);
return;
}
// strip file protocol
if (stripos($params['file'], 'file://') === 0) {
$params['file'] = substr($params['file'], 7);
}
$protocol = strpos($params['file'], '://');
if ($protocol !== false) {
$protocol = strtolower(substr($params['file'], 0, $protocol));
}
if (isset($template->smarty->security_policy)) {
if ($protocol) {
// remote resource (or php stream, …)
if(!$template->smarty->security_policy->isTrustedUri($params['file'])) {
return;
}
} else {
// local file
if(!$template->smarty->security_policy->isTrustedResourceDir($params['file'])) {
return;
}
}
}
$content = '';
if ($protocol == 'http') {
// http fetch
if($uri_parts = parse_url($params['file'])) {
// set defaults
$host = $server_name = $uri_parts['host'];
$timeout = 30;
$accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*";
$agent = "Smarty Template Engine ". Smarty::SMARTY_VERSION;
$referer = "";
$uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/';
$uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : '';
$_is_proxy = false;
if(empty($uri_parts['port'])) {
$port = 80;
} else {
$port = $uri_parts['port'];
}
if(!empty($uri_parts['user'])) {
$user = $uri_parts['user'];
}
if(!empty($uri_parts['pass'])) {
$pass = $uri_parts['pass'];
}
// loop through parameters, setup headers
foreach($params as $param_key => $param_value) {
switch($param_key) {
case "file":
case "assign":
case "assign_headers":
break;
case "user":
if(!empty($param_value)) {
$user = $param_value;
}
break;
case "pass":
if(!empty($param_value)) {
$pass = $param_value;
}
break;
case "accept":
if(!empty($param_value)) {
$accept = $param_value;
}
break;
case "header":
if(!empty($param_value)) {
if(!preg_match('![\w\d-]+: .+!',$param_value)) {
trigger_error("[plugin] invalid header format '".$param_value."'",E_USER_NOTICE);
return;
} else {
$extra_headers[] = $param_value;
}
}
break;
case "proxy_host":
if(!empty($param_value)) {
$proxy_host = $param_value;
}
break;
case "proxy_port":
if(!preg_match('!\D!', $param_value)) {
$proxy_port = (int) $param_value;
} else {
trigger_error("[plugin] invalid value for attribute '".$param_key."'",E_USER_NOTICE);
return;
}
break;
case "agent":
if(!empty($param_value)) {
$agent = $param_value;
}
break;
case "referer":
if(!empty($param_value)) {
$referer = $param_value;
}
break;
case "timeout":
if(!preg_match('!\D!', $param_value)) {
$timeout = (int) $param_value;
} else {
trigger_error("[plugin] invalid value for attribute '".$param_key."'",E_USER_NOTICE);
return;
}
break;
default:
trigger_error("[plugin] unrecognized attribute '".$param_key."'",E_USER_NOTICE);
return;
}
}
if(!empty($proxy_host) && !empty($proxy_port)) {
$_is_proxy = true;
$fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout);
} else {
$fp = fsockopen($server_name,$port,$errno,$errstr,$timeout);
}
if(!$fp) {
trigger_error("[plugin] unable to fetch: $errstr ($errno)",E_USER_NOTICE);
return;
} else {
if($_is_proxy) {
fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n");
} else {
fputs($fp, "GET $uri HTTP/1.0\r\n");
}
if(!empty($host)) {
fputs($fp, "Host: $host\r\n");
}
if(!empty($accept)) {
fputs($fp, "Accept: $accept\r\n");
}
if(!empty($agent)) {
fputs($fp, "User-Agent: $agent\r\n");
}
if(!empty($referer)) {
fputs($fp, "Referer: $referer\r\n");
}
if(isset($extra_headers) && is_array($extra_headers)) {
foreach($extra_headers as $curr_header) {
fputs($fp, $curr_header."\r\n");
}
}
if(!empty($user) && !empty($pass)) {
fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n");
}
fputs($fp, "\r\n");
while(!feof($fp)) {
$content .= fgets($fp,4096);
}
fclose($fp);
$csplit = preg_split("!\r\n\r\n!",$content,2);
$content = $csplit[1];
if(!empty($params['assign_headers'])) {
$template->assign($params['assign_headers'],preg_split("!\r\n!",$csplit[0]));
}
}
} else {
trigger_error("[plugin fetch] unable to parse URL, check syntax",E_USER_NOTICE);
return;
}
} else {
$content = @file_get_contents($params['file']);
if ($content === false) {
throw new SmartyException("{fetch} cannot read resource '" . $params['file'] ."'");
}
}
if (!empty($params['assign'])) {
$template->assign($params['assign'], $content);
} else {
return $content;
}
}
?>

View File

@ -0,0 +1,233 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_checkboxes} function plugin
*
* File: function.html_checkboxes.php<br>
* Type: function<br>
* Name: html_checkboxes<br>
* Date: 24.Feb.2003<br>
* Purpose: Prints out a list of checkbox input types<br>
* Examples:
* <pre>
* {html_checkboxes values=$ids output=$names}
* {html_checkboxes values=$ids name='box' separator='<br>' output=$names}
* {html_checkboxes values=$ids checked=$checked separator='<br>' output=$names}
* </pre>
* Params:
* <pre>
* - name (optional) - string default "checkbox"
* - values (required) - array
* - options (optional) - associative array
* - checked (optional) - array default not set
* - separator (optional) - ie <br> or &nbsp;
* - output (optional) - the output next to each checkbox
* - assign (optional) - assign the output as an array to this variable
* - escape (optional) - escape the content (not value), defaults to true
* </pre>
*
* @link http://www.smarty.net/manual/en/language.function.html.checkboxes.php {html_checkboxes}
* (Smarty online manual)
* @author Christopher Kvarme <christopher.kvarme@flashjab.com>
* @author credits to Monte Ohrt <monte at ohrt dot com>
* @version 1.0
* @param array $params parameters
* @param object $template template object
* @return string
* @uses smarty_function_escape_special_chars()
*/
function smarty_function_html_checkboxes($params, $template)
{
require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
$name = 'checkbox';
$values = null;
$options = null;
$selected = array();
$separator = '';
$escape = true;
$labels = true;
$label_ids = false;
$output = null;
$extra = '';
foreach($params as $_key => $_val) {
switch($_key) {
case 'name':
case 'separator':
$$_key = (string) $_val;
break;
case 'escape':
case 'labels':
case 'label_ids':
$$_key = (bool) $_val;
break;
case 'options':
$$_key = (array) $_val;
break;
case 'values':
case 'output':
$$_key = array_values((array) $_val);
break;
case 'checked':
case 'selected':
if (is_array($_val)) {
$selected = array();
foreach ($_val as $_sel) {
if (is_object($_sel)) {
if (method_exists($_sel, "__toString")) {
$_sel = smarty_function_escape_special_chars((string) $_sel->__toString());
} else {
trigger_error("html_checkboxes: selected attribute contains an object of class '". get_class($_sel) ."' without __toString() method", E_USER_NOTICE);
continue;
}
} else {
$_sel = smarty_function_escape_special_chars((string) $_sel);
}
$selected[$_sel] = true;
}
} elseif (is_object($_val)) {
if (method_exists($_val, "__toString")) {
$selected = smarty_function_escape_special_chars((string) $_val->__toString());
} else {
trigger_error("html_checkboxes: selected attribute is an object of class '". get_class($_val) ."' without __toString() method", E_USER_NOTICE);
}
} else {
$selected = smarty_function_escape_special_chars((string) $_val);
}
break;
case 'checkboxes':
trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING);
$options = (array) $_val;
break;
case 'assign':
break;
case 'strict': break;
case 'disabled':
case 'readonly':
if (!empty($params['strict'])) {
if (!is_scalar($_val)) {
trigger_error("html_options: $_key attribute must be a scalar, only boolean true or string '$_key' will actually add the attribute", E_USER_NOTICE);
}
if ($_val === true || $_val === $_key) {
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_key) . '"';
}
break;
}
// omit break; to fall through!
default:
if(!is_array($_val)) {
$extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"';
} else {
trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
}
}
if (!isset($options) && !isset($values))
return ''; /* raise error here? */
$_html_result = array();
if (isset($options)) {
foreach ($options as $_key=>$_val) {
$_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids, $escape);
}
} else {
foreach ($values as $_i=>$_key) {
$_val = isset($output[$_i]) ? $output[$_i] : '';
$_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids, $escape);
}
}
if(!empty($params['assign'])) {
$template->assign($params['assign'], $_html_result);
} else {
return implode("\n", $_html_result);
}
}
function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels, $label_ids, $escape=true) {
$_output = '';
if (is_object($value)) {
if (method_exists($value, "__toString")) {
$value = (string) $value->__toString();
} else {
trigger_error("html_options: value is an object of class '". get_class($value) ."' without __toString() method", E_USER_NOTICE);
return '';
}
} else {
$value = (string) $value;
}
if (is_object($output)) {
if (method_exists($output, "__toString")) {
$output = (string) $output->__toString();
} else {
trigger_error("html_options: output is an object of class '". get_class($output) ."' without __toString() method", E_USER_NOTICE);
return '';
}
} else {
$output = (string) $output;
}
if ($labels) {
if ($label_ids) {
$_id = smarty_function_escape_special_chars(preg_replace('![^\w\-\.]!' . Smarty::$_UTF8_MODIFIER, '_', $name . '_' . $value));
$_output .= '<label for="' . $_id . '">';
} else {
$_output .= '<label>';
}
}
$name = smarty_function_escape_special_chars($name);
$value = smarty_function_escape_special_chars($value);
if ($escape) {
$output = smarty_function_escape_special_chars($output);
}
$_output .= '<input type="checkbox" name="' . $name . '[]" value="' . $value . '"';
if ($labels && $label_ids) {
$_output .= ' id="' . $_id . '"';
}
if (is_array($selected)) {
if (isset($selected[$value])) {
$_output .= ' checked="checked"';
}
} elseif ($value === $selected) {
$_output .= ' checked="checked"';
}
$_output .= $extra . ' />' . $output;
if ($labels) {
$_output .= '</label>';
}
$_output .= $separator;
return $_output;
}
?>

View File

@ -0,0 +1,159 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_image} function plugin
*
* Type: function<br>
* Name: html_image<br>
* Date: Feb 24, 2003<br>
* Purpose: format HTML tags for the image<br>
* Examples: {html_image file="/images/masthead.gif"}<br>
* Output: <img src="/images/masthead.gif" width=400 height=23><br>
* Params:
* <pre>
* - file - (required) - file (and path) of image
* - height - (optional) - image height (default actual height)
* - width - (optional) - image width (default actual width)
* - basedir - (optional) - base directory for absolute paths, default is environment variable DOCUMENT_ROOT
* - path_prefix - prefix for path output (optional, default empty)
* </pre>
*
* @link http://www.smarty.net/manual/en/language.function.html.image.php {html_image}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @author credits to Duda <duda@big.hu>
* @version 1.0
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
* @return string
* @uses smarty_function_escape_special_chars()
*/
function smarty_function_html_image($params, $template)
{
require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
$alt = '';
$file = '';
$height = '';
$width = '';
$extra = '';
$prefix = '';
$suffix = '';
$path_prefix = '';
$basedir = isset($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : '';
foreach($params as $_key => $_val) {
switch ($_key) {
case 'file':
case 'height':
case 'width':
case 'dpi':
case 'path_prefix':
case 'basedir':
$$_key = $_val;
break;
case 'alt':
if (!is_array($_val)) {
$$_key = smarty_function_escape_special_chars($_val);
} else {
throw new SmartyException ("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
case 'link':
case 'href':
$prefix = '<a href="' . $_val . '">';
$suffix = '</a>';
break;
default:
if (!is_array($_val)) {
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
} else {
throw new SmartyException ("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
}
}
if (empty($file)) {
trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE);
return;
}
if ($file[0] == '/') {
$_image_path = $basedir . $file;
} else {
$_image_path = $file;
}
// strip file protocol
if (stripos($params['file'], 'file://') === 0) {
$params['file'] = substr($params['file'], 7);
}
$protocol = strpos($params['file'], '://');
if ($protocol !== false) {
$protocol = strtolower(substr($params['file'], 0, $protocol));
}
if (isset($template->smarty->security_policy)) {
if ($protocol) {
// remote resource (or php stream, …)
if(!$template->smarty->security_policy->isTrustedUri($params['file'])) {
return;
}
} else {
// local file
if(!$template->smarty->security_policy->isTrustedResourceDir($params['file'])) {
return;
}
}
}
if (!isset($params['width']) || !isset($params['height'])) {
// FIXME: (rodneyrehm) getimagesize() loads the complete file off a remote resource, use custom [jpg,png,gif]header reader!
if (!$_image_data = @getimagesize($_image_path)) {
if (!file_exists($_image_path)) {
trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE);
return;
} else if (!is_readable($_image_path)) {
trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE);
return;
} else {
trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE);
return;
}
}
if (!isset($params['width'])) {
$width = $_image_data[0];
}
if (!isset($params['height'])) {
$height = $_image_data[1];
}
}
if (isset($params['dpi'])) {
if (strstr($_SERVER['HTTP_USER_AGENT'], 'Mac')) {
// FIXME: (rodneyrehm) wrong dpi assumption
// don't know who thought this up… even if it was true in 1998, it's definitely wrong in 2011.
$dpi_default = 72;
} else {
$dpi_default = 96;
}
$_resize = $dpi_default / $params['dpi'];
$width = round($width * $_resize);
$height = round($height * $_resize);
}
return $prefix . '<img src="' . $path_prefix . $file . '" alt="' . $alt . '" width="' . $width . '" height="' . $height . '"' . $extra . ' />' . $suffix;
}
?>

View File

@ -0,0 +1,193 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_options} function plugin
*
* Type: function<br>
* Name: html_options<br>
* Purpose: Prints the list of <option> tags generated from
* the passed parameters<br>
* Params:
* <pre>
* - name (optional) - string default "select"
* - values (required) - if no options supplied) - array
* - options (required) - if no values supplied) - associative array
* - selected (optional) - string default not set
* - output (required) - if not options supplied) - array
* - id (optional) - string default not set
* - class (optional) - string default not set
* </pre>
*
* @link http://www.smarty.net/manual/en/language.function.html.options.php {html_image}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @author Ralf Strehle (minor optimization) <ralf dot strehle at yahoo dot de>
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
* @return string
* @uses smarty_function_escape_special_chars()
*/
function smarty_function_html_options($params, $template)
{
require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
$name = null;
$values = null;
$options = null;
$selected = null;
$output = null;
$id = null;
$class = null;
$extra = '';
foreach ($params as $_key => $_val) {
switch ($_key) {
case 'name':
case 'class':
case 'id':
$$_key = (string) $_val;
break;
case 'options':
$options = (array) $_val;
break;
case 'values':
case 'output':
$$_key = array_values((array) $_val);
break;
case 'selected':
if (is_array($_val)) {
$selected = array();
foreach ($_val as $_sel) {
if (is_object($_sel)) {
if (method_exists($_sel, "__toString")) {
$_sel = smarty_function_escape_special_chars((string) $_sel->__toString());
} else {
trigger_error("html_options: selected attribute contains an object of class '". get_class($_sel) ."' without __toString() method", E_USER_NOTICE);
continue;
}
} else {
$_sel = smarty_function_escape_special_chars((string) $_sel);
}
$selected[$_sel] = true;
}
} elseif (is_object($_val)) {
if (method_exists($_val, "__toString")) {
$selected = smarty_function_escape_special_chars((string) $_val->__toString());
} else {
trigger_error("html_options: selected attribute is an object of class '". get_class($_val) ."' without __toString() method", E_USER_NOTICE);
}
} else {
$selected = smarty_function_escape_special_chars((string) $_val);
}
break;
case 'strict': break;
case 'disabled':
case 'readonly':
if (!empty($params['strict'])) {
if (!is_scalar($_val)) {
trigger_error("html_options: $_key attribute must be a scalar, only boolean true or string '$_key' will actually add the attribute", E_USER_NOTICE);
}
if ($_val === true || $_val === $_key) {
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_key) . '"';
}
break;
}
// omit break; to fall through!
default:
if (!is_array($_val)) {
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
} else {
trigger_error("html_options: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
}
}
if (!isset($options) && !isset($values)) {
/* raise error here? */
return '';
}
$_html_result = '';
$_idx = 0;
if (isset($options)) {
foreach ($options as $_key => $_val) {
$_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected, $id, $class, $_idx);
}
} else {
foreach ($values as $_i => $_key) {
$_val = isset($output[$_i]) ? $output[$_i] : '';
$_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected, $id, $class, $_idx);
}
}
if (!empty($name)) {
$_html_class = !empty($class) ? ' class="'.$class.'"' : '';
$_html_id = !empty($id) ? ' id="'.$id.'"' : '';
$_html_result = '<select name="' . $name . '"' . $_html_class . $_html_id . $extra . '>' . "\n" . $_html_result . '</select>' . "\n";
}
return $_html_result;
}
function smarty_function_html_options_optoutput($key, $value, $selected, $id, $class, &$idx)
{
if (!is_array($value)) {
$_key = smarty_function_escape_special_chars($key);
$_html_result = '<option value="' . $_key . '"';
if (is_array($selected)) {
if (isset($selected[$_key])) {
$_html_result .= ' selected="selected"';
}
} elseif ($_key === $selected) {
$_html_result .= ' selected="selected"';
}
$_html_class = !empty($class) ? ' class="'.$class.' option"' : '';
$_html_id = !empty($id) ? ' id="'.$id.'-'.$idx.'"' : '';
if (is_object($value)) {
if (method_exists($value, "__toString")) {
$value = smarty_function_escape_special_chars((string) $value->__toString());
} else {
trigger_error("html_options: value is an object of class '". get_class($value) ."' without __toString() method", E_USER_NOTICE);
return '';
}
} else {
$value = smarty_function_escape_special_chars((string) $value);
}
$_html_result .= $_html_class . $_html_id . '>' . $value . '</option>' . "\n";
$idx++;
} else {
$_idx = 0;
$_html_result = smarty_function_html_options_optgroup($key, $value, $selected, !empty($id) ? ($id.'-'.$idx) : null, $class, $_idx);
$idx++;
}
return $_html_result;
}
function smarty_function_html_options_optgroup($key, $values, $selected, $id, $class, &$idx)
{
$optgroup_html = '<optgroup label="' . smarty_function_escape_special_chars($key) . '">' . "\n";
foreach ($values as $key => $value) {
$optgroup_html .= smarty_function_html_options_optoutput($key, $value, $selected, $id, $class, $idx);
}
$optgroup_html .= "</optgroup>\n";
return $optgroup_html;
}
?>

View File

@ -0,0 +1,217 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_radios} function plugin
*
* File: function.html_radios.php<br>
* Type: function<br>
* Name: html_radios<br>
* Date: 24.Feb.2003<br>
* Purpose: Prints out a list of radio input types<br>
* Params:
* <pre>
* - name (optional) - string default "radio"
* - values (required) - array
* - options (required) - associative array
* - checked (optional) - array default not set
* - separator (optional) - ie <br> or &nbsp;
* - output (optional) - the output next to each radio button
* - assign (optional) - assign the output as an array to this variable
* - escape (optional) - escape the content (not value), defaults to true
* </pre>
* Examples:
* <pre>
* {html_radios values=$ids output=$names}
* {html_radios values=$ids name='box' separator='<br>' output=$names}
* {html_radios values=$ids checked=$checked separator='<br>' output=$names}
* </pre>
*
* @link http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios}
* (Smarty online manual)
* @author Christopher Kvarme <christopher.kvarme@flashjab.com>
* @author credits to Monte Ohrt <monte at ohrt dot com>
* @version 1.0
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
* @return string
* @uses smarty_function_escape_special_chars()
*/
function smarty_function_html_radios($params, $template)
{
require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
$name = 'radio';
$values = null;
$options = null;
$selected = null;
$separator = '';
$escape = true;
$labels = true;
$label_ids = false;
$output = null;
$extra = '';
foreach($params as $_key => $_val) {
switch ($_key) {
case 'name':
case 'separator':
$$_key = (string) $_val;
break;
case 'checked':
case 'selected':
if (is_array($_val)) {
trigger_error('html_radios: the "' . $_key . '" attribute cannot be an array', E_USER_WARNING);
} elseif (is_object($_val)) {
if (method_exists($_val, "__toString")) {
$selected = smarty_function_escape_special_chars((string) $_val->__toString());
} else {
trigger_error("html_radios: selected attribute is an object of class '". get_class($_val) ."' without __toString() method", E_USER_NOTICE);
}
} else {
$selected = (string) $_val;
}
break;
case 'escape':
case 'labels':
case 'label_ids':
$$_key = (bool) $_val;
break;
case 'options':
$$_key = (array) $_val;
break;
case 'values':
case 'output':
$$_key = array_values((array) $_val);
break;
case 'radios':
trigger_error('html_radios: the use of the "radios" attribute is deprecated, use "options" instead', E_USER_WARNING);
$options = (array) $_val;
break;
case 'assign':
break;
case 'strict': break;
case 'disabled':
case 'readonly':
if (!empty($params['strict'])) {
if (!is_scalar($_val)) {
trigger_error("html_options: $_key attribute must be a scalar, only boolean true or string '$_key' will actually add the attribute", E_USER_NOTICE);
}
if ($_val === true || $_val === $_key) {
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_key) . '"';
}
break;
}
// omit break; to fall through!
default:
if (!is_array($_val)) {
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
} else {
trigger_error("html_radios: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
}
}
if (!isset($options) && !isset($values)) {
/* raise error here? */
return '';
}
$_html_result = array();
if (isset($options)) {
foreach ($options as $_key => $_val) {
$_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids, $escape);
}
} else {
foreach ($values as $_i => $_key) {
$_val = isset($output[$_i]) ? $output[$_i] : '';
$_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids, $escape);
}
}
if (!empty($params['assign'])) {
$template->assign($params['assign'], $_html_result);
} else {
return implode("\n", $_html_result);
}
}
function smarty_function_html_radios_output($name, $value, $output, $selected, $extra, $separator, $labels, $label_ids, $escape)
{
$_output = '';
if (is_object($value)) {
if (method_exists($value, "__toString")) {
$value = (string) $value->__toString();
} else {
trigger_error("html_options: value is an object of class '". get_class($value) ."' without __toString() method", E_USER_NOTICE);
return '';
}
} else {
$value = (string) $value;
}
if (is_object($output)) {
if (method_exists($output, "__toString")) {
$output = (string) $output->__toString();
} else {
trigger_error("html_options: output is an object of class '". get_class($output) ."' without __toString() method", E_USER_NOTICE);
return '';
}
} else {
$output = (string) $output;
}
if ($labels) {
if ($label_ids) {
$_id = smarty_function_escape_special_chars(preg_replace('![^\w\-\.]!' . Smarty::$_UTF8_MODIFIER, '_', $name . '_' . $value));
$_output .= '<label for="' . $_id . '">';
} else {
$_output .= '<label>';
}
}
$name = smarty_function_escape_special_chars($name);
$value = smarty_function_escape_special_chars($value);
if ($escape) {
$output = smarty_function_escape_special_chars($output);
}
$_output .= '<input type="radio" name="' . $name . '" value="' . $value . '"';
if ($labels && $label_ids) {
$_output .= ' id="' . $_id . '"';
}
if ($value === $selected) {
$_output .= ' checked="checked"';
}
$_output .= $extra . ' />' . $output;
if ($labels) {
$_output .= '</label>';
}
$_output .= $separator;
return $_output;
}
?>

View File

@ -0,0 +1,394 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* @ignore
*/
require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
/**
* @ignore
*/
require_once(SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php');
/**
* Smarty {html_select_date} plugin
*
* Type: function<br>
* Name: html_select_date<br>
* Purpose: Prints the dropdowns for date selection.
*
* ChangeLog:
* <pre>
* - 1.0 initial release
* - 1.1 added support for +/- N syntax for begin
* and end year values. (Monte)
* - 1.2 added support for yyyy-mm-dd syntax for
* time value. (Jan Rosier)
* - 1.3 added support for choosing format for
* month values (Gary Loescher)
* - 1.3.1 added support for choosing format for
* day values (Marcus Bointon)
* - 1.3.2 support negative timestamps, force year
* dropdown to include given date unless explicitly set (Monte)
* - 1.3.4 fix behaviour of 0000-00-00 00:00:00 dates to match that
* of 0000-00-00 dates (cybot, boots)
* - 2.0 complete rewrite for performance,
* added attributes month_names, *_id
* </pre>
*
* @link http://www.smarty.net/manual/en/language.function.html.select.date.php {html_select_date}
* (Smarty online manual)
* @version 2.0
* @author Andrei Zmievski
* @author Monte Ohrt <monte at ohrt dot com>
* @author Rodney Rehm
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
* @return string
*/
function smarty_function_html_select_date($params, $template)
{
// generate timestamps used for month names only
static $_month_timestamps = null;
static $_current_year = null;
if ($_month_timestamps === null) {
$_current_year = date('Y');
$_month_timestamps = array();
for ($i = 1; $i <= 12; $i++) {
$_month_timestamps[$i] = mktime(0, 0, 0, $i, 1, 2000);
}
}
/* Default values. */
$prefix = "Date_";
$start_year = null;
$end_year = null;
$display_days = true;
$display_months = true;
$display_years = true;
$month_format = "%B";
/* Write months as numbers by default GL */
$month_value_format = "%m";
$day_format = "%02d";
/* Write day values using this format MB */
$day_value_format = "%d";
$year_as_text = false;
/* Display years in reverse order? Ie. 2000,1999,.... */
$reverse_years = false;
/* Should the select boxes be part of an array when returned from PHP?
e.g. setting it to "birthday", would create "birthday[Day]",
"birthday[Month]" & "birthday[Year]". Can be combined with prefix */
$field_array = null;
/* <select size>'s of the different <select> tags.
If not set, uses default dropdown. */
$day_size = null;
$month_size = null;
$year_size = null;
/* Unparsed attributes common to *ALL* the <select>/<input> tags.
An example might be in the template: all_extra ='class ="foo"'. */
$all_extra = null;
/* Separate attributes for the tags. */
$day_extra = null;
$month_extra = null;
$year_extra = null;
/* Order in which to display the fields.
"D" -> day, "M" -> month, "Y" -> year. */
$field_order = 'MDY';
/* String printed between the different fields. */
$field_separator = "\n";
$option_separator = "\n";
$time = null;
// $all_empty = null;
// $day_empty = null;
// $month_empty = null;
// $year_empty = null;
$extra_attrs = '';
$all_id = null;
$day_id = null;
$month_id = null;
$year_id = null;
foreach ($params as $_key => $_value) {
switch ($_key) {
case 'time':
if (!is_array($_value) && $_value !== null) {
$time = smarty_make_timestamp($_value);
}
break;
case 'month_names':
if (is_array($_value) && count($_value) == 12) {
$$_key = $_value;
} else {
trigger_error("html_select_date: month_names must be an array of 12 strings", E_USER_NOTICE);
}
break;
case 'prefix':
case 'field_array':
case 'start_year':
case 'end_year':
case 'day_format':
case 'day_value_format':
case 'month_format':
case 'month_value_format':
case 'day_size':
case 'month_size':
case 'year_size':
case 'all_extra':
case 'day_extra':
case 'month_extra':
case 'year_extra':
case 'field_order':
case 'field_separator':
case 'option_separator':
case 'all_empty':
case 'month_empty':
case 'day_empty':
case 'year_empty':
case 'all_id':
case 'month_id':
case 'day_id':
case 'year_id':
$$_key = (string)$_value;
break;
case 'display_days':
case 'display_months':
case 'display_years':
case 'year_as_text':
case 'reverse_years':
$$_key = (bool)$_value;
break;
default:
if (!is_array($_value)) {
$extra_attrs .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_value) . '"';
} else {
trigger_error("html_select_date: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
}
}
// Note: date() is faster than strftime()
// Note: explode(date()) is faster than date() date() date()
if (isset($params['time']) && is_array($params['time'])) {
if (isset($params['time'][$prefix . 'Year'])) {
// $_REQUEST[$field_array] given
foreach (array('Y' => 'Year', 'm' => 'Month', 'd' => 'Day') as $_elementKey => $_elementName) {
$_variableName = '_' . strtolower($_elementName);
$$_variableName = isset($params['time'][$prefix . $_elementName])
? $params['time'][$prefix . $_elementName]
: date($_elementKey);
}
$time = mktime(0, 0, 0, $_month, $_day, $_year);
} elseif (isset($params['time'][$field_array][$prefix . 'Year'])) {
// $_REQUEST given
foreach (array('Y' => 'Year', 'm' => 'Month', 'd' => 'Day') as $_elementKey => $_elementName) {
$_variableName = '_' . strtolower($_elementName);
$$_variableName = isset($params['time'][$field_array][$prefix . $_elementName])
? $params['time'][$field_array][$prefix . $_elementName]
: date($_elementKey);
}
$time = mktime(0, 0, 0, $_month, $_day, $_year);
} else {
// no date found, use NOW
list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d'));
}
} elseif ($time === null) {
if (array_key_exists('time', $params)) {
$_year = $_month = $_day = $time = null;
} else {
list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d'));
}
} else {
list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d', $time));
}
// make syntax "+N" or "-N" work with $start_year and $end_year
// Note preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match) is slower than trim+substr
foreach (array('start', 'end') as $key) {
$key .= '_year';
$t = $$key;
if ($t === null) {
$$key = (int)$_current_year;
} else if ($t[0] == '+') {
$$key = (int)($_current_year + trim(substr($t, 1)));
} else if ($t[0] == '-') {
$$key = (int)($_current_year - trim(substr($t, 1)));
} else {
$$key = (int)$$key;
}
}
// flip for ascending or descending
if (($start_year > $end_year && !$reverse_years) || ($start_year < $end_year && $reverse_years)) {
$t = $end_year;
$end_year = $start_year;
$start_year = $t;
}
// generate year <select> or <input>
if ($display_years) {
$_html_years = '';
$_extra = '';
$_name = $field_array ? ($field_array . '[' . $prefix . 'Year]') : ($prefix . 'Year');
if ($all_extra) {
$_extra .= ' ' . $all_extra;
}
if ($year_extra) {
$_extra .= ' ' . $year_extra;
}
if ($year_as_text) {
$_html_years = '<input type="text" name="' . $_name . '" value="' . $_year . '" size="4" maxlength="4"' . $_extra . $extra_attrs . ' />';
} else {
$_html_years = '<select name="' . $_name . '"';
if ($year_id !== null || $all_id !== null) {
$_html_years .= ' id="' . smarty_function_escape_special_chars(
$year_id !== null ? ( $year_id ? $year_id : $_name ) : ( $all_id ? ($all_id . $_name) : $_name )
) . '"';
}
if ($year_size) {
$_html_years .= ' size="' . $year_size . '"';
}
$_html_years .= $_extra . $extra_attrs . '>' . $option_separator;
if (isset($year_empty) || isset($all_empty)) {
$_html_years .= '<option value="">' . ( isset($year_empty) ? $year_empty : $all_empty ) . '</option>' . $option_separator;
}
$op = $start_year > $end_year ? -1 : 1;
for ($i=$start_year; $op > 0 ? $i <= $end_year : $i >= $end_year; $i += $op) {
$_html_years .= '<option value="' . $i . '"'
. ($_year == $i ? ' selected="selected"' : '')
. '>' . $i . '</option>' . $option_separator;
}
$_html_years .= '</select>';
}
}
// generate month <select> or <input>
if ($display_months) {
$_html_month = '';
$_extra = '';
$_name = $field_array ? ($field_array . '[' . $prefix . 'Month]') : ($prefix . 'Month');
if ($all_extra) {
$_extra .= ' ' . $all_extra;
}
if ($month_extra) {
$_extra .= ' ' . $month_extra;
}
$_html_months = '<select name="' . $_name . '"';
if ($month_id !== null || $all_id !== null) {
$_html_months .= ' id="' . smarty_function_escape_special_chars(
$month_id !== null ? ( $month_id ? $month_id : $_name ) : ( $all_id ? ($all_id . $_name) : $_name )
) . '"';
}
if ($month_size) {
$_html_months .= ' size="' . $month_size . '"';
}
$_html_months .= $_extra . $extra_attrs . '>' . $option_separator;
if (isset($month_empty) || isset($all_empty)) {
$_html_months .= '<option value="">' . ( isset($month_empty) ? $month_empty : $all_empty ) . '</option>' . $option_separator;
}
for ($i = 1; $i <= 12; $i++) {
$_val = sprintf('%02d', $i);
$_text = isset($month_names) ? smarty_function_escape_special_chars($month_names[$i]) : ($month_format == "%m" ? $_val : strftime($month_format, $_month_timestamps[$i]));
$_value = $month_value_format == "%m" ? $_val : strftime($month_value_format, $_month_timestamps[$i]);
$_html_months .= '<option value="' . $_value . '"'
. ($_val == $_month ? ' selected="selected"' : '')
. '>' . $_text . '</option>' . $option_separator;
}
$_html_months .= '</select>';
}
// generate day <select> or <input>
if ($display_days) {
$_html_day = '';
$_extra = '';
$_name = $field_array ? ($field_array . '[' . $prefix . 'Day]') : ($prefix . 'Day');
if ($all_extra) {
$_extra .= ' ' . $all_extra;
}
if ($day_extra) {
$_extra .= ' ' . $day_extra;
}
$_html_days = '<select name="' . $_name . '"';
if ($day_id !== null || $all_id !== null) {
$_html_days .= ' id="' . smarty_function_escape_special_chars(
$day_id !== null ? ( $day_id ? $day_id : $_name ) : ( $all_id ? ($all_id . $_name) : $_name )
) . '"';
}
if ($day_size) {
$_html_days .= ' size="' . $day_size . '"';
}
$_html_days .= $_extra . $extra_attrs . '>' . $option_separator;
if (isset($day_empty) || isset($all_empty)) {
$_html_days .= '<option value="">' . ( isset($day_empty) ? $day_empty : $all_empty ) . '</option>' . $option_separator;
}
for ($i = 1; $i <= 31; $i++) {
$_val = sprintf('%02d', $i);
$_text = $day_format == '%02d' ? $_val : sprintf($day_format, $i);
$_value = $day_value_format == '%02d' ? $_val : sprintf($day_value_format, $i);
$_html_days .= '<option value="' . $_value . '"'
. ($_val == $_day ? ' selected="selected"' : '')
. '>' . $_text . '</option>' . $option_separator;
}
$_html_days .= '</select>';
}
// order the fields for output
$_html = '';
for ($i=0; $i <= 2; $i++) {
switch ($field_order[$i]) {
case 'Y':
case 'y':
if (isset($_html_years)) {
if ($_html) {
$_html .= $field_separator;
}
$_html .= $_html_years;
}
break;
case 'm':
case 'M':
if (isset($_html_months)) {
if ($_html) {
$_html .= $field_separator;
}
$_html .= $_html_months;
}
break;
case 'd':
case 'D':
if (isset($_html_days)) {
if ($_html) {
$_html .= $field_separator;
}
$_html .= $_html_days;
}
break;
}
}
return $_html;
}
?>

View File

@ -0,0 +1,366 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* @ignore
*/
require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
/**
* @ignore
*/
require_once(SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php');
/**
* Smarty {html_select_time} function plugin
*
* Type: function<br>
* Name: html_select_time<br>
* Purpose: Prints the dropdowns for time selection
*
* @link http://www.smarty.net/manual/en/language.function.html.select.time.php {html_select_time}
* (Smarty online manual)
* @author Roberto Berto <roberto@berto.net>
* @author Monte Ohrt <monte AT ohrt DOT com>
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
* @return string
* @uses smarty_make_timestamp()
*/
function smarty_function_html_select_time($params, $template)
{
$prefix = "Time_";
$field_array = null;
$field_separator = "\n";
$option_separator = "\n";
$time = null;
$display_hours = true;
$display_minutes = true;
$display_seconds = true;
$display_meridian = true;
$hour_format = '%02d';
$hour_value_format = '%02d';
$minute_format = '%02d';
$minute_value_format = '%02d';
$second_format = '%02d';
$second_value_format = '%02d';
$hour_size = null;
$minute_size = null;
$second_size = null;
$meridian_size = null;
$all_empty = null;
$hour_empty = null;
$minute_empty = null;
$second_empty = null;
$meridian_empty = null;
$all_id = null;
$hour_id = null;
$minute_id = null;
$second_id = null;
$meridian_id = null;
$use_24_hours = true;
$minute_interval = 1;
$second_interval = 1;
$extra_attrs = '';
$all_extra = null;
$hour_extra = null;
$minute_extra = null;
$second_extra = null;
$meridian_extra = null;
foreach ($params as $_key => $_value) {
switch ($_key) {
case 'time':
if (!is_array($_value) && $_value !== null) {
$time = smarty_make_timestamp($_value);
}
break;
case 'prefix':
case 'field_array':
case 'field_separator':
case 'option_separator':
case 'all_extra':
case 'hour_extra':
case 'minute_extra':
case 'second_extra':
case 'meridian_extra':
case 'all_empty':
case 'hour_empty':
case 'minute_empty':
case 'second_empty':
case 'meridian_empty':
case 'all_id':
case 'hour_id':
case 'minute_id':
case 'second_id':
case 'meridian_id':
case 'hour_format':
case 'hour_value_format':
case 'minute_format':
case 'minute_value_format':
case 'second_format':
case 'second_value_format':
$$_key = (string)$_value;
break;
case 'display_hours':
case 'display_minutes':
case 'display_seconds':
case 'display_meridian':
case 'use_24_hours':
$$_key = (bool)$_value;
break;
case 'minute_interval':
case 'second_interval':
case 'hour_size':
case 'minute_size':
case 'second_size':
case 'meridian_size':
$$_key = (int)$_value;
break;
default:
if (!is_array($_value)) {
$extra_attrs .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_value) . '"';
} else {
trigger_error("html_select_date: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
}
break;
}
}
if (isset($params['time']) && is_array($params['time'])) {
if (isset($params['time'][$prefix . 'Hour'])) {
// $_REQUEST[$field_array] given
foreach (array('H' => 'Hour', 'i' => 'Minute', 's' => 'Second') as $_elementKey => $_elementName) {
$_variableName = '_' . strtolower($_elementName);
$$_variableName = isset($params['time'][$prefix . $_elementName])
? $params['time'][$prefix . $_elementName]
: date($_elementKey);
}
$_meridian = isset($params['time'][$prefix . 'Meridian'])
? (' ' . $params['time'][$prefix . 'Meridian'])
: '';
$time = strtotime( $_hour . ':' . $_minute . ':' . $_second . $_meridian );
list($_hour, $_minute, $_second) = $time = explode('-', date('H-i-s', $time));
} elseif (isset($params['time'][$field_array][$prefix . 'Hour'])) {
// $_REQUEST given
foreach (array('H' => 'Hour', 'i' => 'Minute', 's' => 'Second') as $_elementKey => $_elementName) {
$_variableName = '_' . strtolower($_elementName);
$$_variableName = isset($params['time'][$field_array][$prefix . $_elementName])
? $params['time'][$field_array][$prefix . $_elementName]
: date($_elementKey);
}
$_meridian = isset($params['time'][$field_array][$prefix . 'Meridian'])
? (' ' . $params['time'][$field_array][$prefix . 'Meridian'])
: '';
$time = strtotime( $_hour . ':' . $_minute . ':' . $_second . $_meridian );
list($_hour, $_minute, $_second) = $time = explode('-', date('H-i-s', $time));
} else {
// no date found, use NOW
list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d'));
}
} elseif ($time === null) {
if (array_key_exists('time', $params)) {
$_hour = $_minute = $_second = $time = null;
} else {
list($_hour, $_minute, $_second) = $time = explode('-', date('H-i-s'));
}
} else {
list($_hour, $_minute, $_second) = $time = explode('-', date('H-i-s', $time));
}
// generate hour <select>
if ($display_hours) {
$_html_hours = '';
$_extra = '';
$_name = $field_array ? ($field_array . '[' . $prefix . 'Hour]') : ($prefix . 'Hour');
if ($all_extra) {
$_extra .= ' ' . $all_extra;
}
if ($hour_extra) {
$_extra .= ' ' . $hour_extra;
}
$_html_hours = '<select name="' . $_name . '"';
if ($hour_id !== null || $all_id !== null) {
$_html_hours .= ' id="' . smarty_function_escape_special_chars(
$hour_id !== null ? ( $hour_id ? $hour_id : $_name ) : ( $all_id ? ($all_id . $_name) : $_name )
) . '"';
}
if ($hour_size) {
$_html_hours .= ' size="' . $hour_size . '"';
}
$_html_hours .= $_extra . $extra_attrs . '>' . $option_separator;
if (isset($hour_empty) || isset($all_empty)) {
$_html_hours .= '<option value="">' . ( isset($hour_empty) ? $hour_empty : $all_empty ) . '</option>' . $option_separator;
}
$start = $use_24_hours ? 0 : 1;
$end = $use_24_hours ? 23 : 12;
for ($i=$start; $i <= $end; $i++) {
$_val = sprintf('%02d', $i);
$_text = $hour_format == '%02d' ? $_val : sprintf($hour_format, $i);
$_value = $hour_value_format == '%02d' ? $_val : sprintf($hour_value_format, $i);
if (!$use_24_hours) {
$_hour12 = $_hour == 0
? 12
: ($_hour <= 12 ? $_hour : $_hour -12);
}
$selected = $_hour !== null ? ($use_24_hours ? $_hour == $_val : $_hour12 == $_val) : null;
$_html_hours .= '<option value="' . $_value . '"'
. ($selected ? ' selected="selected"' : '')
. '>' . $_text . '</option>' . $option_separator;
}
$_html_hours .= '</select>';
}
// generate minute <select>
if ($display_minutes) {
$_html_minutes = '';
$_extra = '';
$_name = $field_array ? ($field_array . '[' . $prefix . 'Minute]') : ($prefix . 'Minute');
if ($all_extra) {
$_extra .= ' ' . $all_extra;
}
if ($minute_extra) {
$_extra .= ' ' . $minute_extra;
}
$_html_minutes = '<select name="' . $_name . '"';
if ($minute_id !== null || $all_id !== null) {
$_html_minutes .= ' id="' . smarty_function_escape_special_chars(
$minute_id !== null ? ( $minute_id ? $minute_id : $_name ) : ( $all_id ? ($all_id . $_name) : $_name )
) . '"';
}
if ($minute_size) {
$_html_minutes .= ' size="' . $minute_size . '"';
}
$_html_minutes .= $_extra . $extra_attrs . '>' . $option_separator;
if (isset($minute_empty) || isset($all_empty)) {
$_html_minutes .= '<option value="">' . ( isset($minute_empty) ? $minute_empty : $all_empty ) . '</option>' . $option_separator;
}
$selected = $_minute !== null ? ($_minute - $_minute % $minute_interval) : null;
for ($i=0; $i <= 59; $i += $minute_interval) {
$_val = sprintf('%02d', $i);
$_text = $minute_format == '%02d' ? $_val : sprintf($minute_format, $i);
$_value = $minute_value_format == '%02d' ? $_val : sprintf($minute_value_format, $i);
$_html_minutes .= '<option value="' . $_value . '"'
. ($selected === $i ? ' selected="selected"' : '')
. '>' . $_text . '</option>' . $option_separator;
}
$_html_minutes .= '</select>';
}
// generate second <select>
if ($display_seconds) {
$_html_seconds = '';
$_extra = '';
$_name = $field_array ? ($field_array . '[' . $prefix . 'Second]') : ($prefix . 'Second');
if ($all_extra) {
$_extra .= ' ' . $all_extra;
}
if ($second_extra) {
$_extra .= ' ' . $second_extra;
}
$_html_seconds = '<select name="' . $_name . '"';
if ($second_id !== null || $all_id !== null) {
$_html_seconds .= ' id="' . smarty_function_escape_special_chars(
$second_id !== null ? ( $second_id ? $second_id : $_name ) : ( $all_id ? ($all_id . $_name) : $_name )
) . '"';
}
if ($second_size) {
$_html_seconds .= ' size="' . $second_size . '"';
}
$_html_seconds .= $_extra . $extra_attrs . '>' . $option_separator;
if (isset($second_empty) || isset($all_empty)) {
$_html_seconds .= '<option value="">' . ( isset($second_empty) ? $second_empty : $all_empty ) . '</option>' . $option_separator;
}
$selected = $_second !== null ? ($_second - $_second % $second_interval) : null;
for ($i=0; $i <= 59; $i += $second_interval) {
$_val = sprintf('%02d', $i);
$_text = $second_format == '%02d' ? $_val : sprintf($second_format, $i);
$_value = $second_value_format == '%02d' ? $_val : sprintf($second_value_format, $i);
$_html_seconds .= '<option value="' . $_value . '"'
. ($selected === $i ? ' selected="selected"' : '')
. '>' . $_text . '</option>' . $option_separator;
}
$_html_seconds .= '</select>';
}
// generate meridian <select>
if ($display_meridian && !$use_24_hours) {
$_html_meridian = '';
$_extra = '';
$_name = $field_array ? ($field_array . '[' . $prefix . 'Meridian]') : ($prefix . 'Meridian');
if ($all_extra) {
$_extra .= ' ' . $all_extra;
}
if ($meridian_extra) {
$_extra .= ' ' . $meridian_extra;
}
$_html_meridian = '<select name="' . $_name . '"';
if ($meridian_id !== null || $all_id !== null) {
$_html_meridian .= ' id="' . smarty_function_escape_special_chars(
$meridian_id !== null ? ( $meridian_id ? $meridian_id : $_name ) : ( $all_id ? ($all_id . $_name) : $_name )
) . '"';
}
if ($meridian_size) {
$_html_meridian .= ' size="' . $meridian_size . '"';
}
$_html_meridian .= $_extra . $extra_attrs . '>' . $option_separator;
if (isset($meridian_empty) || isset($all_empty)) {
$_html_meridian .= '<option value="">' . ( isset($meridian_empty) ? $meridian_empty : $all_empty ) . '</option>' . $option_separator;
}
$_html_meridian .= '<option value="am"'. ($_hour < 12 ? ' selected="selected"' : '') .'>AM</option>' . $option_separator
. '<option value="pm"'. ($_hour < 12 ? '' : ' selected="selected"') .'>PM</option>' . $option_separator
. '</select>';
}
$_html = '';
foreach (array('_html_hours', '_html_minutes', '_html_seconds', '_html_meridian') as $k) {
if (isset($$k)) {
if ($_html) {
$_html .= $field_separator;
}
$_html .= $$k;
}
}
return $_html;
}
?>

View File

@ -0,0 +1,177 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_table} function plugin
*
* Type: function<br>
* Name: html_table<br>
* Date: Feb 17, 2003<br>
* Purpose: make an html table from an array of data<br>
* Params:
* <pre>
* - loop - array to loop through
* - cols - number of columns, comma separated list of column names
* or array of column names
* - rows - number of rows
* - table_attr - table attributes
* - th_attr - table heading attributes (arrays are cycled)
* - tr_attr - table row attributes (arrays are cycled)
* - td_attr - table cell attributes (arrays are cycled)
* - trailpad - value to pad trailing cells with
* - caption - text for caption element
* - vdir - vertical direction (default: "down", means top-to-bottom)
* - hdir - horizontal direction (default: "right", means left-to-right)
* - inner - inner loop (default "cols": print $loop line by line,
* $loop will be printed column by column otherwise)
* </pre>
* Examples:
* <pre>
* {table loop=$data}
* {table loop=$data cols=4 tr_attr='"bgcolor=red"'}
* {table loop=$data cols="first,second,third" tr_attr=$colors}
* </pre>
*
* @author Monte Ohrt <monte at ohrt dot com>
* @author credit to Messju Mohr <messju at lammfellpuschen dot de>
* @author credit to boots <boots dot smarty at yahoo dot com>
* @version 1.1
* @link http://www.smarty.net/manual/en/language.function.html.table.php {html_table}
* (Smarty online manual)
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
* @return string
*/
function smarty_function_html_table($params, $template)
{
$table_attr = 'border="1"';
$tr_attr = '';
$th_attr = '';
$td_attr = '';
$cols = $cols_count = 3;
$rows = 3;
$trailpad = '&nbsp;';
$vdir = 'down';
$hdir = 'right';
$inner = 'cols';
$caption = '';
$loop = null;
if (!isset($params['loop'])) {
trigger_error("html_table: missing 'loop' parameter",E_USER_WARNING);
return;
}
foreach ($params as $_key => $_value) {
switch ($_key) {
case 'loop':
$$_key = (array)$_value;
break;
case 'cols':
if (is_array($_value) && !empty($_value)) {
$cols = $_value;
$cols_count = count($_value);
} elseif (!is_numeric($_value) && is_string($_value) && !empty($_value)) {
$cols = explode(',', $_value);
$cols_count = count($cols);
} elseif (!empty($_value)) {
$cols_count = (int)$_value;
} else {
$cols_count = $cols;
}
break;
case 'rows':
$$_key = (int)$_value;
break;
case 'table_attr':
case 'trailpad':
case 'hdir':
case 'vdir':
case 'inner':
case 'caption':
$$_key = (string)$_value;
break;
case 'tr_attr':
case 'td_attr':
case 'th_attr':
$$_key = $_value;
break;
}
}
$loop_count = count($loop);
if (empty($params['rows'])) {
/* no rows specified */
$rows = ceil($loop_count / $cols_count);
} elseif (empty($params['cols'])) {
if (!empty($params['rows'])) {
/* no cols specified, but rows */
$cols_count = ceil($loop_count / $rows);
}
}
$output = "<table $table_attr>\n";
if (!empty($caption)) {
$output .= '<caption>' . $caption . "</caption>\n";
}
if (is_array($cols)) {
$cols = ($hdir == 'right') ? $cols : array_reverse($cols);
$output .= "<thead><tr>\n";
for ($r = 0; $r < $cols_count; $r++) {
$output .= '<th' . smarty_function_html_table_cycle('th', $th_attr, $r) . '>';
$output .= $cols[$r];
$output .= "</th>\n";
}
$output .= "</tr></thead>\n";
}
$output .= "<tbody>\n";
for ($r = 0; $r < $rows; $r++) {
$output .= "<tr" . smarty_function_html_table_cycle('tr', $tr_attr, $r) . ">\n";
$rx = ($vdir == 'down') ? $r * $cols_count : ($rows-1 - $r) * $cols_count;
for ($c = 0; $c < $cols_count; $c++) {
$x = ($hdir == 'right') ? $rx + $c : $rx + $cols_count-1 - $c;
if ($inner != 'cols') {
/* shuffle x to loop over rows*/
$x = floor($x / $cols_count) + ($x % $cols_count) * $rows;
}
if ($x < $loop_count) {
$output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">" . $loop[$x] . "</td>\n";
} else {
$output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">$trailpad</td>\n";
}
}
$output .= "</tr>\n";
}
$output .= "</tbody>\n";
$output .= "</table>\n";
return $output;
}
function smarty_function_html_table_cycle($name, $var, $no)
{
if (!is_array($var)) {
$ret = $var;
} else {
$ret = $var[$no % count($var)];
}
return ($ret) ? ' ' . $ret : '';
}
?>

View File

@ -0,0 +1,152 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {mailto} function plugin
*
* Type: function<br>
* Name: mailto<br>
* Date: May 21, 2002
* Purpose: automate mailto address link creation, and optionally encode them.<br>
* Params:
* <pre>
* - address - (required) - e-mail address
* - text - (optional) - text to display, default is address
* - encode - (optional) - can be one of:
* * none : no encoding (default)
* * javascript : encode with javascript
* * javascript_charcode : encode with javascript charcode
* * hex : encode with hexidecimal (no javascript)
* - cc - (optional) - address(es) to carbon copy
* - bcc - (optional) - address(es) to blind carbon copy
* - subject - (optional) - e-mail subject
* - newsgroups - (optional) - newsgroup(s) to post to
* - followupto - (optional) - address(es) to follow up to
* - extra - (optional) - extra tags for the href link
* </pre>
* Examples:
* <pre>
* {mailto address="me@domain.com"}
* {mailto address="me@domain.com" encode="javascript"}
* {mailto address="me@domain.com" encode="hex"}
* {mailto address="me@domain.com" subject="Hello to you!"}
* {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"}
* {mailto address="me@domain.com" extra='class="mailto"'}
* </pre>
*
* @link http://www.smarty.net/manual/en/language.function.mailto.php {mailto}
* (Smarty online manual)
* @version 1.2
* @author Monte Ohrt <monte at ohrt dot com>
* @author credits to Jason Sweat (added cc, bcc and subject functionality)
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
* @return string
*/
function smarty_function_mailto($params, $template)
{
static $_allowed_encoding = array('javascript' => true, 'javascript_charcode' => true, 'hex' => true, 'none' => true);
$extra = '';
if (empty($params['address'])) {
trigger_error("mailto: missing 'address' parameter",E_USER_WARNING);
return;
} else {
$address = $params['address'];
}
$text = $address;
// netscape and mozilla do not decode %40 (@) in BCC field (bug?)
// so, don't encode it.
$search = array('%40', '%2C');
$replace = array('@', ',');
$mail_parms = array();
foreach ($params as $var => $value) {
switch ($var) {
case 'cc':
case 'bcc':
case 'followupto':
if (!empty($value))
$mail_parms[] = $var . '=' . str_replace($search, $replace, rawurlencode($value));
break;
case 'subject':
case 'newsgroups':
$mail_parms[] = $var . '=' . rawurlencode($value);
break;
case 'extra':
case 'text':
$$var = $value;
default:
}
}
if ($mail_parms) {
$address .= '?' . join('&', $mail_parms);
}
$encode = (empty($params['encode'])) ? 'none' : $params['encode'];
if (!isset($_allowed_encoding[$encode])) {
trigger_error("mailto: 'encode' parameter must be none, javascript, javascript_charcode or hex", E_USER_WARNING);
return;
}
// FIXME: (rodneyrehm) document.write() excues me what? 1998 has passed!
if ($encode == 'javascript') {
$string = 'document.write(\'<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>\');';
$js_encode = '';
for ($x = 0, $_length = strlen($string); $x < $_length; $x++) {
$js_encode .= '%' . bin2hex($string[$x]);
}
return '<script type="text/javascript">eval(unescape(\'' . $js_encode . '\'))</script>';
} elseif ($encode == 'javascript_charcode') {
$string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
for($x = 0, $y = strlen($string); $x < $y; $x++) {
$ord[] = ord($string[$x]);
}
$_ret = "<script type=\"text/javascript\" language=\"javascript\">\n"
. "{document.write(String.fromCharCode("
. implode(',', $ord)
. "))"
. "}\n"
. "</script>\n";
return $_ret;
} elseif ($encode == 'hex') {
preg_match('!^(.*)(\?.*)$!', $address, $match);
if (!empty($match[2])) {
trigger_error("mailto: hex encoding does not work with extra attributes. Try javascript.",E_USER_WARNING);
return;
}
$address_encode = '';
for ($x = 0, $_length = strlen($address); $x < $_length; $x++) {
if (preg_match('!\w!' . Smarty::$_UTF8_MODIFIER, $address[$x])) {
$address_encode .= '%' . bin2hex($address[$x]);
} else {
$address_encode .= $address[$x];
}
}
$text_encode = '';
for ($x = 0, $_length = strlen($text); $x < $_length; $x++) {
$text_encode .= '&#x' . bin2hex($text[$x]) . ';';
}
$mailto = "&#109;&#97;&#105;&#108;&#116;&#111;&#58;";
return '<a href="' . $mailto . $address_encode . '" ' . $extra . '>' . $text_encode . '</a>';
} else {
// no encoding
return '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
}
}
?>

View File

@ -0,0 +1,87 @@
<?php
/**
* Smarty plugin
*
* This plugin is only for Smarty2 BC
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {math} function plugin
*
* Type: function<br>
* Name: math<br>
* Purpose: handle math computations in template
*
* @link http://www.smarty.net/manual/en/language.function.math.php {math}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
* @return string|null
*/
function smarty_function_math($params, $template)
{
static $_allowed_funcs = array(
'int' => true, 'abs' => true, 'ceil' => true, 'cos' => true, 'exp' => true, 'floor' => true,
'log' => true, 'log10' => true, 'max' => true, 'min' => true, 'pi' => true, 'pow' => true,
'rand' => true, 'round' => true, 'sin' => true, 'sqrt' => true, 'srand' => true ,'tan' => true
);
// be sure equation parameter is present
if (empty($params['equation'])) {
trigger_error("math: missing equation parameter",E_USER_WARNING);
return;
}
$equation = $params['equation'];
// make sure parenthesis are balanced
if (substr_count($equation,"(") != substr_count($equation,")")) {
trigger_error("math: unbalanced parenthesis",E_USER_WARNING);
return;
}
// match all vars in equation, make sure all are passed
preg_match_all("!(?:0x[a-fA-F0-9]+)|([a-zA-Z][a-zA-Z0-9_]*)!",$equation, $match);
foreach($match[1] as $curr_var) {
if ($curr_var && !isset($params[$curr_var]) && !isset($_allowed_funcs[$curr_var])) {
trigger_error("math: function call $curr_var not allowed",E_USER_WARNING);
return;
}
}
foreach($params as $key => $val) {
if ($key != "equation" && $key != "format" && $key != "assign") {
// make sure value is not empty
if (strlen($val)==0) {
trigger_error("math: parameter $key is empty",E_USER_WARNING);
return;
}
if (!is_numeric($val)) {
trigger_error("math: parameter $key: is not numeric",E_USER_WARNING);
return;
}
$equation = preg_replace("/\b$key\b/", " \$params['$key'] ", $equation);
}
}
$smarty_math_result = null;
eval("\$smarty_math_result = ".$equation.";");
if (empty($params['format'])) {
if (empty($params['assign'])) {
return $smarty_math_result;
} else {
$template->assign($params['assign'],$smarty_math_result);
}
} else {
if (empty($params['assign'])){
printf($params['format'],$smarty_math_result);
} else {
$template->assign($params['assign'],sprintf($params['format'],$smarty_math_result));
}
}
}
?>

View File

@ -0,0 +1,65 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty capitalize modifier plugin
*
* Type: modifier<br>
* Name: capitalize<br>
* Purpose: capitalize words in the string
*
* {@internal {$string|capitalize:true:true} is the fastest option for MBString enabled systems }}
*
* @param string $string string to capitalize
* @param boolean $uc_digits also capitalize "x123" to "X123"
* @param boolean $lc_rest capitalize first letters, lowercase all following letters "aAa" to "Aaa"
* @return string capitalized string
* @author Monte Ohrt <monte at ohrt dot com>
* @author Rodney Rehm
*/
function smarty_modifier_capitalize($string, $uc_digits = false, $lc_rest = false)
{
if (Smarty::$_MBSTRING) {
if ($lc_rest) {
// uppercase (including hyphenated words)
$upper_string = mb_convert_case( $string, MB_CASE_TITLE, Smarty::$_CHARSET );
} else {
// uppercase word breaks
$upper_string = preg_replace("!(^|[^\p{L}'])([\p{Ll}])!eS" . Smarty::$_UTF8_MODIFIER, "stripslashes('\\1').mb_convert_case(stripslashes('\\2'),MB_CASE_UPPER, '" . addslashes(Smarty::$_CHARSET) . "')", $string);
}
// check uc_digits case
if (!$uc_digits) {
if (preg_match_all("!\b([\p{L}]*[\p{N}]+[\p{L}]*)\b!" . Smarty::$_UTF8_MODIFIER, $string, $matches, PREG_OFFSET_CAPTURE)) {
foreach($matches[1] as $match) {
$upper_string = substr_replace($upper_string, mb_strtolower($match[0], Smarty::$_CHARSET), $match[1], strlen($match[0]));
}
}
}
$upper_string = preg_replace("!((^|\s)['\"])(\w)!e" . Smarty::$_UTF8_MODIFIER, "stripslashes('\\1').mb_convert_case(stripslashes('\\3'),MB_CASE_UPPER, '" . addslashes(Smarty::$_CHARSET) . "')", $upper_string);
return $upper_string;
}
// lowercase first
if ($lc_rest) {
$string = strtolower($string);
}
// uppercase (including hyphenated words)
$upper_string = preg_replace("!(^|[^\p{L}'])([\p{Ll}])!eS" . Smarty::$_UTF8_MODIFIER, "stripslashes('\\1').ucfirst(stripslashes('\\2'))", $string);
// check uc_digits case
if (!$uc_digits) {
if (preg_match_all("!\b([\p{L}]*[\p{N}]+[\p{L}]*)\b!" . Smarty::$_UTF8_MODIFIER, $string, $matches, PREG_OFFSET_CAPTURE)) {
foreach($matches[1] as $match) {
$upper_string = substr_replace($upper_string, strtolower($match[0]), $match[1], strlen($match[0]));
}
}
}
$upper_string = preg_replace("!((^|\s)['\"])(\w)!e" . Smarty::$_UTF8_MODIFIER, "stripslashes('\\1').strtoupper(stripslashes('\\3'))", $upper_string);
return $upper_string;
}
?>

View File

@ -0,0 +1,65 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty date_format modifier plugin
*
* Type: modifier<br>
* Name: date_format<br>
* Purpose: format datestamps via strftime<br>
* Input:<br>
* - string: input date string
* - format: strftime format for output
* - default_date: default date if $string is empty
*
* @link http://www.smarty.net/manual/en/language.modifier.date.format.php date_format (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $string input date string
* @param string $format strftime format for output
* @param string $default_date default date if $string is empty
* @param string $formatter either 'strftime' or 'auto'
* @return string |void
* @uses smarty_make_timestamp()
*/
function smarty_modifier_date_format($string, $format=null, $default_date='', $formatter='auto')
{
if ($format === null) {
$format = Smarty::$_DATE_FORMAT;
}
/**
* Include the {@link shared.make_timestamp.php} plugin
*/
require_once(SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php');
if ($string != '' && $string != '0000-00-00' && $string != '0000-00-00 00:00:00') {
$timestamp = smarty_make_timestamp($string);
} elseif ($default_date != '') {
$timestamp = smarty_make_timestamp($default_date);
} else {
return;
}
if($formatter=='strftime'||($formatter=='auto'&&strpos($format,'%')!==false)) {
if (DS == '\\') {
$_win_from = array('%D', '%h', '%n', '%r', '%R', '%t', '%T');
$_win_to = array('%m/%d/%y', '%b', "\n", '%I:%M:%S %p', '%H:%M', "\t", '%H:%M:%S');
if (strpos($format, '%e') !== false) {
$_win_from[] = '%e';
$_win_to[] = sprintf('%\' 2d', date('j', $timestamp));
}
if (strpos($format, '%l') !== false) {
$_win_from[] = '%l';
$_win_to[] = sprintf('%\' 2d', date('h', $timestamp));
}
$format = str_replace($_win_from, $_win_to, $format);
}
return strftime($format, $timestamp);
} else {
return date($format, $timestamp);
}
}
?>

View File

@ -0,0 +1,105 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage Debug
*/
/**
* Smarty debug_print_var modifier plugin
*
* Type: modifier<br>
* Name: debug_print_var<br>
* Purpose: formats variable contents for display in the console
*
* @author Monte Ohrt <monte at ohrt dot com>
* @param array|object $var variable to be formatted
* @param integer $depth maximum recursion depth if $var is an array
* @param integer $length maximum string length if $var is a string
* @return string
*/
function smarty_modifier_debug_print_var ($var, $depth = 0, $length = 40)
{
$_replace = array("\n" => '<i>\n</i>',
"\r" => '<i>\r</i>',
"\t" => '<i>\t</i>'
);
switch (gettype($var)) {
case 'array' :
$results = '<b>Array (' . count($var) . ')</b>';
foreach ($var as $curr_key => $curr_val) {
$results .= '<br>' . str_repeat('&nbsp;', $depth * 2)
. '<b>' . strtr($curr_key, $_replace) . '</b> =&gt; '
. smarty_modifier_debug_print_var($curr_val, ++$depth, $length);
$depth--;
}
break;
case 'object' :
$object_vars = get_object_vars($var);
$results = '<b>' . get_class($var) . ' Object (' . count($object_vars) . ')</b>';
foreach ($object_vars as $curr_key => $curr_val) {
$results .= '<br>' . str_repeat('&nbsp;', $depth * 2)
. '<b> -&gt;' . strtr($curr_key, $_replace) . '</b> = '
. smarty_modifier_debug_print_var($curr_val, ++$depth, $length);
$depth--;
}
break;
case 'boolean' :
case 'NULL' :
case 'resource' :
if (true === $var) {
$results = 'true';
} elseif (false === $var) {
$results = 'false';
} elseif (null === $var) {
$results = 'null';
} else {
$results = htmlspecialchars((string) $var);
}
$results = '<i>' . $results . '</i>';
break;
case 'integer' :
case 'float' :
$results = htmlspecialchars((string) $var);
break;
case 'string' :
$results = strtr($var, $_replace);
if (Smarty::$_MBSTRING) {
if (mb_strlen($var, Smarty::$_CHARSET) > $length) {
$results = mb_substr($var, 0, $length - 3, Smarty::$_CHARSET) . '...';
}
} else {
if (isset($var[$length])) {
$results = substr($var, 0, $length - 3) . '...';
}
}
$results = htmlspecialchars('"' . $results . '"');
break;
case 'unknown type' :
default :
$results = strtr((string) $var, $_replace);
if (Smarty::$_MBSTRING) {
if (mb_strlen($results, Smarty::$_CHARSET) > $length) {
$results = mb_substr($results, 0, $length - 3, Smarty::$_CHARSET) . '...';
}
} else {
if (strlen($results) > $length) {
$results = substr($results, 0, $length - 3) . '...';
}
}
$results = htmlspecialchars($results);
}
return $results;
}
?>

View File

@ -0,0 +1,188 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty escape modifier plugin
*
* Type: modifier<br>
* Name: escape<br>
* Purpose: escape string for output
*
* @link http://www.smarty.net/manual/en/language.modifier.count.characters.php count_characters (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $string input string
* @param string $esc_type escape type
* @param string $char_set character set, used for htmlspecialchars() or htmlentities()
* @param boolean $double_encode encode already encoded entitites again, used for htmlspecialchars() or htmlentities()
* @return string escaped input string
*/
function smarty_modifier_escape($string, $esc_type = 'html', $char_set = null, $double_encode = true)
{
static $_double_encode = null;
if ($_double_encode === null) {
$_double_encode = version_compare(PHP_VERSION, '5.2.3', '>=');
}
if (!$char_set) {
$char_set = Smarty::$_CHARSET;
}
switch ($esc_type) {
case 'html':
if ($_double_encode) {
// php >=5.3.2 - go native
return htmlspecialchars($string, ENT_QUOTES, $char_set, $double_encode);
} else {
if ($double_encode) {
// php <5.2.3 - only handle double encoding
return htmlspecialchars($string, ENT_QUOTES, $char_set);
} else {
// php <5.2.3 - prevent double encoding
$string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
$string = htmlspecialchars($string, ENT_QUOTES, $char_set);
$string = str_replace(array('%%%SMARTY_START%%%', '%%%SMARTY_END%%%'), array('&', ';'), $string);
return $string;
}
}
case 'htmlall':
if (Smarty::$_MBSTRING) {
// mb_convert_encoding ignores htmlspecialchars()
if ($_double_encode) {
// php >=5.3.2 - go native
$string = htmlspecialchars($string, ENT_QUOTES, $char_set, $double_encode);
} else {
if ($double_encode) {
// php <5.2.3 - only handle double encoding
$string = htmlspecialchars($string, ENT_QUOTES, $char_set);
} else {
// php <5.2.3 - prevent double encoding
$string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
$string = htmlspecialchars($string, ENT_QUOTES, $char_set);
$string = str_replace(array('%%%SMARTY_START%%%', '%%%SMARTY_END%%%'), array('&', ';'), $string);
return $string;
}
}
// htmlentities() won't convert everything, so use mb_convert_encoding
return mb_convert_encoding($string, 'HTML-ENTITIES', $char_set);
}
// no MBString fallback
if ($_double_encode) {
return htmlentities($string, ENT_QUOTES, $char_set, $double_encode);
} else {
if ($double_encode) {
return htmlentities($string, ENT_QUOTES, $char_set);
} else {
$string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
$string = htmlentities($string, ENT_QUOTES, $char_set);
$string = str_replace(array('%%%SMARTY_START%%%', '%%%SMARTY_END%%%'), array('&', ';'), $string);
return $string;
}
}
case 'url':
return rawurlencode($string);
case 'urlpathinfo':
return str_replace('%2F', '/', rawurlencode($string));
case 'quotes':
// escape unescaped single quotes
return preg_replace("%(?<!\\\\)'%", "\\'", $string);
case 'hex':
// escape every byte into hex
// Note that the UTF-8 encoded character ä will be represented as %c3%a4
$return = '';
$_length = strlen($string);
for ($x = 0; $x < $_length; $x++) {
$return .= '%' . bin2hex($string[$x]);
}
return $return;
case 'hexentity':
$return = '';
if (Smarty::$_MBSTRING) {
require_once(SMARTY_PLUGINS_DIR . 'shared.mb_unicode.php');
$return = '';
foreach (smarty_mb_to_unicode($string, Smarty::$_CHARSET) as $unicode) {
$return .= '&#x' . strtoupper(dechex($unicode)) . ';';
}
return $return;
}
// no MBString fallback
$_length = strlen($string);
for ($x = 0; $x < $_length; $x++) {
$return .= '&#x' . bin2hex($string[$x]) . ';';
}
return $return;
case 'decentity':
$return = '';
if (Smarty::$_MBSTRING) {
require_once(SMARTY_PLUGINS_DIR . 'shared.mb_unicode.php');
$return = '';
foreach (smarty_mb_to_unicode($string, Smarty::$_CHARSET) as $unicode) {
$return .= '&#' . $unicode . ';';
}
return $return;
}
// no MBString fallback
$_length = strlen($string);
for ($x = 0; $x < $_length; $x++) {
$return .= '&#' . ord($string[$x]) . ';';
}
return $return;
case 'javascript':
// escape quotes and backslashes, newlines, etc.
return strtr($string, array('\\' => '\\\\', "'" => "\\'", '"' => '\\"', "\r" => '\\r', "\n" => '\\n', '</' => '<\/'));
case 'mail':
if (Smarty::$_MBSTRING) {
require_once(SMARTY_PLUGINS_DIR . 'shared.mb_str_replace.php');
return smarty_mb_str_replace(array('@', '.'), array(' [AT] ', ' [DOT] '), $string);
}
// no MBString fallback
return str_replace(array('@', '.'), array(' [AT] ', ' [DOT] '), $string);
case 'nonstd':
// escape non-standard chars, such as ms document quotes
$return = '';
if (Smarty::$_MBSTRING) {
require_once(SMARTY_PLUGINS_DIR . 'shared.mb_unicode.php');
foreach (smarty_mb_to_unicode($string, Smarty::$_CHARSET) as $unicode) {
if ($unicode >= 126) {
$return .= '&#' . $unicode . ';';
} else {
$return .= chr($unicode);
}
}
return $return;
}
$_length = strlen($string);
for ($_i = 0; $_i < $_length; $_i++) {
$_ord = ord(substr($string, $_i, 1));
// non-standard char, escape it
if ($_ord >= 126) {
$return .= '&#' . $_ord . ';';
} else {
$return .= substr($string, $_i, 1);
}
}
return $return;
default:
return $string;
}
}
?>

View File

@ -0,0 +1,55 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty regex_replace modifier plugin
*
* Type: modifier<br>
* Name: regex_replace<br>
* Purpose: regular expression search/replace
*
* @link http://smarty.php.net/manual/en/language.modifier.regex.replace.php
* regex_replace (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $string input string
* @param string|array $search regular expression(s) to search for
* @param string|array $replace string(s) that should be replaced
* @return string
*/
function smarty_modifier_regex_replace($string, $search, $replace)
{
if(is_array($search)) {
foreach($search as $idx => $s) {
$search[$idx] = _smarty_regex_replace_check($s);
}
} else {
$search = _smarty_regex_replace_check($search);
}
return preg_replace($search, $replace, $string);
}
/**
* @param string $search string(s) that should be replaced
* @return string
* @ignore
*/
function _smarty_regex_replace_check($search)
{
// null-byte injection detection
// anything behind the first null-byte is ignored
if (($pos = strpos($search,"\0")) !== false) {
$search = substr($search,0,$pos);
}
// remove eval-modifier from $search
if (preg_match('!([a-zA-Z\s]+)$!s', $search, $match) && (strpos($match[1], 'e') !== false)) {
$search = substr($search, 0, -strlen($match[1])) . preg_replace('![e\s]+!', '', $match[1]);
}
return $search;
}
?>

View File

@ -0,0 +1,33 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty replace modifier plugin
*
* Type: modifier<br>
* Name: replace<br>
* Purpose: simple search/replace
*
* @link http://smarty.php.net/manual/en/language.modifier.replace.php replace (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @author Uwe Tews
* @param string $string input string
* @param string $search text to search for
* @param string $replace replacement text
* @return string
*/
function smarty_modifier_replace($string, $search, $replace)
{
if (Smarty::$_MBSTRING) {
require_once(SMARTY_PLUGINS_DIR . 'shared.mb_str_replace.php');
return smarty_mb_str_replace($search, $replace, $string);
}
return str_replace($search, $replace, $string);
}
?>

View File

@ -0,0 +1,27 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty spacify modifier plugin
*
* Type: modifier<br>
* Name: spacify<br>
* Purpose: add spaces between characters in a string
*
* @link http://smarty.php.net/manual/en/language.modifier.spacify.php spacify (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $string input string
* @param string $spacify_char string to insert between characters.
* @return string
*/
function smarty_modifier_spacify($string, $spacify_char = ' ')
{
// well… what about charsets besides latin and UTF-8?
return implode($spacify_char, preg_split('//' . Smarty::$_UTF8_MODIFIER, $string, -1, PREG_SPLIT_NO_EMPTY));
}
?>

View File

@ -0,0 +1,59 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifier
*/
/**
* Smarty truncate modifier plugin
*
* Type: modifier<br>
* Name: truncate<br>
* Purpose: Truncate a string to a certain length if necessary,
* optionally splitting in the middle of a word, and
* appending the $etc string or inserting $etc into the middle.
*
* @link http://smarty.php.net/manual/en/language.modifier.truncate.php truncate (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $string input string
* @param integer $length length of truncated text
* @param string $etc end string
* @param boolean $break_words truncate at word boundary
* @param boolean $middle truncate in the middle of text
* @return string truncated string
*/
function smarty_modifier_truncate($string, $length = 80, $etc = '...', $break_words = false, $middle = false) {
if ($length == 0)
return '';
if (Smarty::$_MBSTRING) {
if (mb_strlen($string, Smarty::$_CHARSET) > $length) {
$length -= min($length, mb_strlen($etc, Smarty::$_CHARSET));
if (!$break_words && !$middle) {
$string = preg_replace('/\s+?(\S+)?$/' . Smarty::$_UTF8_MODIFIER, '', mb_substr($string, 0, $length + 1, Smarty::$_CHARSET));
}
if (!$middle) {
return mb_substr($string, 0, $length, Smarty::$_CHARSET) . $etc;
}
return mb_substr($string, 0, $length / 2, Smarty::$_CHARSET) . $etc . mb_substr($string, - $length / 2, $length, Smarty::$_CHARSET);
}
return $string;
}
// no MBString fallback
if (isset($string[$length])) {
$length -= min($length, strlen($etc));
if (!$break_words && !$middle) {
$string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length + 1));
}
if (!$middle) {
return substr($string, 0, $length) . $etc;
}
return substr($string, 0, $length / 2) . $etc . substr($string, - $length / 2);
}
return $string;
}
?>

View File

@ -0,0 +1,30 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty cat modifier plugin
*
* Type: modifier<br>
* Name: cat<br>
* Date: Feb 24, 2003<br>
* Purpose: catenate a value to a variable<br>
* Input: string to catenate<br>
* Example: {$var|cat:"foo"}
*
* @link http://smarty.php.net/manual/en/language.modifier.cat.php cat
* (Smarty online manual)
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_cat($params, $compiler)
{
return '('.implode(').(', $params).')';
}
?>

View File

@ -0,0 +1,33 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty count_characters modifier plugin
*
* Type: modifier<br>
* Name: count_characteres<br>
* Purpose: count the number of characters in a text
*
* @link http://www.smarty.net/manual/en/language.modifier.count.characters.php count_characters (Smarty online manual)
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_count_characters($params, $compiler)
{
if (!isset($params[1]) || $params[1] != 'true') {
return 'preg_match_all(\'/[^\s]/' . Smarty::$_UTF8_MODIFIER . '\',' . $params[0] . ', $tmp)';
}
if (Smarty::$_MBSTRING) {
return 'mb_strlen(' . $params[0] . ', \'' . addslashes(Smarty::$_CHARSET) . '\')';
}
// no MBString fallback
return 'strlen(' . $params[0] . ')';
}
?>

View File

@ -0,0 +1,28 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty count_paragraphs modifier plugin
*
* Type: modifier<br>
* Name: count_paragraphs<br>
* Purpose: count the number of paragraphs in a text
*
* @link http://www.smarty.net/manual/en/language.modifier.count.paragraphs.php
* count_paragraphs (Smarty online manual)
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_count_paragraphs($params, $compiler)
{
// count \r or \n characters
return '(preg_match_all(\'#[\r\n]+#\', ' . $params[0] . ', $tmp)+1)';
}
?>

View File

@ -0,0 +1,28 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty count_sentences modifier plugin
*
* Type: modifier<br>
* Name: count_sentences
* Purpose: count the number of sentences in a text
*
* @link http://www.smarty.net/manual/en/language.modifier.count.paragraphs.php
* count_sentences (Smarty online manual)
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_count_sentences($params, $compiler)
{
// find periods, question marks, exclamation marks with a word before but not after.
return 'preg_match_all("#\w[\.\?\!](\W|$)#S' . Smarty::$_UTF8_MODIFIER . '", ' . $params[0] . ', $tmp)';
}
?>

View File

@ -0,0 +1,32 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty count_words modifier plugin
*
* Type: modifier<br>
* Name: count_words<br>
* Purpose: count the number of words in a text
*
* @link http://www.smarty.net/manual/en/language.modifier.count.words.php count_words (Smarty online manual)
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_count_words($params, $compiler)
{
if (Smarty::$_MBSTRING) {
// return 'preg_match_all(\'#[\w\pL]+#' . Smarty::$_UTF8_MODIFIER . '\', ' . $params[0] . ', $tmp)';
// expression taken from http://de.php.net/manual/en/function.str-word-count.php#85592
return 'preg_match_all(\'/\p{L}[\p{L}\p{Mn}\p{Pd}\\\'\x{2019}]*/' . Smarty::$_UTF8_MODIFIER . '\', ' . $params[0] . ', $tmp)';
}
// no MBString fallback
return 'str_word_count(' . $params[0] . ')';
}
?>

View File

@ -0,0 +1,35 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty default modifier plugin
*
* Type: modifier<br>
* Name: default<br>
* Purpose: designate default value for empty variables
*
* @link http://www.smarty.net/manual/en/language.modifier.default.php default (Smarty online manual)
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_default ($params, $compiler)
{
$output = $params[0];
if (!isset($params[1])) {
$params[1] = "''";
}
array_shift($params);
foreach ($params as $param) {
$output = '(($tmp = @' . $output . ')===null||$tmp===\'\' ? ' . $param . ' : $tmp)';
}
return $output;
}
?>

View File

@ -0,0 +1,125 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* @ignore
*/
require_once( SMARTY_PLUGINS_DIR .'shared.literal_compiler_param.php' );
/**
* Smarty escape modifier plugin
*
* Type: modifier<br>
* Name: escape<br>
* Purpose: escape string for output
*
* @link http://www.smarty.net/docsv2/en/language.modifier.escape count_characters (Smarty online manual)
* @author Rodney Rehm
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_escape($params, $compiler)
{
static $_double_encode = null;
if ($_double_encode === null) {
$_double_encode = version_compare(PHP_VERSION, '5.2.3', '>=');
}
try {
$esc_type = smarty_literal_compiler_param($params, 1, 'html');
$char_set = smarty_literal_compiler_param($params, 2, Smarty::$_CHARSET);
$double_encode = smarty_literal_compiler_param($params, 3, true);
if (!$char_set) {
$char_set = Smarty::$_CHARSET;
}
switch ($esc_type) {
case 'html':
if ($_double_encode) {
return 'htmlspecialchars('
. $params[0] .', ENT_QUOTES, '
. var_export($char_set, true) . ', '
. var_export($double_encode, true) . ')';
} else if ($double_encode) {
return 'htmlspecialchars('
. $params[0] .', ENT_QUOTES, '
. var_export($char_set, true) . ')';
} else {
// fall back to modifier.escape.php
}
case 'htmlall':
if (Smarty::$_MBSTRING) {
if ($_double_encode) {
// php >=5.2.3 - go native
return 'mb_convert_encoding(htmlspecialchars('
. $params[0] .', ENT_QUOTES, '
. var_export($char_set, true) . ', '
. var_export($double_encode, true)
. '), "HTML-ENTITIES", '
. var_export($char_set, true) . ')';
} else if ($double_encode) {
// php <5.2.3 - only handle double encoding
return 'mb_convert_encoding(htmlspecialchars('
. $params[0] .', ENT_QUOTES, '
. var_export($char_set, true)
. '), "HTML-ENTITIES", '
. var_export($char_set, true) . ')';
} else {
// fall back to modifier.escape.php
}
}
// no MBString fallback
if ($_double_encode) {
// php >=5.2.3 - go native
return 'htmlentities('
. $params[0] .', ENT_QUOTES, '
. var_export($char_set, true) . ', '
. var_export($double_encode, true) . ')';
} else if ($double_encode) {
// php <5.2.3 - only handle double encoding
return 'htmlentities('
. $params[0] .', ENT_QUOTES, '
. var_export($char_set, true) . ')';
} else {
// fall back to modifier.escape.php
}
case 'url':
return 'rawurlencode(' . $params[0] . ')';
case 'urlpathinfo':
return 'str_replace("%2F", "/", rawurlencode(' . $params[0] . '))';
case 'quotes':
// escape unescaped single quotes
return 'preg_replace("%(?<!\\\\\\\\)\'%", "\\\'",' . $params[0] . ')';
case 'javascript':
// escape quotes and backslashes, newlines, etc.
return 'strtr(' . $params[0] . ', array("\\\\" => "\\\\\\\\", "\'" => "\\\\\'", "\"" => "\\\\\"", "\\r" => "\\\\r", "\\n" => "\\\n", "</" => "<\/" ))';
}
} catch(SmartyException $e) {
// pass through to regular plugin fallback
}
// could not optimize |escape call, so fallback to regular plugin
if ($compiler->tag_nocache | $compiler->nocache) {
$compiler->template->required_plugins['nocache']['escape']['modifier']['file'] = SMARTY_PLUGINS_DIR .'modifier.escape.php';
$compiler->template->required_plugins['nocache']['escape']['modifier']['function'] = 'smarty_modifier_escape';
} else {
$compiler->template->required_plugins['compiled']['escape']['modifier']['file'] = SMARTY_PLUGINS_DIR .'modifier.escape.php';
$compiler->template->required_plugins['compiled']['escape']['modifier']['function'] = 'smarty_modifier_escape';
}
return 'smarty_modifier_escape(' . join( ', ', $params ) . ')';
}
?>

View File

@ -0,0 +1,34 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty from_charset modifier plugin
*
* Type: modifier<br>
* Name: from_charset<br>
* Purpose: convert character encoding from $charset to internal encoding
*
* @author Rodney Rehm
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_from_charset($params, $compiler)
{
if (!Smarty::$_MBSTRING) {
// FIXME: (rodneyrehm) shouldn't this throw an error?
return $params[0];
}
if (!isset($params[1])) {
$params[1] = '"ISO-8859-1"';
}
return 'mb_convert_encoding(' . $params[0] . ', "' . addslashes(Smarty::$_CHARSET) . '", ' . $params[1] . ')';
}
?>

View File

@ -0,0 +1,32 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty indent modifier plugin
*
* Type: modifier<br>
* Name: indent<br>
* Purpose: indent lines of text
*
* @link http://www.smarty.net/manual/en/language.modifier.indent.php indent (Smarty online manual)
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_indent($params, $compiler)
{
if (!isset($params[1])) {
$params[1] = 4;
}
if (!isset($params[2])) {
$params[2] = "' '";
}
return 'preg_replace(\'!^!m\',str_repeat(' . $params[2] . ',' . $params[1] . '),' . $params[0] . ')';
}
?>

View File

@ -0,0 +1,31 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty lower modifier plugin
*
* Type: modifier<br>
* Name: lower<br>
* Purpose: convert string to lowercase
*
* @link http://www.smarty.net/manual/en/language.modifier.lower.php lower (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_lower($params, $compiler)
{
if (Smarty::$_MBSTRING) {
return 'mb_strtolower(' . $params[0] . ', \'' . addslashes(Smarty::$_CHARSET) . '\')' ;
}
// no MBString fallback
return 'strtolower(' . $params[0] . ')';
}
?>

View File

@ -0,0 +1,25 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty noprint modifier plugin
*
* Type: modifier<br>
* Name: noprint<br>
* Purpose: return an empty string
*
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_noprint($params, $compiler)
{
return "''";
}
?>

View File

@ -0,0 +1,26 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty string_format modifier plugin
*
* Type: modifier<br>
* Name: string_format<br>
* Purpose: format strings via sprintf
*
* @link http://www.smarty.net/manual/en/language.modifier.string.format.php string_format (Smarty online manual)
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_string_format($params, $compiler)
{
return 'sprintf(' . $params[1] . ',' . $params[0] . ')';
}
?>

View File

@ -0,0 +1,33 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty strip modifier plugin
*
* Type: modifier<br>
* Name: strip<br>
* Purpose: Replace all repeated spaces, newlines, tabs
* with a single space or supplied replacement string.<br>
* Example: {$var|strip} {$var|strip:"&nbsp;"}<br>
* Date: September 25th, 2002
*
* @link http://www.smarty.net/manual/en/language.modifier.strip.php strip (Smarty online manual)
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_strip($params, $compiler)
{
if (!isset($params[1])) {
$params[1] = "' '";
}
return "preg_replace('!\s+!" . Smarty::$_UTF8_MODIFIER . "', {$params[1]},{$params[0]})";
}
?>

View File

@ -0,0 +1,33 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty strip_tags modifier plugin
*
* Type: modifier<br>
* Name: strip_tags<br>
* Purpose: strip html tags from text
*
* @link http://www.smarty.net/manual/en/language.modifier.strip.tags.php strip_tags (Smarty online manual)
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_strip_tags($params, $compiler)
{
if (!isset($params[1])) {
$params[1] = true;
}
if ($params[1] === true) {
return "preg_replace('!<[^>]*?>!', ' ', {$params[0]})";
} else {
return 'strip_tags(' . $params[0] . ')';
}
}
?>

View File

@ -0,0 +1,34 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty to_charset modifier plugin
*
* Type: modifier<br>
* Name: to_charset<br>
* Purpose: convert character encoding from internal encoding to $charset
*
* @author Rodney Rehm
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_to_charset($params, $compiler)
{
if (!Smarty::$_MBSTRING) {
// FIXME: (rodneyrehm) shouldn't this throw an error?
return $params[0];
}
if (!isset($params[1])) {
$params[1] = '"ISO-8859-1"';
}
return 'mb_convert_encoding(' . $params[0] . ', ' . $params[1] . ', "' . addslashes(Smarty::$_CHARSET) . '")';
}
?>

View File

@ -0,0 +1,51 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty unescape modifier plugin
*
* Type: modifier<br>
* Name: unescape<br>
* Purpose: unescape html entities
*
* @author Rodney Rehm
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_unescape($params, $compiler)
{
if (!isset($params[1])) {
$params[1] = 'html';
}
if (!isset($params[2])) {
$params[2] = '\'' . addslashes(Smarty::$_CHARSET) . '\'';
} else {
$params[2] = "'" . $params[2] . "'";
}
switch (trim($params[1], '"\'')) {
case 'entity':
case 'htmlall':
if (Smarty::$_MBSTRING) {
return 'mb_convert_encoding(' . $params[0] . ', ' . $params[2] . ', \'HTML-ENTITIES\')';
}
return 'html_entity_decode(' . $params[0] . ', ENT_NOQUOTES, ' . $params[2] . ')';
case 'html':
return 'htmlspecialchars_decode(' . $params[0] . ', ENT_QUOTES)';
case 'url':
return 'rawurldecode(' . $params[0] . ')';
default:
return $params[0];
}
}
?>

View File

@ -0,0 +1,30 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty upper modifier plugin
*
* Type: modifier<br>
* Name: lower<br>
* Purpose: convert string to uppercase
*
* @link http://smarty.php.net/manual/en/language.modifier.upper.php lower (Smarty online manual)
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_upper($params, $compiler)
{
if (Smarty::$_MBSTRING) {
return 'mb_strtoupper(' . $params[0] . ', \'' . addslashes(Smarty::$_CHARSET) . '\')' ;
}
// no MBString fallback
return 'strtoupper(' . $params[0] . ')';
}
?>

View File

@ -0,0 +1,46 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty wordwrap modifier plugin
*
* Type: modifier<br>
* Name: wordwrap<br>
* Purpose: wrap a string of text at a given length
*
* @link http://smarty.php.net/manual/en/language.modifier.wordwrap.php wordwrap (Smarty online manual)
* @author Uwe Tews
* @param array $params parameters
* @return string with compiled code
*/
function smarty_modifiercompiler_wordwrap($params, $compiler)
{
if (!isset($params[1])) {
$params[1] = 80;
}
if (!isset($params[2])) {
$params[2] = '"\n"';
}
if (!isset($params[3])) {
$params[3] = 'false';
}
$function = 'wordwrap';
if (Smarty::$_MBSTRING) {
if ($compiler->tag_nocache | $compiler->nocache) {
$compiler->template->required_plugins['nocache']['wordwrap']['modifier']['file'] = SMARTY_PLUGINS_DIR .'shared.mb_wordwrap.php';
$compiler->template->required_plugins['nocache']['wordwrap']['modifier']['function'] = 'smarty_mb_wordwrap';
} else {
$compiler->template->required_plugins['compiled']['wordwrap']['modifier']['file'] = SMARTY_PLUGINS_DIR .'shared.mb_wordwrap.php';
$compiler->template->required_plugins['compiled']['wordwrap']['modifier']['function'] = 'smarty_mb_wordwrap';
}
$function = 'smarty_mb_wordwrap';
}
return $function . '(' . $params[0] . ',' . $params[1] . ',' . $params[2] . ',' . $params[3] . ')';
}
?>

View File

@ -0,0 +1,94 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFilter
*/
/**
* Smarty trimwhitespace outputfilter plugin
*
* Trim unnecessary whitespace from HTML markup.
*
* @author Rodney Rehm
* @param string $source input string
* @param Smarty_Internal_Template $smarty Smarty object
* @return string filtered output
* @todo substr_replace() is not overloaded by mbstring.func_overload - so this function might fail!
*/
function smarty_outputfilter_trimwhitespace($source, Smarty_Internal_Template $smarty)
{
$store = array();
$_store = 0;
$_offset = 0;
// Unify Line-Breaks to \n
$source = preg_replace("/\015\012|\015|\012/", "\n", $source);
// capture Internet Explorer Conditional Comments
if (preg_match_all('#<!--\[[^\]]+\]>.*?<!\[[^\]]+\]-->#is', $source, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
foreach ($matches as $match) {
$store[] = $match[0][0];
$_length = strlen($match[0][0]);
$replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
$source = substr_replace($source, $replace, $match[0][1] - $_offset, $_length);
$_offset += $_length - strlen($replace);
$_store++;
}
}
// Strip all HTML-Comments
// yes, even the ones in <script> - see http://stackoverflow.com/a/808850/515124
$source = preg_replace( '#<!--.*?-->#ms', '', $source );
// capture html elements not to be messed with
$_offset = 0;
if (preg_match_all('#<(script|pre|textarea)[^>]*>.*?</\\1>#is', $source, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
foreach ($matches as $match) {
$store[] = $match[0][0];
$_length = strlen($match[0][0]);
$replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
$source = substr_replace($source, $replace, $match[0][1] - $_offset, $_length);
$_offset += $_length - strlen($replace);
$_store++;
}
}
$expressions = array(
// replace multiple spaces between tags by a single space
// can't remove them entirely, becaue that might break poorly implemented CSS display:inline-block elements
'#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1 \2',
// remove spaces between attributes (but not in attribute values!)
'#(([a-z0-9]\s*=\s*(["\'])[^\3]*?\3)|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \4',
// note: for some very weird reason trim() seems to remove spaces inside attributes.
// maybe a \0 byte or something is interfering?
'#^\s+<#Ss' => '<',
'#>\s+$#Ss' => '>',
);
$source = preg_replace( array_keys($expressions), array_values($expressions), $source );
// note: for some very weird reason trim() seems to remove spaces inside attributes.
// maybe a \0 byte or something is interfering?
// $source = trim( $source );
// capture html elements not to be messed with
$_offset = 0;
if (preg_match_all('#@!@SMARTY:([0-9]+):SMARTY@!@#is', $source, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
foreach ($matches as $match) {
$store[] = $match[0][0];
$_length = strlen($match[0][0]);
$replace = array_shift($store);
$source = substr_replace($source, $replace, $match[0][1] + $_offset, $_length);
$_offset += strlen($replace) - $_length;
$_store++;
}
}
return $source;
}
?>

View File

@ -0,0 +1,51 @@
<?php
/**
* Smarty shared plugin
*
* @package Smarty
* @subpackage PluginsShared
*/
if (version_compare(PHP_VERSION, '5.2.3', '>=')) {
/**
* escape_special_chars common function
*
* Function: smarty_function_escape_special_chars<br>
* Purpose: used by other smarty functions to escape
* special chars except for already escaped ones
*
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $string text that should by escaped
* @return string
*/
function smarty_function_escape_special_chars($string)
{
if (!is_array($string)) {
$string = htmlspecialchars($string, ENT_COMPAT, Smarty::$_CHARSET, false);
}
return $string;
}
} else {
/**
* escape_special_chars common function
*
* Function: smarty_function_escape_special_chars<br>
* Purpose: used by other smarty functions to escape
* special chars except for already escaped ones
*
* @author Monte Ohrt <monte at ohrt dot com>
* @param string $string text that should by escaped
* @return string
*/
function smarty_function_escape_special_chars($string)
{
if (!is_array($string)) {
$string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
$string = htmlspecialchars($string);
$string = str_replace(array('%%%SMARTY_START%%%', '%%%SMARTY_END%%%'), array('&', ';'), $string);
}
return $string;
}
}
?>

View File

@ -0,0 +1,33 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsShared
*/
/**
* evaluate compiler parameter
*
* @param array $params parameter array as given to the compiler function
* @param integer $index array index of the parameter to convert
* @param mixed $default value to be returned if the parameter is not present
* @return mixed evaluated value of parameter or $default
* @throws SmartyException if parameter is not a literal (but an expression, variable, )
* @author Rodney Rehm
*/
function smarty_literal_compiler_param($params, $index, $default=null)
{
// not set, go default
if (!isset($params[$index])) {
return $default;
}
// test if param is a literal
if (!preg_match('/^([\'"]?)[a-zA-Z0-9]+(\\1)$/', $params[$index])) {
throw new SmartyException('$param[' . $index . '] is not a literal and is thus not evaluatable at compile time');
}
$t = null;
eval("\$t = " . $params[$index] . ";");
return $t;
}

View File

@ -0,0 +1,42 @@
<?php
/**
* Smarty shared plugin
*
* @package Smarty
* @subpackage PluginsShared
*/
/**
* Function: smarty_make_timestamp<br>
* Purpose: used by other smarty functions to make a timestamp from a string.
*
* @author Monte Ohrt <monte at ohrt dot com>
* @param DateTime|int|string $string date object, timestamp or string that can be converted using strtotime()
* @return int
*/
function smarty_make_timestamp($string)
{
if (empty($string)) {
// use "now":
return time();
} elseif ($string instanceof DateTime) {
return $string->getTimestamp();
} elseif (strlen($string) == 14 && ctype_digit($string)) {
// it is mysql timestamp format of YYYYMMDDHHMMSS?
return mktime(substr($string, 8, 2),substr($string, 10, 2),substr($string, 12, 2),
substr($string, 4, 2),substr($string, 6, 2),substr($string, 0, 4));
} elseif (is_numeric($string)) {
// it is a numeric string, we handle it as timestamp
return (int) $string;
} else {
// strtotime should handle it
$time = strtotime($string);
if ($time == -1 || $time === false) {
// strtotime() was not able to parse $string, use "now":
return time();
}
return $time;
}
}
?>

View File

@ -0,0 +1,55 @@
<?php
/**
* Smarty shared plugin
*
* @package Smarty
* @subpackage PluginsShared
*/
if (!function_exists('smarty_mb_str_replace')) {
/**
* Multibyte string replace
*
* @param string $search the string to be searched
* @param string $replace the replacement string
* @param string $subject the source string
* @param int &$count number of matches found
* @return string replaced string
* @author Rodney Rehm
*/
function smarty_mb_str_replace($search, $replace, $subject, &$count=0)
{
if (!is_array($search) && is_array($replace)) {
return false;
}
if (is_array($subject)) {
// call mb_replace for each single string in $subject
foreach ($subject as &$string) {
$string = &smarty_mb_str_replace($search, $replace, $string, $c);
$count += $c;
}
} elseif (is_array($search)) {
if (!is_array($replace)) {
foreach ($search as &$string) {
$subject = smarty_mb_str_replace($string, $replace, $subject, $c);
$count += $c;
}
} else {
$n = max(count($search), count($replace));
while ($n--) {
$subject = smarty_mb_str_replace(current($search), current($replace), $subject, $c);
$count += $c;
next($search);
next($replace);
}
}
} else {
$parts = mb_split(preg_quote($search), $subject);
$count = count($parts) - 1;
$subject = implode($replace, $parts);
}
return $subject;
}
}
?>

View File

@ -0,0 +1,48 @@
<?php
/**
* Smarty shared plugin
*
* @package Smarty
* @subpackage PluginsShared
*/
/**
* convert characters to their decimal unicode equivalents
*
* @link http://www.ibm.com/developerworks/library/os-php-unicode/index.html#listing3 for inspiration
* @param string $string characters to calculate unicode of
* @param string $encoding encoding of $string, if null mb_internal_encoding() is used
* @return array sequence of unicodes
* @author Rodney Rehm
*/
function smarty_mb_to_unicode($string, $encoding=null) {
if ($encoding) {
$expanded = mb_convert_encoding($string, "UTF-32BE", $encoding);
} else {
$expanded = mb_convert_encoding($string, "UTF-32BE");
}
return unpack("N*", $expanded);
}
/**
* convert unicodes to the character of given encoding
*
* @link http://www.ibm.com/developerworks/library/os-php-unicode/index.html#listing3 for inspiration
* @param integer|array $unicode single unicode or list of unicodes to convert
* @param string $encoding encoding of returned string, if null mb_internal_encoding() is used
* @return string unicode as character sequence in given $encoding
* @author Rodney Rehm
*/
function smarty_mb_from_unicode($unicode, $encoding=null) {
$t = '';
if (!$encoding) {
$encoding = mb_internal_encoding();
}
foreach((array) $unicode as $utf32be) {
$character = pack("N*", $utf32be);
$t .= mb_convert_encoding($character, $encoding, "UTF-32BE");
}
return $t;
}
?>

View File

@ -0,0 +1,83 @@
<?php
/**
* Smarty shared plugin
*
* @package Smarty
* @subpackage PluginsShared
*/
if(!function_exists('smarty_mb_wordwrap')) {
/**
* Wrap a string to a given number of characters
*
* @link http://php.net/manual/en/function.wordwrap.php for similarity
* @param string $str the string to wrap
* @param int $width the width of the output
* @param string $break the character used to break the line
* @param boolean $cut ignored parameter, just for the sake of
* @return string wrapped string
* @author Rodney Rehm
*/
function smarty_mb_wordwrap($str, $width=75, $break="\n", $cut=false)
{
// break words into tokens using white space as a delimiter
$tokens = preg_split('!(\s)!S' . Smarty::$_UTF8_MODIFIER, $str, -1, PREG_SPLIT_NO_EMPTY + PREG_SPLIT_DELIM_CAPTURE);
$length = 0;
$t = '';
$_previous = false;
foreach ($tokens as $_token) {
$token_length = mb_strlen($_token, Smarty::$_CHARSET);
$_tokens = array($_token);
if ($token_length > $width) {
// remove last space
$t = mb_substr($t, 0, -1, Smarty::$_CHARSET);
$_previous = false;
$length = 0;
if ($cut) {
$_tokens = preg_split('!(.{' . $width . '})!S' . Smarty::$_UTF8_MODIFIER, $_token, -1, PREG_SPLIT_NO_EMPTY + PREG_SPLIT_DELIM_CAPTURE);
// broken words go on a new line
$t .= $break;
}
}
foreach ($_tokens as $token) {
$_space = !!preg_match('!^\s$!S' . Smarty::$_UTF8_MODIFIER, $token);
$token_length = mb_strlen($token, Smarty::$_CHARSET);
$length += $token_length;
if ($length > $width) {
// remove space before inserted break
if ($_previous && $token_length < $width) {
$t = mb_substr($t, 0, -1, Smarty::$_CHARSET);
}
// add the break before the token
$t .= $break;
$length = $token_length;
// skip space after inserting a break
if ($_space) {
$length = 0;
continue;
}
} else if ($token == "\n") {
// hard break must reset counters
$_previous = 0;
$length = 0;
} else {
// remember if we had a space or not
$_previous = $_space;
}
// add the token
$t .= $token;
}
}
return $t;
}
}
?>

View File

@ -0,0 +1,21 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFilter
*/
/**
* Smarty htmlspecialchars variablefilter plugin
*
* @param string $source input string
* @param Smarty_Internal_Template $smarty Smarty object
* @return string filtered output
*/
function smarty_variablefilter_htmlspecialchars($source, $smarty)
{
return htmlspecialchars($source, ENT_QUOTES, Smarty::$_CHARSET);
}
?>

View File

@ -0,0 +1,381 @@
<?php
/**
* Smarty Internal Plugin
*
* @package Smarty
* @subpackage Cacher
*/
/**
* Cache Handler API
*
* @package Smarty
* @subpackage Cacher
* @author Rodney Rehm
*/
abstract class Smarty_CacheResource {
/**
* cache for Smarty_CacheResource instances
* @var array
*/
public static $resources = array();
/**
* resource types provided by the core
* @var array
*/
protected static $sysplugins = array(
'file' => true,
);
/**
* populate Cached Object with meta data from Resource
*
* @param Smarty_Template_Cached $cached cached object
* @param Smarty_Internal_Template $_template template object
* @return void
*/
public abstract function populate(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template);
/**
* populate Cached Object with timestamp and exists from Resource
*
* @param Smarty_Template_Cached $source cached object
* @return void
*/
public abstract function populateTimestamp(Smarty_Template_Cached $cached);
/**
* Read the cached template and process header
*
* @param Smarty_Internal_Template $_template template object
* @param Smarty_Template_Cached $cached cached object
* @return booelan true or false if the cached content does not exist
*/
public abstract function process(Smarty_Internal_Template $_template, Smarty_Template_Cached $cached=null);
/**
* Write the rendered template output to cache
*
* @param Smarty_Internal_Template $_template template object
* @param string $content content to cache
* @return boolean success
*/
public abstract function writeCachedContent(Smarty_Internal_Template $_template, $content);
/**
* Return cached content
*
* @param Smarty_Internal_Template $_template template object
* @param string $content content of cache
*/
public function getCachedContent(Smarty_Internal_Template $_template)
{
if ($_template->cached->handler->process($_template)) {
ob_start();
$_template->properties['unifunc']($_template);
return ob_get_clean();
}
return null;
}
/**
* Empty cache
*
* @param Smarty $smarty Smarty object
* @param integer $exp_time expiration time (number of seconds, not timestamp)
* @return integer number of cache files deleted
*/
public abstract function clearAll(Smarty $smarty, $exp_time=null);
/**
* Empty cache for a specific template
*
* @param Smarty $smarty Smarty object
* @param string $resource_name template name
* @param string $cache_id cache id
* @param string $compile_id compile id
* @param integer $exp_time expiration time (number of seconds, not timestamp)
* @return integer number of cache files deleted
*/
public abstract function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time);
public function locked(Smarty $smarty, Smarty_Template_Cached $cached)
{
// theoretically locking_timeout should be checked against time_limit (max_execution_time)
$start = microtime(true);
$hadLock = null;
while ($this->hasLock($smarty, $cached)) {
$hadLock = true;
if (microtime(true) - $start > $smarty->locking_timeout) {
// abort waiting for lock release
return false;
}
sleep(1);
}
return $hadLock;
}
public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached)
{
// check if lock exists
return false;
}
public function acquireLock(Smarty $smarty, Smarty_Template_Cached $cached)
{
// create lock
return true;
}
public function releaseLock(Smarty $smarty, Smarty_Template_Cached $cached)
{
// release lock
return true;
}
/**
* Load Cache Resource Handler
*
* @param Smarty $smarty Smarty object
* @param string $type name of the cache resource
* @return Smarty_CacheResource Cache Resource Handler
*/
public static function load(Smarty $smarty, $type = null)
{
if (!isset($type)) {
$type = $smarty->caching_type;
}
// try smarty's cache
if (isset($smarty->_cacheresource_handlers[$type])) {
return $smarty->_cacheresource_handlers[$type];
}
// try registered resource
if (isset($smarty->registered_cache_resources[$type])) {
// do not cache these instances as they may vary from instance to instance
return $smarty->_cacheresource_handlers[$type] = $smarty->registered_cache_resources[$type];
}
// try sysplugins dir
if (isset(self::$sysplugins[$type])) {
if (!isset(self::$resources[$type])) {
$cache_resource_class = 'Smarty_Internal_CacheResource_' . ucfirst($type);
self::$resources[$type] = new $cache_resource_class();
}
return $smarty->_cacheresource_handlers[$type] = self::$resources[$type];
}
// try plugins dir
$cache_resource_class = 'Smarty_CacheResource_' . ucfirst($type);
if ($smarty->loadPlugin($cache_resource_class)) {
if (!isset(self::$resources[$type])) {
self::$resources[$type] = new $cache_resource_class();
}
return $smarty->_cacheresource_handlers[$type] = self::$resources[$type];
}
// give up
throw new SmartyException("Unable to load cache resource '{$type}'");
}
/**
* Invalid Loaded Cache Files
*
* @param Smarty $smarty Smarty object
*/
public static function invalidLoadedCache(Smarty $smarty)
{
foreach ($smarty->template_objects as $tpl) {
if (isset($tpl->cached)) {
$tpl->cached->valid = false;
$tpl->cached->processed = false;
}
}
}
}
/**
* Smarty Resource Data Object
*
* Cache Data Container for Template Files
*
* @package Smarty
* @subpackage TemplateResources
* @author Rodney Rehm
*/
class Smarty_Template_Cached {
/**
* Source Filepath
* @var string
*/
public $filepath = false;
/**
* Source Content
* @var string
*/
public $content = null;
/**
* Source Timestamp
* @var integer
*/
public $timestamp = false;
/**
* Source Existance
* @var boolean
*/
public $exists = false;
/**
* Cache Is Valid
* @var boolean
*/
public $valid = false;
/**
* Cache was processed
* @var boolean
*/
public $processed = false;
/**
* CacheResource Handler
* @var Smarty_CacheResource
*/
public $handler = null;
/**
* Template Compile Id (Smarty_Internal_Template::$compile_id)
* @var string
*/
public $compile_id = null;
/**
* Template Cache Id (Smarty_Internal_Template::$cache_id)
* @var string
*/
public $cache_id = null;
/**
* Id for cache locking
* @var string
*/
public $lock_id = null;
/**
* flag that cache is locked by this instance
* @var bool
*/
public $is_locked = false;
/**
* Source Object
* @var Smarty_Template_Source
*/
public $source = null;
/**
* create Cached Object container
*
* @param Smarty_Internal_Template $_template template object
*/
public function __construct(Smarty_Internal_Template $_template)
{
$this->compile_id = $_template->compile_id;
$this->cache_id = $_template->cache_id;
$this->source = $_template->source;
$_template->cached = $this;
$smarty = $_template->smarty;
//
// load resource handler
//
$this->handler = $handler = Smarty_CacheResource::load($smarty); // Note: prone to circular references
//
// check if cache is valid
//
if (!($_template->caching == Smarty::CACHING_LIFETIME_CURRENT || $_template->caching == Smarty::CACHING_LIFETIME_SAVED) || $_template->source->recompiled) {
$handler->populate($this, $_template);
return;
}
while (true) {
while (true) {
$handler->populate($this, $_template);
if ($this->timestamp === false || $smarty->force_compile || $smarty->force_cache) {
$this->valid = false;
} else {
$this->valid = true;
}
if ($this->valid && $_template->caching == Smarty::CACHING_LIFETIME_CURRENT && $_template->cache_lifetime >= 0 && time() > ($this->timestamp + $_template->cache_lifetime)) {
// lifetime expired
$this->valid = false;
}
if ($this->valid || !$_template->smarty->cache_locking) {
break;
}
if (!$this->handler->locked($_template->smarty, $this)) {
$this->handler->acquireLock($_template->smarty, $this);
break 2;
}
}
if ($this->valid) {
if (!$_template->smarty->cache_locking || $this->handler->locked($_template->smarty, $this) === null) {
// load cache file for the following checks
if ($smarty->debugging) {
Smarty_Internal_Debug::start_cache($_template);
}
if($handler->process($_template, $this) === false) {
$this->valid = false;
} else {
$this->processed = true;
}
if ($smarty->debugging) {
Smarty_Internal_Debug::end_cache($_template);
}
} else {
continue;
}
} else {
return;
}
if ($this->valid && $_template->caching === Smarty::CACHING_LIFETIME_SAVED && $_template->properties['cache_lifetime'] >= 0 && (time() > ($_template->cached->timestamp + $_template->properties['cache_lifetime']))) {
$this->valid = false;
}
if (!$this->valid && $_template->smarty->cache_locking) {
$this->handler->acquireLock($_template->smarty, $this);
return;
} else {
return;
}
}
}
/**
* Write this cache object to handler
*
* @param Smarty_Internal_Template $_template template object
* @param string $content content to cache
* @return boolean success
*/
public function write(Smarty_Internal_Template $_template, $content)
{
if (!$_template->source->recompiled) {
if ($this->handler->writeCachedContent($_template, $content)) {
$this->timestamp = time();
$this->exists = true;
$this->valid = true;
if ($_template->smarty->cache_locking) {
$this->handler->releaseLock($_template->smarty, $this);
}
return true;
}
}
return false;
}
}
?>

View File

@ -0,0 +1,237 @@
<?php
/**
* Smarty Internal Plugin
*
* @package Smarty
* @subpackage Cacher
*/
/**
* Cache Handler API
*
* @package Smarty
* @subpackage Cacher
* @author Rodney Rehm
*/
abstract class Smarty_CacheResource_Custom extends Smarty_CacheResource {
/**
* 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 abstract function fetch($id, $name, $cache_id, $compile_id, &$content, &$mtime);
/**
* 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 $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)
{
return null;
}
/**
* 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 or null
* @param string $content content to cache
* @return boolean success
*/
protected abstract function save($id, $name, $cache_id, $compile_id, $exp_time, $content);
/**
* 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 time in seconds or null
* @return integer number of deleted caches
*/
protected abstract function delete($name, $cache_id, $compile_id, $exp_time);
/**
* populate Cached Object with meta data from Resource
*
* @param Smarty_Template_Cached $cached cached object
* @param Smarty_Internal_Template $_template template object
* @return void
*/
public function populate(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template)
{
$_cache_id = isset($cached->cache_id) ? preg_replace('![^\w\|]+!', '_', $cached->cache_id) : null;
$_compile_id = isset($cached->compile_id) ? preg_replace('![^\w\|]+!', '_', $cached->compile_id) : null;
$cached->filepath = sha1($cached->source->filepath . $_cache_id . $_compile_id);
$this->populateTimestamp($cached);
}
/**
* populate Cached Object with timestamp and exists from Resource
*
* @param Smarty_Template_Cached $source cached object
* @return void
*/
public function populateTimestamp(Smarty_Template_Cached $cached)
{
$mtime = $this->fetchTimestamp($cached->filepath, $cached->source->name, $cached->cache_id, $cached->compile_id);
if ($mtime !== null) {
$cached->timestamp = $mtime;
$cached->exists = !!$cached->timestamp;
return;
}
$timestamp = null;
$this->fetch($cached->filepath, $cached->source->name, $cached->cache_id, $cached->compile_id, $cached->content, $timestamp);
$cached->timestamp = isset($timestamp) ? $timestamp : false;
$cached->exists = !!$cached->timestamp;
}
/**
* Read the cached template and process the header
*
* @param Smarty_Internal_Template $_template template object
* @param Smarty_Template_Cached $cached cached object
* @return booelan true or false if the cached content does not exist
*/
public function process(Smarty_Internal_Template $_template, Smarty_Template_Cached $cached=null)
{
if (!$cached) {
$cached = $_template->cached;
}
$content = $cached->content ? $cached->content : null;
$timestamp = $cached->timestamp ? $cached->timestamp : null;
if ($content === null || !$timestamp) {
$this->fetch(
$_template->cached->filepath,
$_template->source->name,
$_template->cache_id,
$_template->compile_id,
$content,
$timestamp
);
}
if (isset($content)) {
$_smarty_tpl = $_template;
eval("?>" . $content);
return true;
}
return false;
}
/**
* Write the rendered template output to cache
*
* @param Smarty_Internal_Template $_template template object
* @param string $content content to cache
* @return boolean success
*/
public function writeCachedContent(Smarty_Internal_Template $_template, $content)
{
return $this->save(
$_template->cached->filepath,
$_template->source->name,
$_template->cache_id,
$_template->compile_id,
$_template->properties['cache_lifetime'],
$content
);
}
/**
* Empty cache
*
* @param Smarty $smarty Smarty object
* @param integer $exp_time expiration time (number of seconds, not timestamp)
* @return integer number of cache files deleted
*/
public function clearAll(Smarty $smarty, $exp_time=null)
{
$this->cache = array();
return $this->delete(null, null, null, $exp_time);
}
/**
* Empty cache for a specific template
*
* @param Smarty $smarty Smarty object
* @param string $resource_name template name
* @param string $cache_id cache id
* @param string $compile_id compile id
* @param integer $exp_time expiration time (number of seconds, not timestamp)
* @return integer number of cache files deleted
*/
public function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time)
{
$this->cache = array();
return $this->delete($resource_name, $cache_id, $compile_id, $exp_time);
}
/**
* Check is cache is locked for this template
*
* @param Smarty $smarty Smarty object
* @param Smarty_Template_Cached $cached cached object
* @return booelan true or false if cache is locked
*/
public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached)
{
$id = $cached->filepath;
$name = $cached->source->name . '.lock';
$mtime = $this->fetchTimestamp($id, $name, null, null);
if ($mtime === null) {
$this->fetch($id, $name, null, null, $content, $mtime);
}
return $mtime && time() - $mtime < $smarty->locking_timeout;
}
/**
* Lock cache for this template
*
* @param Smarty $smarty Smarty object
* @param Smarty_Template_Cached $cached cached object
*/
public function acquireLock(Smarty $smarty, Smarty_Template_Cached $cached)
{
$cached->is_locked = true;
$id = $cached->filepath;
$name = $cached->source->name . '.lock';
$this->save($id, $name, null, null, $smarty->locking_timeout, '');
}
/**
* Unlock cache for this template
*
* @param Smarty $smarty Smarty object
* @param Smarty_Template_Cached $cached cached object
*/
public function releaseLock(Smarty $smarty, Smarty_Template_Cached $cached)
{
$cached->is_locked = false;
$name = $cached->source->name . '.lock';
$this->delete($name, null, null, null);
}
}
?>

View File

@ -0,0 +1,463 @@
<?php
/**
* Smarty Internal Plugin
*
* @package Smarty
* @subpackage Cacher
*/
/**
* Smarty Cache Handler Base for Key/Value Storage Implementations
*
* This class implements the functionality required to use simple key/value stores
* for hierarchical cache groups. key/value stores like memcache or APC do not support
* wildcards in keys, therefore a cache group cannot be cleared like "a|*" - which
* is no problem to filesystem and RDBMS implementations.
*
* This implementation is based on the concept of invalidation. While one specific cache
* can be identified and cleared, any range of caches cannot be identified. For this reason
* each level of the cache group hierarchy can have its own value in the store. These values
* are nothing but microtimes, telling us when a particular cache group was cleared for the
* last time. These keys are evaluated for every cache read to determine if the cache has
* been invalidated since it was created and should hence be treated as inexistent.
*
* Although deep hierarchies are possible, they are not recommended. Try to keep your
* cache groups as shallow as possible. Anything up 3-5 parents should be ok. So
* »a|b| is a good depth where »a|b|c|d|e|f|g|h|i|j| isn't. Try to join correlating
* cache groups: if your cache groups look somewhat like »a|b|$page|$items|$whatever«
* consider using »a|b|c|$page-$items-$whatever« instead.
*
* @package Smarty
* @subpackage Cacher
* @author Rodney Rehm
*/
abstract class Smarty_CacheResource_KeyValueStore extends Smarty_CacheResource {
/**
* cache for contents
* @var array
*/
protected $contents = array();
/**
* cache for timestamps
* @var array
*/
protected $timestamps = array();
/**
* populate Cached Object with meta data from Resource
*
* @param Smarty_Template_Cached $cached cached object
* @param Smarty_Internal_Template $_template template object
* @return void
*/
public function populate(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template)
{
$cached->filepath = $_template->source->uid
. '#' . $this->sanitize($cached->source->name)
. '#' . $this->sanitize($cached->cache_id)
. '#' . $this->sanitize($cached->compile_id);
$this->populateTimestamp($cached);
}
/**
* populate Cached Object with timestamp and exists from Resource
*
* @param Smarty_Template_Cached $cached cached object
* @return void
*/
public function populateTimestamp(Smarty_Template_Cached $cached)
{
if (!$this->fetch($cached->filepath, $cached->source->name, $cached->cache_id, $cached->compile_id, $content, $timestamp, $cached->source->uid)) {
return;
}
$cached->content = $content;
$cached->timestamp = (int) $timestamp;
$cached->exists = $cached->timestamp;
}
/**
* Read the cached template and process the header
*
* @param Smarty_Internal_Template $_template template object
* @param Smarty_Template_Cached $cached cached object
* @return booelan true or false if the cached content does not exist
*/
public function process(Smarty_Internal_Template $_template, Smarty_Template_Cached $cached=null)
{
if (!$cached) {
$cached = $_template->cached;
}
$content = $cached->content ? $cached->content : null;
$timestamp = $cached->timestamp ? $cached->timestamp : null;
if ($content === null || !$timestamp) {
if (!$this->fetch($_template->cached->filepath, $_template->source->name, $_template->cache_id, $_template->compile_id, $content, $timestamp, $_template->source->uid)) {
return false;
}
}
if (isset($content)) {
$_smarty_tpl = $_template;
eval("?>" . $content);
return true;
}
return false;
}
/**
* Write the rendered template output to cache
*
* @param Smarty_Internal_Template $_template template object
* @param string $content content to cache
* @return boolean success
*/
public function writeCachedContent(Smarty_Internal_Template $_template, $content)
{
$this->addMetaTimestamp($content);
return $this->write(array($_template->cached->filepath => $content), $_template->properties['cache_lifetime']);
}
/**
* Empty cache
*
* {@internal the $exp_time argument is ignored altogether }}
*
* @param Smarty $smarty Smarty object
* @param integer $exp_time expiration time [being ignored]
* @return integer number of cache files deleted [always -1]
* @uses purge() to clear the whole store
* @uses invalidate() to mark everything outdated if purge() is inapplicable
*/
public function clearAll(Smarty $smarty, $exp_time=null)
{
if (!$this->purge()) {
$this->invalidate(null);
}
return -1;
}
/**
* Empty cache for a specific template
*
* {@internal the $exp_time argument is ignored altogether}}
*
* @param Smarty $smarty Smarty object
* @param string $resource_name template name
* @param string $cache_id cache id
* @param string $compile_id compile id
* @param integer $exp_time expiration time [being ignored]
* @return integer number of cache files deleted [always -1]
* @uses buildCachedFilepath() to generate the CacheID
* @uses invalidate() to mark CacheIDs parent chain as outdated
* @uses delete() to remove CacheID from cache
*/
public function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time)
{
$uid = $this->getTemplateUid($smarty, $resource_name, $cache_id, $compile_id);
$cid = $uid . '#' . $this->sanitize($resource_name) . '#' . $this->sanitize($cache_id) . '#' . $this->sanitize($compile_id);
$this->delete(array($cid));
$this->invalidate($cid, $resource_name, $cache_id, $compile_id, $uid);
return -1;
}
/**
* Get template's unique ID
*
* @param Smarty $smarty Smarty object
* @param string $resource_name template name
* @param string $cache_id cache id
* @param string $compile_id compile id
* @return string filepath of cache file
*/
protected function getTemplateUid(Smarty $smarty, $resource_name, $cache_id, $compile_id)
{
$uid = '';
if (isset($resource_name)) {
$tpl = new $smarty->template_class($resource_name, $smarty);
if ($tpl->source->exists) {
$uid = $tpl->source->uid;
}
// remove from template cache
if ($smarty->allow_ambiguous_resources) {
$_templateId = $tpl->source->unique_resource . $tpl->cache_id . $tpl->compile_id;
} else {
$_templateId = $smarty->joined_template_dir . '#' . $resource_name . $tpl->cache_id . $tpl->compile_id;
}
if (isset($_templateId[150])) {
$_templateId = sha1($_templateId);
}
unset($smarty->template_objects[$_templateId]);
}
return $uid;
}
/**
* Sanitize CacheID components
*
* @param string $string CacheID component to sanitize
* @return string sanitized CacheID component
*/
protected function sanitize($string)
{
// some poeple smoke bad weed
$string = trim($string, '|');
if (!$string) {
return null;
}
return preg_replace('#[^\w\|]+#S', '_', $string);
}
/**
* Fetch and prepare a cache object.
*
* @param string $cid CacheID to fetch
* @param string $resource_name template name
* @param string $cache_id cache id
* @param string $compile_id compile id
* @param string $content cached content
* @param integer &$timestamp cached timestamp (epoch)
* @param string $resource_uid resource's uid
* @return boolean success
*/
protected function fetch($cid, $resource_name = null, $cache_id = null, $compile_id = null, &$content = null, &$timestamp = null, $resource_uid = null)
{
$t = $this->read(array($cid));
$content = !empty($t[$cid]) ? $t[$cid] : null;
$timestamp = null;
if ($content && ($timestamp = $this->getMetaTimestamp($content))) {
$invalidated = $this->getLatestInvalidationTimestamp($cid, $resource_name, $cache_id, $compile_id, $resource_uid);
if ($invalidated > $timestamp) {
$timestamp = null;
$content = null;
}
}
return !!$content;
}
/**
* Add current microtime to the beginning of $cache_content
*
* {@internal the header uses 8 Bytes, the first 4 Bytes are the seconds, the second 4 Bytes are the microseconds}}
*
* @param string &$content the content to be cached
*/
protected function addMetaTimestamp(&$content)
{
$mt = explode(" ", microtime());
$ts = pack("NN", $mt[1], (int) ($mt[0] * 100000000));
$content = $ts . $content;
}
/**
* Extract the timestamp the $content was cached
*
* @param string &$content the cached content
* @return float the microtime the content was cached
*/
protected function getMetaTimestamp(&$content)
{
$s = unpack("N", substr($content, 0, 4));
$m = unpack("N", substr($content, 4, 4));
$content = substr($content, 8);
return $s[1] + ($m[1] / 100000000);
}
/**
* Invalidate CacheID
*
* @param string $cid CacheID
* @param string $resource_name template name
* @param string $cache_id cache id
* @param string $compile_id compile id
* @param string $resource_uid source's uid
* @return void
*/
protected function invalidate($cid = null, $resource_name = null, $cache_id = null, $compile_id = null, $resource_uid = null)
{
$now = microtime(true);
$key = null;
// invalidate everything
if (!$resource_name && !$cache_id && !$compile_id) {
$key = 'IVK#ALL';
}
// invalidate all caches by template
else if ($resource_name && !$cache_id && !$compile_id) {
$key = 'IVK#TEMPLATE#' . $resource_uid . '#' . $this->sanitize($resource_name);
}
// invalidate all caches by cache group
else if (!$resource_name && $cache_id && !$compile_id) {
$key = 'IVK#CACHE#' . $this->sanitize($cache_id);
}
// invalidate all caches by compile id
else if (!$resource_name && !$cache_id && $compile_id) {
$key = 'IVK#COMPILE#' . $this->sanitize($compile_id);
}
// invalidate by combination
else {
$key = 'IVK#CID#' . $cid;
}
$this->write(array($key => $now));
}
/**
* Determine the latest timestamp known to the invalidation chain
*
* @param string $cid CacheID to determine latest invalidation timestamp of
* @param string $resource_name template name
* @param string $cache_id cache id
* @param string $compile_id compile id
* @param string $resource_uid source's filepath
* @return float the microtime the CacheID was invalidated
*/
protected function getLatestInvalidationTimestamp($cid, $resource_name = null, $cache_id = null, $compile_id = null, $resource_uid = null)
{
// abort if there is no CacheID
if (false && !$cid) {
return 0;
}
// abort if there are no InvalidationKeys to check
if (!($_cid = $this->listInvalidationKeys($cid, $resource_name, $cache_id, $compile_id, $resource_uid))) {
return 0;
}
// there are no InValidationKeys
if (!($values = $this->read($_cid))) {
return 0;
}
// make sure we're dealing with floats
$values = array_map('floatval', $values);
return max($values);
}
/**
* Translate a CacheID into the list of applicable InvalidationKeys.
*
* Splits "some|chain|into|an|array" into array( '#clearAll#', 'some', 'some|chain', 'some|chain|into', ... )
*
* @param string $cid CacheID to translate
* @param string $resource_name template name
* @param string $cache_id cache id
* @param string $compile_id compile id
* @param string $resource_uid source's filepath
* @return array list of InvalidationKeys
* @uses $invalidationKeyPrefix to prepend to each InvalidationKey
*/
protected function listInvalidationKeys($cid, $resource_name = null, $cache_id = null, $compile_id = null, $resource_uid = null)
{
$t = array('IVK#ALL');
$_name = $_compile = '#';
if ($resource_name) {
$_name .= $resource_uid . '#' . $this->sanitize($resource_name);
$t[] = 'IVK#TEMPLATE' . $_name;
}
if ($compile_id) {
$_compile .= $this->sanitize($compile_id);
$t[] = 'IVK#COMPILE' . $_compile;
}
$_name .= '#';
// some poeple smoke bad weed
$cid = trim($cache_id, '|');
if (!$cid) {
return $t;
}
$i = 0;
while (true) {
// determine next delimiter position
$i = strpos($cid, '|', $i);
// add complete CacheID if there are no more delimiters
if ($i === false) {
$t[] = 'IVK#CACHE#' . $cid;
$t[] = 'IVK#CID' . $_name . $cid . $_compile;
$t[] = 'IVK#CID' . $_name . $_compile;
break;
}
$part = substr($cid, 0, $i);
// add slice to list
$t[] = 'IVK#CACHE#' . $part;
$t[] = 'IVK#CID' . $_name . $part . $_compile;
// skip past delimiter position
$i++;
}
return $t;
}
/**
* Check is cache is locked for this template
*
* @param Smarty $smarty Smarty object
* @param Smarty_Template_Cached $cached cached object
* @return booelan true or false if cache is locked
*/
public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached)
{
$key = 'LOCK#' . $cached->filepath;
$data = $this->read(array($key));
return $data && time() - $data[$key] < $smarty->locking_timeout;
}
/**
* Lock cache for this template
*
* @param Smarty $smarty Smarty object
* @param Smarty_Template_Cached $cached cached object
*/
public function acquireLock(Smarty $smarty, Smarty_Template_Cached $cached)
{
$cached->is_locked = true;
$key = 'LOCK#' . $cached->filepath;
$this->write(array($key => time()), $smarty->locking_timeout);
}
/**
* Unlock cache for this template
*
* @param Smarty $smarty Smarty object
* @param Smarty_Template_Cached $cached cached object
*/
public function releaseLock(Smarty $smarty, Smarty_Template_Cached $cached)
{
$cached->is_locked = false;
$key = 'LOCK#' . $cached->filepath;
$this->delete(array($key));
}
/**
* 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
*/
protected abstract function read(array $keys);
/**
* 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 abstract function write(array $keys, $expire=null);
/**
* Remove values from cache
*
* @param array $keys list of keys to delete
* @return boolean true on success, false on failure
*/
protected abstract function delete(array $keys);
/**
* Remove *all* values from cache
*
* @return boolean true on success, false on failure
*/
protected function purge()
{
return false;
}
}
?>

View File

@ -0,0 +1,95 @@
<?php
/**
* Smarty Internal Plugin
*
* @package Smarty
* @subpackage TemplateResources
*/
/**
* Smarty Resource Data Object
*
* Meta Data Container for Config Files
*
* @package Smarty
* @subpackage TemplateResources
* @author Rodney Rehm
*
* @property string $content
* @property int $timestamp
* @property bool $exists
*/
class Smarty_Config_Source extends Smarty_Template_Source {
/**
* create Config Object container
*
* @param Smarty_Resource $handler Resource Handler this source object communicates with
* @param Smarty $smarty Smarty instance this source object belongs to
* @param string $resource full config_resource
* @param string $type type of resource
* @param string $name resource name
* @param string $unique_resource unqiue resource name
*/
public function __construct(Smarty_Resource $handler, Smarty $smarty, $resource, $type, $name, $unique_resource)
{
$this->handler = $handler; // Note: prone to circular references
// Note: these may be ->config_compiler_class etc in the future
//$this->config_compiler_class = $handler->config_compiler_class;
//$this->config_lexer_class = $handler->config_lexer_class;
//$this->config_parser_class = $handler->config_parser_class;
$this->smarty = $smarty;
$this->resource = $resource;
$this->type = $type;
$this->name = $name;
$this->unique_resource = $unique_resource;
}
/**
* <<magic>> Generic setter.
*
* @param string $property_name valid: content, timestamp, exists
* @param mixed $value newly assigned value (not check for correct type)
* @throws SmartyException when the given property name is not valid
*/
public function __set($property_name, $value)
{
switch ($property_name) {
case 'content':
case 'timestamp':
case 'exists':
$this->$property_name = $value;
break;
default:
throw new SmartyException("invalid config property '$property_name'.");
}
}
/**
* <<magic>> Generic getter.
*
* @param string $property_name valid: content, timestamp, exists
* @throws SmartyException when the given property name is not valid
*/
public function __get($property_name)
{
switch ($property_name) {
case 'timestamp':
case 'exists':
$this->handler->populateTimestamp($this);
return $this->$property_name;
case 'content':
return $this->content = $this->handler->getContent($this);
default:
throw new SmartyException("config property '$property_name' does not exist.");
}
}
}
?>

View File

@ -0,0 +1,266 @@
<?php
/**
* Smarty Internal Plugin CacheResource File
*
* @package Smarty
* @subpackage Cacher
* @author Uwe Tews
* @author Rodney Rehm
*/
/**
* This class does contain all necessary methods for the HTML cache on file system
*
* Implements the file system as resource for the HTML cache Version ussing nocache inserts.
*
* @package Smarty
* @subpackage Cacher
*/
class Smarty_Internal_CacheResource_File extends Smarty_CacheResource {
/**
* populate Cached Object with meta data from Resource
*
* @param Smarty_Template_Cached $cached cached object
* @param Smarty_Internal_Template $_template template object
* @return void
*/
public function populate(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template)
{
$_source_file_path = str_replace(':', '.', $_template->source->filepath);
$_cache_id = isset($_template->cache_id) ? preg_replace('![^\w\|]+!', '_', $_template->cache_id) : null;
$_compile_id = isset($_template->compile_id) ? preg_replace('![^\w\|]+!', '_', $_template->compile_id) : null;
$_filepath = $_template->source->uid;
// if use_sub_dirs, break file into directories
if ($_template->smarty->use_sub_dirs) {
$_filepath = substr($_filepath, 0, 2) . DS
. substr($_filepath, 2, 2) . DS
. substr($_filepath, 4, 2) . DS
. $_filepath;
}
$_compile_dir_sep = $_template->smarty->use_sub_dirs ? DS : '^';
if (isset($_cache_id)) {
$_cache_id = str_replace('|', $_compile_dir_sep, $_cache_id) . $_compile_dir_sep;
} else {
$_cache_id = '';
}
if (isset($_compile_id)) {
$_compile_id = $_compile_id . $_compile_dir_sep;
} else {
$_compile_id = '';
}
$_cache_dir = $_template->smarty->getCacheDir();
if ($_template->smarty->cache_locking) {
// create locking file name
// relative file name?
if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_cache_dir)) {
$_lock_dir = rtrim(getcwd(), '/\\') . DS . $_cache_dir;
} else {
$_lock_dir = $_cache_dir;
}
$cached->lock_id = $_lock_dir.sha1($_cache_id.$_compile_id.$_template->source->uid).'.lock';
}
$cached->filepath = $_cache_dir . $_cache_id . $_compile_id . $_filepath . '.' . basename($_source_file_path) . '.php';
$cached->timestamp = @filemtime($cached->filepath);
$cached->exists = !!$cached->timestamp;
}
/**
* populate Cached Object with timestamp and exists from Resource
*
* @param Smarty_Template_Cached $cached cached object
* @return void
*/
public function populateTimestamp(Smarty_Template_Cached $cached)
{
$cached->timestamp = @filemtime($cached->filepath);
$cached->exists = !!$cached->timestamp;
}
/**
* Read the cached template and process its header
*
* @param Smarty_Internal_Template $_template template object
* @param Smarty_Template_Cached $cached cached object
* @return booelan true or false if the cached content does not exist
*/
public function process(Smarty_Internal_Template $_template, Smarty_Template_Cached $cached=null)
{
$_smarty_tpl = $_template;
return @include $_template->cached->filepath;
}
/**
* Write the rendered template output to cache
*
* @param Smarty_Internal_Template $_template template object
* @param string $content content to cache
* @return boolean success
*/
public function writeCachedContent(Smarty_Internal_Template $_template, $content)
{
if (Smarty_Internal_Write_File::writeFile($_template->cached->filepath, $content, $_template->smarty) === true) {
$_template->cached->timestamp = @filemtime($_template->cached->filepath);
$_template->cached->exists = !!$_template->cached->timestamp;
if ($_template->cached->exists) {
return true;
}
}
return false;
}
/**
* Empty cache
*
* @param Smarty_Internal_Template $_template template object
* @param integer $exp_time expiration time (number of seconds, not timestamp)
* @return integer number of cache files deleted
*/
public function clearAll(Smarty $smarty, $exp_time = null)
{
return $this->clear($smarty, null, null, null, $exp_time);
}
/**
* Empty cache for a specific template
*
* @param Smarty $_template template object
* @param string $resource_name template name
* @param string $cache_id cache id
* @param string $compile_id compile id
* @param integer $exp_time expiration time (number of seconds, not timestamp)
* @return integer number of cache files deleted
*/
public function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time)
{
$_cache_id = isset($cache_id) ? preg_replace('![^\w\|]+!', '_', $cache_id) : null;
$_compile_id = isset($compile_id) ? preg_replace('![^\w\|]+!', '_', $compile_id) : null;
$_dir_sep = $smarty->use_sub_dirs ? '/' : '^';
$_compile_id_offset = $smarty->use_sub_dirs ? 3 : 0;
$_dir = $smarty->getCacheDir();
$_dir_length = strlen($_dir);
if (isset($_cache_id)) {
$_cache_id_parts = explode('|', $_cache_id);
$_cache_id_parts_count = count($_cache_id_parts);
if ($smarty->use_sub_dirs) {
foreach ($_cache_id_parts as $id_part) {
$_dir .= $id_part . DS;
}
}
}
if (isset($resource_name)) {
$_save_stat = $smarty->caching;
$smarty->caching = true;
$tpl = new $smarty->template_class($resource_name, $smarty);
$smarty->caching = $_save_stat;
// remove from template cache
$tpl->source; // have the template registered before unset()
if ($smarty->allow_ambiguous_resources) {
$_templateId = $tpl->source->unique_resource . $tpl->cache_id . $tpl->compile_id;
} else {
$_templateId = $smarty->joined_template_dir . '#' . $resource_name . $tpl->cache_id . $tpl->compile_id;
}
if (isset($_templateId[150])) {
$_templateId = sha1($_templateId);
}
unset($smarty->template_objects[$_templateId]);
if ($tpl->source->exists) {
$_resourcename_parts = basename(str_replace('^', '/', $tpl->cached->filepath));
} else {
return 0;
}
}
$_count = 0;
$_time = time();
if (file_exists($_dir)) {
$_cacheDirs = new RecursiveDirectoryIterator($_dir);
$_cache = new RecursiveIteratorIterator($_cacheDirs, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($_cache as $_file) {
if (substr(basename($_file->getPathname()),0,1) == '.' || strpos($_file, '.svn') !== false) continue;
// directory ?
if ($_file->isDir()) {
if (!$_cache->isDot()) {
// delete folder if empty
@rmdir($_file->getPathname());
}
} else {
$_parts = explode($_dir_sep, str_replace('\\', '/', substr((string)$_file, $_dir_length)));
$_parts_count = count($_parts);
// check name
if (isset($resource_name)) {
if ($_parts[$_parts_count-1] != $_resourcename_parts) {
continue;
}
}
// check compile id
if (isset($_compile_id) && (!isset($_parts[$_parts_count-2 - $_compile_id_offset]) || $_parts[$_parts_count-2 - $_compile_id_offset] != $_compile_id)) {
continue;
}
// check cache id
if (isset($_cache_id)) {
// count of cache id parts
$_parts_count = (isset($_compile_id)) ? $_parts_count - 2 - $_compile_id_offset : $_parts_count - 1 - $_compile_id_offset;
if ($_parts_count < $_cache_id_parts_count) {
continue;
}
for ($i = 0; $i < $_cache_id_parts_count; $i++) {
if ($_parts[$i] != $_cache_id_parts[$i]) continue 2;
}
}
// expired ?
if (isset($exp_time) && $_time - @filemtime($_file) < $exp_time) {
continue;
}
$_count += @unlink((string) $_file) ? 1 : 0;
}
}
}
return $_count;
}
/**
* Check is cache is locked for this template
*
* @param Smarty $smarty Smarty object
* @param Smarty_Template_Cached $cached cached object
* @return booelan true or false if cache is locked
*/
public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached)
{
if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
clearstatcache(true, $cached->lock_id);
} else {
clearstatcache();
}
$t = @filemtime($cached->lock_id);
return $t && (time() - $t < $smarty->locking_timeout);
}
/**
* Lock cache for this template
*
* @param Smarty $smarty Smarty object
* @param Smarty_Template_Cached $cached cached object
*/
public function acquireLock(Smarty $smarty, Smarty_Template_Cached $cached)
{
$cached->is_locked = true;
touch($cached->lock_id);
}
/**
* Unlock cache for this template
*
* @param Smarty $smarty Smarty object
* @param Smarty_Template_Cached $cached cached object
*/
public function releaseLock(Smarty $smarty, Smarty_Template_Cached $cached)
{
$cached->is_locked = false;
@unlink($cached->lock_id);
}
}
?>

View File

@ -0,0 +1,53 @@
<?php
/**
* Smarty Internal Plugin Compile Append
*
* Compiles the {append} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Append Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Append extends Smarty_Internal_Compile_Assign {
/**
* Compiles code for the {append} tag
*
* @param array $args array with attributes from parser
* @param object $compiler compiler object
* @param array $parameter array with compilation parameter
* @return string compiled code
*/
public function compile($args, $compiler, $parameter)
{
// the following must be assigned at runtime because it will be overwritten in parent class
$this->required_attributes = array('var', 'value');
$this->shorttag_order = array('var', 'value');
$this->optional_attributes = array('scope', 'index');
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
// map to compile assign attributes
if (isset($_attr['index'])) {
$_params['smarty_internal_index'] = '[' . $_attr['index'] . ']';
unset($_attr['index']);
} else {
$_params['smarty_internal_index'] = '[]';
}
$_new_attr = array();
foreach ($_attr as $key => $value) {
$_new_attr[] = array($key => $value);
}
// call compile assign
return parent::compile($_new_attr, $compiler, $_params);
}
}
?>

View File

@ -0,0 +1,88 @@
<?php
/**
* Smarty Internal Plugin Compile Assign
*
* Compiles the {assign} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Assign Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Assign extends Smarty_Internal_CompileBase {
/**
* Compiles code for the {assign} tag
*
* @param array $args array with attributes from parser
* @param object $compiler compiler object
* @param array $parameter array with compilation parameter
* @return string compiled code
*/
public function compile($args, $compiler, $parameter)
{
// the following must be assigned at runtime because it will be overwritten in Smarty_Internal_Compile_Append
$this->required_attributes = array('var', 'value');
$this->shorttag_order = array('var', 'value');
$this->optional_attributes = array('scope');
$_nocache = 'null';
$_scope = Smarty::SCOPE_LOCAL;
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
// nocache ?
if ($compiler->tag_nocache || $compiler->nocache) {
$_nocache = 'true';
// create nocache var to make it know for further compiling
if (isset($compiler->template->tpl_vars[trim($_attr['var'], "'")])) {
$compiler->template->tpl_vars[trim($_attr['var'], "'")]->nocache = true;
} else {
$compiler->template->tpl_vars[trim($_attr['var'], "'")] = new Smarty_variable(null, true);
}
}
// scope setup
if (isset($_attr['scope'])) {
$_attr['scope'] = trim($_attr['scope'], "'\"");
if ($_attr['scope'] == 'parent') {
$_scope = Smarty::SCOPE_PARENT;
} elseif ($_attr['scope'] == 'root') {
$_scope = Smarty::SCOPE_ROOT;
} elseif ($_attr['scope'] == 'global') {
$_scope = Smarty::SCOPE_GLOBAL;
} else {
$compiler->trigger_template_error('illegal value for "scope" attribute', $compiler->lex->taglineno);
}
}
// compiled output
if (isset($parameter['smarty_internal_index'])) {
$output = "<?php \$_smarty_tpl->createLocalArrayVariable($_attr[var], $_nocache, $_scope);\n\$_smarty_tpl->tpl_vars[$_attr[var]]->value$parameter[smarty_internal_index] = $_attr[value];";
} else {
// implement Smarty2's behaviour of variables assigned by reference
if ($compiler->template->smarty instanceof SmartyBC) {
$output = "<?php if (isset(\$_smarty_tpl->tpl_vars[$_attr[var]])) {\$_smarty_tpl->tpl_vars[$_attr[var]] = clone \$_smarty_tpl->tpl_vars[$_attr[var]];";
$output .= "\n\$_smarty_tpl->tpl_vars[$_attr[var]]->value = $_attr[value]; \$_smarty_tpl->tpl_vars[$_attr[var]]->nocache = $_nocache; \$_smarty_tpl->tpl_vars[$_attr[var]]->scope = $_scope;";
$output .= "\n} else \$_smarty_tpl->tpl_vars[$_attr[var]] = new Smarty_variable($_attr[value], $_nocache, $_scope);";
} else {
$output = "<?php \$_smarty_tpl->tpl_vars[$_attr[var]] = new Smarty_variable($_attr[value], $_nocache, $_scope);";
}
}
if ($_scope == Smarty::SCOPE_PARENT) {
$output .= "\nif (\$_smarty_tpl->parent != null) \$_smarty_tpl->parent->tpl_vars[$_attr[var]] = clone \$_smarty_tpl->tpl_vars[$_attr[var]];";
} elseif ($_scope == Smarty::SCOPE_ROOT || $_scope == Smarty::SCOPE_GLOBAL) {
$output .= "\n\$_ptr = \$_smarty_tpl->parent; while (\$_ptr != null) {\$_ptr->tpl_vars[$_attr[var]] = clone \$_smarty_tpl->tpl_vars[$_attr[var]]; \$_ptr = \$_ptr->parent; }";
}
if ( $_scope == Smarty::SCOPE_GLOBAL) {
$output .= "\nSmarty::\$global_tpl_vars[$_attr[var]] = clone \$_smarty_tpl->tpl_vars[$_attr[var]];";
}
$output .= '?>';
return $output;
}
}
?>

View File

@ -0,0 +1,282 @@
<?php
/**
* Smarty Internal Plugin Compile Block
*
* Compiles the {block}{/block} tags
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Block Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase {
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $required_attributes = array('name');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $shorttag_order = array('name', 'hide');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('hide');
/**
* Compiles code for the {block} tag
*
* @param array $args array with attributes from parser
* @param object $compiler compiler object
* @return boolean true
*/
public function compile($args, $compiler) {
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$save = array($_attr, $compiler->parser->current_buffer, $compiler->nocache, $compiler->smarty->merge_compiled_includes, $compiler->merged_templates, $compiler->smarty->merged_templates_func, $compiler->template->properties, $compiler->template->has_nocache_code);
$this->openTag($compiler, 'block', $save);
if ($_attr['nocache'] == true) {
$compiler->nocache = true;
}
// set flag for {block} tag
$compiler->inheritance = true;
// must merge includes
$compiler->smarty->merge_compiled_includes = true;
$compiler->parser->current_buffer = new _smarty_template_buffer($compiler->parser);
$compiler->has_code = false;
return true;
}
/**
* Save or replace child block source by block name during parsing
*
* @param string $block_content block source content
* @param string $block_tag opening block tag
* @param object $template template object
* @param string $filepath filepath of template source
*/
public static function saveBlockData($block_content, $block_tag, $template, $filepath) {
$_rdl = preg_quote($template->smarty->right_delimiter);
$_ldl = preg_quote($template->smarty->left_delimiter);
if (!$template->smarty->auto_literal) {
$al = '\s*';
} else {
$al = '';
}
if (0 == preg_match("!({$_ldl}{$al}block\s+)(name=)?(\w+|'.*'|\".*\")(\s*?)?((append|prepend|nocache)?(\s*)?(hide)?)?(\s*{$_rdl})!", $block_tag, $_match)) {
$error_text = 'Syntax Error in template "' . $template->source->filepath . '" "' . htmlspecialchars($block_tag) . '" illegal options';
throw new SmartyCompilerException($error_text);
} else {
$_name = trim($_match[3], '\'"');
if ($_match[8] != 'hide' || isset($template->block_data[$_name])) { // replace {$smarty.block.child}
// get nested block tags
if (0 != preg_match_all("!({$_ldl}{$al}block\s+)(name=)?(\w+|'.*'|\".*\")([\s\S]*?)(hide)?(\s*{$_rdl})([\s\S]*?)(.*)?({$_ldl}{$al}/block\s*{$_rdl})!", $block_content, $_match2)) {
foreach ($_match2[3] as $key => $name) {
// get it's replacement
$_name2 = trim($name, '\'"');
if ($_match2[5][$key] != 'hide' || isset($template->block_data[$_name2])) {
if (isset($template->block_data[$_name2])) {
$replacement = $template->block_data[$_name2]['source'];
} else {
$replacement = '';
}
// replace {$smarty.block.child} tag
if (preg_match("!{$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl}!",$_match2[7][$key])) {
$replacement = preg_replace("!({$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl})!", $replacement, $_match2[7][$key]);
$block_content = preg_replace("!(({$_ldl}{$al}block)(.*)?{$name}(.*)?({$_rdl}[\s\S]*?{$_ldl}{$al}/block\s*{$_rdl}))!", $replacement, $block_content);
}
if (preg_match("!{$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl}!",$_match2[8][$key])) {
$replacement = preg_replace("!{$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl}!", $replacement, $_match2[8][$key]);
$block_content = preg_replace("!(({$_ldl}{$al}block)(.*)?{$name}(.*)?({$_rdl})(.*)?({$_ldl}{$al}/block\s*{$_rdl}))!", $replacement, $block_content);
}
} else {
// remove hidden blocks
$block_content = preg_replace("!(({$_ldl}{$al}block)(.*)?{$name}(.*)?({$_rdl}[\s\S]*?{$_ldl}{$al}/block\s*{$_rdl}))!", '', $block_content);
}
}
}
// do we have not nested {$smart.block.child}
if (0 != preg_match("!({$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl})!", $block_content, $_match2)) {
// get child replacement for this block
if (isset($template->block_data[$_name])) {
$replacement = $template->block_data[$_name]['source'];
unset($template->block_data[$_name]);
} else {
$replacement = '';
}
$block_content = preg_replace("!({$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl})!", $replacement, $block_content);
}
if (isset($template->block_data[$_name])) {
if (strpos($template->block_data[$_name]['source'], '%%%%SMARTY_PARENT%%%%') !== false) {
$template->block_data[$_name]['source'] =
str_replace('%%%%SMARTY_PARENT%%%%', $block_content, $template->block_data[$_name]['source']);
} elseif ($template->block_data[$_name]['mode'] == 'prepend') {
$template->block_data[$_name]['source'] .= $block_content;
} elseif ($template->block_data[$_name]['mode'] == 'append') {
$template->block_data[$_name]['source'] = $block_content . $template->block_data[$_name]['source'];
}
} else {
$template->block_data[$_name]['source'] = $block_content;
$template->block_data[$_name]['file'] = $filepath;
}
if ($_match[6] == 'append') {
$template->block_data[$_name]['mode'] = 'append';
} elseif ($_match[6] == 'prepend') {
$template->block_data[$_name]['mode'] = 'prepend';
} else {
$template->block_data[$_name]['mode'] = 'replace';
}
}
}
}
/**
* Compile saved child block source
*
* @param object $compiler compiler object
* @param string $_name optional name of child block
* @return string compiled code of schild block
*/
public static function compileChildBlock($compiler, $_name = null) {
$_output = '';
// if called by {$smarty.block.child} we must search the name of enclosing {block}
if ($_name == null) {
$stack_count = count($compiler->_tag_stack);
while (--$stack_count >= 0) {
if ($compiler->_tag_stack[$stack_count][0] == 'block') {
$_name = trim($compiler->_tag_stack[$stack_count][1][0]['name'], "'\"");
break;
}
}
// flag that child is already compile by {$smarty.block.child} inclusion
$compiler->template->block_data[$_name]['compiled'] = true;
}
if ($_name == null) {
$compiler->trigger_template_error('{$smarty.block.child} used out of context', $compiler->lex->taglineno);
}
// undefined child?
if (!isset($compiler->template->block_data[$_name]['source'])) {
return '';
}
$_tpl = new Smarty_Internal_template('string:' . $compiler->template->block_data[$_name]['source'], $compiler->smarty, $compiler->template, $compiler->template->cache_id,
$compiler->template->compile_id = null, $compiler->template->caching, $compiler->template->cache_lifetime);
$_tpl->variable_filters = $compiler->template->variable_filters;
$_tpl->properties['nocache_hash'] = $compiler->template->properties['nocache_hash'];
$_tpl->source->filepath = $compiler->template->block_data[$_name]['file'];
$_tpl->allow_relative_path = true;
if ($compiler->nocache) {
$_tpl->compiler->forceNocache = 2;
} else {
$_tpl->compiler->forceNocache = 1;
}
$_tpl->compiler->suppressHeader = true;
$_tpl->compiler->suppressTemplatePropertyHeader = true;
$_tpl->compiler->suppressMergedTemplates = true;
if (strpos($compiler->template->block_data[$_name]['source'], '%%%%SMARTY_PARENT%%%%') !== false) {
$_output = str_replace('%%%%SMARTY_PARENT%%%%', $compiler->parser->current_buffer->to_smarty_php(), $_tpl->compiler->compileTemplate($_tpl));
} elseif ($compiler->template->block_data[$_name]['mode'] == 'prepend') {
$_output = $_tpl->compiler->compileTemplate($_tpl) . $compiler->parser->current_buffer->to_smarty_php();
} elseif ($compiler->template->block_data[$_name]['mode'] == 'append') {
$_output = $compiler->parser->current_buffer->to_smarty_php() . $_tpl->compiler->compileTemplate($_tpl);
} elseif (!empty($compiler->template->block_data[$_name])) {
$_output = $_tpl->compiler->compileTemplate($_tpl);
}
$compiler->template->properties['file_dependency'] = array_merge($compiler->template->properties['file_dependency'], $_tpl->properties['file_dependency']);
$compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $_tpl->properties['function']);
$compiler->merged_templates = array_merge($compiler->merged_templates, $_tpl->compiler->merged_templates);
$compiler->template->variable_filters = $_tpl->variable_filters;
if ($_tpl->has_nocache_code) {
$compiler->template->has_nocache_code = true;
}
foreach ($_tpl->required_plugins as $key => $tmp1) {
if ($compiler->nocache && $compiler->template->caching) {
$code = 'nocache';
} else {
$code = $key;
}
foreach ($tmp1 as $name => $tmp) {
foreach ($tmp as $type => $data) {
$compiler->template->required_plugins[$code][$name][$type] = $data;
}
}
}
unset($_tpl);
return $_output;
}
}
/**
* Smarty Internal Plugin Compile BlockClose Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_CompileBase {
/**
* Compiles code for the {/block} tag
*
* @param array $args array with attributes from parser
* @param object $compiler compiler object
* @return string compiled code
*/
public function compile($args, $compiler) {
$compiler->has_code = true;
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$saved_data = $this->closeTag($compiler, array('block'));
$_name = trim($saved_data[0]['name'], "\"'");
if (isset($compiler->template->block_data[$_name]) && !isset($compiler->template->block_data[$_name]['compiled'])) {
// restore to status before {block} tag as new subtemplate code of parent {block} is not needed
// TODO: Below code was disabled in 3.1.8 because of problems with {include} in nested {block} tags in child templates
// combined with append/prepend or $smarty.block.parent
// For later versions it should be checked under which conditions it could run for optimisation
//
//$compiler->merged_templates = $saved_data[4];
//$compiler->smarty->merged_templates_func = $saved_data[5];
//$compiler->template->properties = $saved_data[6];
//$compiler->template->has_nocache_code = $saved_data[7];
$_output = Smarty_Internal_Compile_Block::compileChildBlock($compiler, $_name);
} else {
if (isset($saved_data[0]['hide']) && !isset($compiler->template->block_data[$_name]['source'])) {
$_output = '';
} else {
$_output = $compiler->parser->current_buffer->to_smarty_php();
}
unset($compiler->template->block_data[$_name]['compiled']);
}
// reset flags
$compiler->parser->current_buffer = $saved_data[1];
$compiler->nocache = $saved_data[2];
$compiler->smarty->merge_compiled_includes = $saved_data[3];
// reset flag for {block} tag
$compiler->inheritance = false;
// $_output content has already nocache code processed
$compiler->suppressNocacheProcessing = true;
return $_output;
}
}
?>

View File

@ -0,0 +1,77 @@
<?php
/**
* Smarty Internal Plugin Compile Break
*
* Compiles the {break} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Break Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Break extends Smarty_Internal_CompileBase {
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('levels');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $shorttag_order = array('levels');
/**
* Compiles code for the {break} tag
*
* @param array $args array with attributes from parser
* @param object $compiler compiler object
* @param array $parameter array with compilation parameter
* @return string compiled code
*/
public function compile($args, $compiler, $parameter)
{
static $_is_loopy = array('for' => true, 'foreach' => true, 'while' => true, 'section' => true);
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache'] === true) {
$compiler->trigger_template_error('nocache option not allowed', $compiler->lex->taglineno);
}
if (isset($_attr['levels'])) {
if (!is_numeric($_attr['levels'])) {
$compiler->trigger_template_error('level attribute must be a numeric constant', $compiler->lex->taglineno);
}
$_levels = $_attr['levels'];
} else {
$_levels = 1;
}
$level_count = $_levels;
$stack_count = count($compiler->_tag_stack) - 1;
while ($level_count > 0 && $stack_count >= 0) {
if (isset($_is_loopy[$compiler->_tag_stack[$stack_count][0]])) {
$level_count--;
}
$stack_count--;
}
if ($level_count != 0) {
$compiler->trigger_template_error("cannot break {$_levels} level(s)", $compiler->lex->taglineno);
}
$compiler->has_code = true;
return "<?php break {$_levels}?>";
}
}
?>

View File

@ -0,0 +1,130 @@
<?php
/**
* Smarty Internal Plugin Compile Function_Call
*
* Compiles the calls of user defined tags defined by {function}
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Function_Call Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Call extends Smarty_Internal_CompileBase {
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $required_attributes = array('name');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $shorttag_order = array('name');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('_any');
/**
* Compiles the calls of user defined tags defined by {function}
*
* @param array $args array with attributes from parser
* @param object $compiler compiler object
* @param array $parameter array with compilation parameter
* @return string compiled code
*/
public function compile($args, $compiler)
{
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
// save possible attributes
if (isset($_attr['assign'])) {
// output will be stored in a smarty variable instead of beind displayed
$_assign = $_attr['assign'];
}
$_name = $_attr['name'];
if ($compiler->compiles_template_function) {
$compiler->called_functions[] = trim($_name, "'\"");
}
unset($_attr['name'], $_attr['assign'], $_attr['nocache']);
// set flag (compiled code of {function} must be included in cache file
if ($compiler->nocache || $compiler->tag_nocache) {
$_nocache = 'true';
} else {
$_nocache = 'false';
}
$_paramsArray = array();
foreach ($_attr as $_key => $_value) {
if (is_int($_key)) {
$_paramsArray[] = "$_key=>$_value";
} else {
$_paramsArray[] = "'$_key'=>$_value";
}
}
if (isset($compiler->template->properties['function'][$_name]['parameter'])) {
foreach ($compiler->template->properties['function'][$_name]['parameter'] as $_key => $_value) {
if (!isset($_attr[$_key])) {
if (is_int($_key)) {
$_paramsArray[] = "$_key=>$_value";
} else {
$_paramsArray[] = "'$_key'=>$_value";
}
}
}
} elseif (isset($compiler->smarty->template_functions[$_name]['parameter'])) {
foreach ($compiler->smarty->template_functions[$_name]['parameter'] as $_key => $_value) {
if (!isset($_attr[$_key])) {
if (is_int($_key)) {
$_paramsArray[] = "$_key=>$_value";
} else {
$_paramsArray[] = "'$_key'=>$_value";
}
}
}
}
//varibale name?
if (!(strpos($_name, '$') === false)) {
$call_cache = $_name;
$call_function = '$tmp = "smarty_template_function_".' . $_name . '; $tmp';
} else {
$_name = trim($_name, "'\"");
$call_cache = "'{$_name}'";
$call_function = 'smarty_template_function_' . $_name;
}
$_params = 'array(' . implode(",", $_paramsArray) . ')';
$_hash = str_replace('-', '_', $compiler->template->properties['nocache_hash']);
// was there an assign attribute
if (isset($_assign)) {
if ($compiler->template->caching) {
$_output = "<?php ob_start(); Smarty_Internal_Function_Call_Handler::call ({$call_cache},\$_smarty_tpl,{$_params},'{$_hash}',{$_nocache}); \$_smarty_tpl->assign({$_assign}, ob_get_clean());?>\n";
} else {
$_output = "<?php ob_start(); {$call_function}(\$_smarty_tpl,{$_params}); \$_smarty_tpl->assign({$_assign}, ob_get_clean());?>\n";
}
} else {
if ($compiler->template->caching) {
$_output = "<?php Smarty_Internal_Function_Call_Handler::call ({$call_cache},\$_smarty_tpl,{$_params},'{$_hash}',{$_nocache});?>\n";
} else {
$_output = "<?php {$call_function}(\$_smarty_tpl,{$_params});?>\n";
}
}
return $_output;
}
}
?>

Some files were not shown because too many files have changed in this diff Show More