Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • fsini-informatik/fsfahrttool
  • kleemeis/fsfahrttool
2 results
Show changes
Showing
with 2132 additions and 1998 deletions
<?php
require_once __DIR__ . '/../config.inc.php';
require_once __DIR__ . '/../lang.php';
require_once __DIR__ . '/medoo.php';
require_once __DIR__ . '/soft_protect.php';
require_once __DIR__ . '/Fahrt.php';
require_once __DIR__ . '/Bachelor.php';
use medoo\Medoo;
class Environment {
const LOGIN_RIGHTS_NONE = 0;
const LOGIN_RIGHTS_ADMIN = 1;
const LOGIN_RIGHTS_SUDO = 2;
private static $__instance;
public $database;
public $config;
public $sysconf;
private $permission_level = Environment::LOGIN_RIGHTS_NONE;
private $adminEnv;
// if the context provides a specific trip or bachelor, these are set
/** @var Fahrt */
private $fahrt;
/** @var Bachelor */
private $bachelor;
public static function getEnv($admin = false) {
if (self::$__instance == NULL) self::$__instance = new Environment($admin);
if (!self::$__instance->adminEnv and $admin) self::$__instance = new Environment($admin);
return self::$__instance;
}
protected function __construct($admin = false) {
global $config_db, $config_studitypen, $config_essen, $config_reisearten, $config_invalidCharsRegEx,
$config_reisearten_o, $config_essen_o, $config_studitypen_o, $config_baseurl, $config_basepath,
$config_mailtag, $config_impressum, $config_reisearten_destroyed, $config_databse_debug,
$config_userfile, $config_current_fahrt_file, $config_reisearten_o_short;
$this->adminEnv = $admin;
$this->database = new medoo(array(
'database_type' => $config_db["type"],
'database_name' => $config_db["name"],
'server' => $config_db["host"],
'username' => $config_db["user"],
'password' => $config_db["pass"]
));
$this->config = [
'studitypen' => $config_studitypen,
'essen' => $config_essen,
'reisearten' => $config_reisearten,
'invalidChars' => $config_invalidCharsRegEx,
'reiseartenDestroyed' => $config_reisearten_destroyed
];
$this->oconfig = [
'studitypen' => $config_studitypen_o,
'essen' => $config_essen_o,
'reisearten' => $config_reisearten_o,
'reiseartenShort' => $config_reisearten_o_short
];
$this->sysconf = [
'currentTripId' => $this->readCurrentTripId(),
'baseURL' => $config_baseurl,
'basePath' => $config_basepath,
'mailTag' => $config_mailtag,
'impressum' => $config_impressum,
'databaseDebug' => $config_databse_debug,
'adminUsersFile' => $config_userfile,
'currentFahrtFile' => $config_current_fahrt_file,
'gitSummary' => $this->getGitSummary()
];
$this->bachelor = null;
$this->fahrt = null;
if ($admin) {
self::adminCheckIfLogin();
if (self::adminIsLoggedIn())
$this->permission_level = self::adminGetLevel();
}
}
public function __destruct() {
if ($this->sysconf['databaseDebug']) {
echo '<pre>';
var_dump($this->database->log());
echo '</pre>';
}
}
// ========================================================================================================
// ADMIN STUFF
private static function adminCheckIfLogin() {
if (isset($_GET['logout'])) {
Environment::adminLogOut();
} else if (isset($_POST['user']) and isset($_POST['password'])) {
$user = $_POST['user'];
$password = $_POST['password'];
if (Environment::adminIsValidUser($user, $password)) {
$_SESSION['loggedIn'] = $user;
$_SESSION['userStyle'] = Environment::getStylePreference($user);
}
}
}
private static function getStylePreference($user) {
$config_admins = Environment::adminReadUsersFile();
foreach ($config_admins as $cfg_user => $cfg_password) {
if ($cfg_user != $user)
continue;
return $cfg_password["style"];
}
return 0;
}
private static function adminIsValidUser($user, $password) {
$config_admins = Environment::adminReadUsersFile();
foreach ($config_admins as $cfg_user => $cfg_password) {
if ($cfg_user != $user)
continue;
$cfg_password = $cfg_password["pw"];
if ($cfg_password[0] == '{') {
if (strpos($cfg_password, "{SHA256}") >= 0) {
$beginOfSalt = strpos($cfg_password, "$");
$salt = substr($cfg_password, 9, strpos($cfg_password, "$") - 9);
$hash = substr($cfg_password, $beginOfSalt + 1);
if (hash('sha256', $password . $salt) == $hash) {
return true;
}
}
} else {
// ONLY sha256 yet, others not implemented
}
}
return false;
}
private static function adminReadUsersFile() {
global $config_userfile;
$ret = [];
$handle = fopen($config_userfile, "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
$tmp = explode(" ", $line);
if (count($tmp) >= 3) {
$ret[$tmp[1]] = ["pw" => $tmp[2], "sa" => $tmp[0], "style" => $tmp[3]];
}
}
}
fclose($handle);
return $ret;
}
private static function adminIsLoggedIn() {
return isset($_SESSION['loggedIn']) and $_SESSION['loggedIn'] != '';
}
private static function adminGetLevel() {
$config_admins = Environment::adminReadUsersFile();
if (isset($_SESSION['loggedIn']) && isset($config_admins[$_SESSION['loggedIn']])) {
if ($config_admins[$_SESSION['loggedIn']]['sa'] === 'S')
return Environment::LOGIN_RIGHTS_SUDO;
elseif ($config_admins[$_SESSION['loggedIn']]['sa'] === 'N')
return Environment::LOGIN_RIGHTS_ADMIN;
}
return Environment::LOGIN_RIGHTS_NONE;
}
public function isAdmin() {
return $this->permission_level == Environment::LOGIN_RIGHTS_ADMIN or
$this->permission_level == Environment::LOGIN_RIGHTS_SUDO;
}
public function isSuperAdmin() {
return $this->permission_level == Environment::LOGIN_RIGHTS_SUDO;
}
public static function adminLogOut() {
session_destroy();
header("location: ..");
}
private function getGitSummary() {
if (isset($this->sysconf['gitSummary']) and !empty($this->sysconf['gitSummary']))
return $this->sysconf['gitSummary'];
exec('git show --quiet HEAD', $output);
return $output;
}
// ===========================================================================================================
// Some context based trip getters
private function readCurrentTripId() {
global $config_current_fahrt_file;
if (file_exists($config_current_fahrt_file)) {
$tmp = file_get_contents($config_current_fahrt_file);
if (is_numeric($tmp))
return $tmp;
}
return null;
}
private function isTripIdValid($fid) {
if (empty($fid) and $fid != 0) return false;
return $this->database->has('fahrten', ['fahrt_id' => $fid]);
}
public function getCurrentTripId() {
return $this->sysconf['currentTripId'];
}
public function getSelectedTripId() {
if (isset($_REQUEST['fid']))
return (int)$_REQUEST['fid'];
else
return null;
}
public function isSelectedTripIdValid() {
return $this->isTripIdValid($this->getSelectedTripId());
}
public function getTrip($fallbackCurrent = false) {
$tripID = $this->getSelectedTripId();
if (is_null($tripID) and !$fallbackCurrent)
return null;
if (!is_null($this->fahrt))
return $this->fahrt;
if (is_null($tripID) and $fallbackCurrent)
$tripID = $this->getCurrentTripId();
if (!$this->isTripIdValid($tripID))
return null;
$this->fahrt = new Fahrt($tripID);
return $this->fahrt;
}
// ===========================================================================================================
// Some context based bachelor getters
public function isInWaitlistMode() {
return isset($_REQUEST['waitlist']);
}
/**
* @return bool true iff formdata is received
*/
public function formDataReceived() {
return isset($_REQUEST['submit']) || isset($_REQUEST['storySubmit']);
}
public function getSelectedBachelorId() {
if (isset($_REQUEST['bid']))
return $_REQUEST['bid'];
if (isset($_REQUEST['hash']))
return $_REQUEST['hash'];
return null;
}
public function getBachelor($allowTripIdFallback = false, $fallbackNew = false, $declareNew = false) {
if ($this->formDataReceived())
return Bachelor::makeFromForm($declareNew);
$bid = $this->getSelectedBachelorId();
$trip = $this->getTrip($allowTripIdFallback);
if (!is_null($bid) and !is_null($trip))
return Bachelor::makeFromDB($trip, $bid);
if ($fallbackNew)
return Bachelor::makeEmptyBachelor($trip);
return null;
}
// ==========================================================================================================
// SOME OTHER STUFF
/**
* sends mail
*
* first line of $cont is used as subject iff terminated by double backslash (\\)
* note that there should be no "\\" anywhere else in the string!!!
*
* returns true/false depending on success
*/
public function sendMail($addr, $cont, $from = null, $bcc = null) {
$subj = "Wichtige Information";
$mess = $cont;
$tmp = explode("\\\\", $cont);
if (count($tmp) > 1) {
$subj = $tmp[0];
$mess = $tmp[1];
}
$subj = $this->sysconf['mailTag'] . $subj;
$headers = 'MIME-Version: 1.0' . "\r\n" .
'Content-type: text/plain; charset=UTF-8' . "\r\n" .
'From: ' . $from . "\r\n" .
'Reply-To: ' . $from . "\r\n" .
'X-Mailer: PHP/' . phpversion();
if (!is_null($bcc)) $headers .= "\r\nBcc: " . $bcc;
return mail($addr, $subj, $mess, $headers);
}
public function getLanguageString($lang, $replace) {
global $$lang;
return str_replace(array_keys($replace), array_values($replace), $$lang);
}
}
<?php
require_once __DIR__ . '/Bachelor.php';
require_once __DIR__ . '/Environment.php';
class Fahrt {
const STATUS_IS_OPEN_NOT_FULL = 0;
const STATUS_IS_OPEN_FULL = 1;
const STATUS_IS_CLOSED = 2;
const STATUS_IS_COUNTDOWN = 3;
public static $ALLOWED_FIELDS = ['fahrt_id', 'titel', 'ziel', 'von', 'bis', 'regopen', 'beschreibung', 'leiter', 'kontakt',
'map_pin', 'max_bachelor', 'wikilink', 'paydeadline', 'payinfo', 'opentime', 'disclaimlink', 'isSummer'];
/** @var Environment */
private $environment;
private $fid;
private $data;
private $newFahrt = false;
function __construct($fid) {
$this->environment = Environment::getEnv();
$this->fid = $fid;
$this->data = null;
}
public static function getEmptyFahrt() {
$newFahrt = new Fahrt(null);
foreach (Fahrt::$ALLOWED_FIELDS as $field) {
$newFahrt->data[$field] = '';
}
unset($newFahrt->data['fahrt_id']);
$newFahrt->set([
'titel' => 'Neue Fahrt',
'map_pin' => '52.42951196033782 13.530490995971718',
'von' => date('Y-m-d'),
'bis' => date('Y-m-d')
]);
$newFahrt->newFahrt = true;
return $newFahrt;
}
public static function getFahrtFromData($data) {
$newFahrt = new Fahrt($data['fahrt_id']);
try {
$newFahrt->set($data);
return $newFahrt;
} catch (Exception $e) {
return null;
}
}
public static function getAlleFahrten() {
$tmpEnvironment = Environment::getEnv();
// $fahrtenData = $tmpEnvironment->database->select('fahrten', Fahrt::$ALLOWED_FIELDS, 'ORDER BY fahrt_id DESC');
$fahrtenData = $tmpEnvironment->database->select('fahrten', Fahrt::$ALLOWED_FIELDS, ["ORDER" => ["fahrt_id" => "DESC"]]);
if (empty($fahrtenData))
return null;
$fahrten = array_map(function ($fahrtData) {
return Fahrt::getFahrtFromData($fahrtData);
}, $fahrtenData);
return $fahrten;
}
public function set($data) {
if (is_null($data) or !isset($data) or empty($data))
throw new Exception('No data to set!');
foreach ($data as $key => $val) {
if (in_array($key, Fahrt::$ALLOWED_FIELDS)) {
$this->data[$key] = $val;
} else {
throw new Exception('Fahrt hat kein Feld: ' . $key);
}
}
}
public function save() {
if ($this->environment->isSuperAdmin() and $this->newFahrt) {
return $this->environment->database->insert('fahrten', $this->data)->rowCount() > 0;
} elseif ($this->environment->isAdmin() and !$this->newFahrt) {
return $this->environment->database->update('fahrten', $this->data, ['fahrt_id' => $this->fid])->rowCount() > 0;
} else {
throw new Exception('Nicht erlaubt!');
}
}
private function getBachelorsSelector($params) {
$conditions = [
'fahrt_id' => $this->fid
];
if (isset($params['waiting'])) {
if ($params['waiting']) {
$conditions['transferred'] = null;
$conditions['on_waitlist'] = 1;
} else {
$conditions['OR'] = [
'on_waitlist' => 0,
'AND' => [
'transferred[!]' => null,
'on_waitlist' => 1
]
];
}
}
if (isset($params['essen']))
$conditions['essen'] = $params['essen'];
if (isset($params['antyp']))
$conditions['antyp'] = $params['antyp'];
if (isset($params['studityp']))
$conditions['studityp'] = $params['studityp'];
if (isset($params['virgin']))
$conditions['virgin'] = ($params['virgin']) ? 1 : 0;
if (isset($params['backstepped']))
$conditions['backstepped' . (($params['backstepped']) ? '[!]' : '')] = null;
if (isset($params['paid']))
$conditions['paid' . (($params['paid']) ? '[!]' : '')] = null;
if (isset($params['repaid']))
$conditions['repaid' . (($params['backstepped']) ? '[!]' : '')] = null;
if (isset($params['public']))
$conditions['public'] = ($params['public']) ? 1 : 0;
if (isset($params['mGame']))
$conditions['mGame'] = ($params['mGame']) ? 1 : 0;
$selector = [
'table' => 'bachelor',
'fields' => !isset($params['fields']) ? Bachelor::$ALLOWED_FIELDS : $params['fields'],
'where' => ['AND' => $conditions]
];
return $selector;
}
/**
* This function returns participants of this fahrt.
* Set parameters to filter, keep unset means 'dont care'.
*
* Form the param array as follows:
* - $fields (array[string]) columns you want to select
* - $waiting (bool) is on the waitlist and not transferred
* - $essen (str) has specific food preferences
* - $studityp (int) is of specific studityp
* - $virgin (bool) is <18 or not
* - $backstepped (bool) stepped back or not
* - $paid (bool) paid or not
* - $repaid (bool) got money back or not
* - $public (bool) publically visible
*
* @param array $params params for the selector
*
* @return medoo result
*/
public function getBachelors($params, $order = null) {
$selector = $this->getBachelorsSelector($params);
if (!empty($order))
$selector['where']['ORDER'] = $order;
return $this->environment->database->select($selector['table'], $selector['fields'], $selector['where']);
}
public function getBachelor($bid) {
return Bachelor::makeFromDB($this->fid, $bid);
}
public function getFahrtDetails() {
if (!is_null($this->data) and !empty($this->data))
return $this->data;
$this->data = $this->environment->database->get('fahrten', Fahrt::$ALLOWED_FIELDS, ['fahrt_id' => $this->fid]);
return $this->data;
}
public function get($field) {
if (in_array($field, Fahrt::$ALLOWED_FIELDS))
return $this->getFahrtDetails()[$field];
else
throw new Exception('Dieses Feld ist nicht vorhanden!');
}
public function getID() {
return $this->fid;
}
public function getPossibleDates() {
$details = $this->getFahrtDetails();
$end = new DateTime($details['bis']);
$period = new DatePeriod(
new DateTime($details['von']),
new DateInterval('P1D'),
$end->modify('+1 day')
);
$ret = [];
foreach ($period as $d) {
array_push($ret, $d->format("d.m.Y"));
}
return $ret;
}
public function getGPS() {
$pin = $this->getFahrtDetails()['map_pin'];
if (!preg_match("/\\d+\\.\\d+ \\d+\\.\\d+/m", $pin))
return '52.4263218 13.5223815';//'71.555267 99.690962';
return $pin;
}
public function getLenTage() {
return $this->environment->database->query("SELECT DATEDIFF(bis, von) AS diff FROM fahrten WHERE fahrt_id=" . $this->fid)->fetch(0)['diff'];
}
public function getNumMaxSpots() {
return $this->getFahrtDetails()['max_bachelor'];
}
public function getNumTakenSpots() {
$selector = $this->getBachelorsSelector(['backstepped' => false, 'waiting' => false]);
return $this->environment->database->count('bachelor', $selector['where']);
}
public function getTimeToOpen() {
$opentime = $this->getFahrtDetails()['opentime'];
return $opentime - time();
}
public function getOpenTime() {
return $this->getFahrtDetails()['opentime'];
}
public function getRegistrationState() {
if (!$this->environment->database->has('fahrten', ['AND' => ['fahrt_id' => $this->fid, 'regopen' => 1]]))
return Fahrt::STATUS_IS_CLOSED;
$timeToOpen = $this->getTimeToOpen();
if ($timeToOpen > 0)
return Fahrt::STATUS_IS_COUNTDOWN;
$cnt = $this->getNumTakenSpots();
$max = $this->getNumMaxSpots();
if ($cnt < $max)
return Fahrt::STATUS_IS_OPEN_NOT_FULL;
return Fahrt::STATUS_IS_OPEN_FULL;
}
public function isRegistrationOpen() {
$state = $this->getRegistrationState();
return $state == Fahrt::STATUS_IS_OPEN_FULL or $state == Fahrt::STATUS_IS_OPEN_NOT_FULL;
}
}
<?php
/**
* converts mail into safe for web format
* @param $mail - mail to convert
* @return mixed - converted mail
*/
function comm_convert_mail($mail){
return str_replace(array("@","."),array("&Oslash;", "&middot;"), $mail);
}
function comm_verbose($level, $text){
global $config_verbose_level;
if($config_verbose_level >= $level) echo $text.'<br />';
}
function comm_format_date($date){
return date('d.m.Y', strtotime($date));
}
function comm_get_possible_dates($fid){
return array("12.03.2014","13.03.2014","14.03.2014");
}
function comm_isopen_fid($db_handle, $fid){
comm_verbose(3,"checking if fid ". $fid . " is open");
return $db_handle->has("fahrten", array(
"AND" => array(
"fahrt_id"=>$fid,
"regopen"=>1)));
}
function comm_generate_key($db_handle, $table, $col, $conditions){
again:
$bytes = openssl_random_pseudo_bytes(8);
$hex = bin2hex($bytes);
comm_verbose(3,"generated hex for test: ".$hex);
$conditions[$col] = $hex;
if($db_handle->has($table, array("AND"=>$conditions))) goto again;
comm_verbose(2,"generated hex: ".$hex);
return $hex;
}
\ No newline at end of file
<?php
/*!
* Medoo database framework
* http://medoo.in
* Version 0.9.1.1
*
* Copyright 2013, Angel Lai
* https://medoo.in
* Version 1.7.8
*
* Copyright 2019, Angel Lai
* Released under the MIT license
*/
class medoo
namespace Medoo;
use PDO;
use Exception;
use PDOException;
use InvalidArgumentException;
class Raw {
public $map;
public $value;
}
class Medoo
{
protected $database_type = 'mysql';
public $pdo;
// For MySQL, MSSQL, Sybase
protected $server = 'localhost';
protected $type;
protected $username = 'username';
protected $prefix;
protected $password = 'password';
protected $statement;
// For SQLite
protected $database_file = '';
protected $dsn;
// Optional
protected $port = 3306;
protected $logs = [];
protected $charset = 'utf8';
protected $logging = false;
protected $database_name = '';
protected $debug_mode = false;
protected $option = array();
protected $guid = 0;
// Variable
protected $queryString;
protected $errorInfo = null;
public function __construct($options)
public function __construct(array $options)
{
try {
$commands = array();
if (isset($options[ 'database_type' ]))
{
$this->type = strtolower($options[ 'database_type' ]);
if (is_string($options))
if ($this->type === 'mariadb')
{
if (strtolower($this->database_type) == 'sqlite')
{
$this->database_file = $options;
}
else
{
$this->database_name = $options;
}
$this->type = 'mysql';
}
else
}
if (isset($options[ 'prefix' ]))
{
$this->prefix = $options[ 'prefix' ];
}
if (isset($options[ 'logging' ]) && is_bool($options[ 'logging' ]))
{
$this->logging = $options[ 'logging' ];
}
$option = isset($options[ 'option' ]) ? $options[ 'option' ] : [];
$commands = (isset($options[ 'command' ]) && is_array($options[ 'command' ])) ? $options[ 'command' ] : [];
switch ($this->type)
{
case 'mysql':
// Make MySQL using standard quoted identifier
$commands[] = 'SET SQL_MODE=ANSI_QUOTES';
break;
case 'mssql':
// Keep MSSQL QUOTED_IDENTIFIER is ON for standard quoting
$commands[] = 'SET QUOTED_IDENTIFIER ON';
// Make ANSI_NULLS is ON for NULL value
$commands[] = 'SET ANSI_NULLS ON';
break;
}
if (isset($options[ 'pdo' ]))
{
if (!$options[ 'pdo' ] instanceof PDO)
{
foreach ($options as $option => $value)
{
$this->$option = $value;
}
throw new InvalidArgumentException('Invalid PDO object supplied');
}
$type = strtolower($this->database_type);
$this->pdo = $options[ 'pdo' ];
foreach ($commands as $value)
{
$this->pdo->exec($value);
}
return;
}
if (isset($options[ 'dsn' ]))
{
if (is_array($options[ 'dsn' ]) && isset($options[ 'dsn' ][ 'driver' ]))
{
$attr = $options[ 'dsn' ];
}
else
{
throw new InvalidArgumentException('Invalid DSN option supplied');
}
}
else
{
if (
isset($this->port) &&
is_int($this->port * 1)
isset($options[ 'port' ]) &&
is_int($options[ 'port' ] * 1)
)
{
$port = $this->port;
$port = $options[ 'port' ];
}
$set_charset = "SET NAMES '" . $this->charset . "'";
$is_port = isset($port);
switch ($type)
switch ($this->type)
{
case 'mariadb':
$type = 'mysql';
case 'mysql':
// Make MySQL using standard quoted identifier
$commands[] = 'SET SQL_MODE=ANSI_QUOTES';
$attr = [
'driver' => 'mysql',
'dbname' => $options[ 'database_name' ]
];
if (isset($options[ 'socket' ]))
{
$attr[ 'unix_socket' ] = $options[ 'socket' ];
}
else
{
$attr[ 'host' ] = $options[ 'server' ];
if ($is_port)
{
$attr[ 'port' ] = $port;
}
}
break;
case 'pgsql':
$dsn = $type . ':host=' . $this->server . (isset($port) ? ';port=' . $port : '') . ';dbname=' . $this->database_name;
$commands[] = $set_charset;
$attr = [
'driver' => 'pgsql',
'host' => $options[ 'server' ],
'dbname' => $options[ 'database_name' ]
];
if ($is_port)
{
$attr[ 'port' ] = $port;
}
break;
case 'sybase':
$dsn = $type . ':host=' . $this->server . (isset($port) ? ',' . $port : '') . ';dbname=' . $this->database_name;
$commands[] = $set_charset;
$attr = [
'driver' => 'dblib',
'host' => $options[ 'server' ],
'dbname' => $options[ 'database_name' ]
];
if ($is_port)
{
$attr[ 'port' ] = $port;
}
break;
case 'oracle':
$attr = [
'driver' => 'oci',
'dbname' => $options[ 'server' ] ?
'//' . $options[ 'server' ] . ($is_port ? ':' . $port : ':1521') . '/' . $options[ 'database_name' ] :
$options[ 'database_name' ]
];
if (isset($options[ 'charset' ]))
{
$attr[ 'charset' ] = $options[ 'charset' ];
}
break;
case 'mssql':
$dsn = strpos(PHP_OS, 'WIN') !== false ?
'sqlsrv:server=' . $this->server . (isset($port) ? ',' . $port : '') . ';database=' . $this->database_name :
'dblib:host=' . $this->server . (isset($port) ? ':' . $port : '') . ';dbname=' . $this->database_name;
if (isset($options[ 'driver' ]) && $options[ 'driver' ] === 'dblib')
{
$attr = [
'driver' => 'dblib',
'host' => $options[ 'server' ] . ($is_port ? ':' . $port : ''),
'dbname' => $options[ 'database_name' ]
];
if (isset($options[ 'appname' ]))
{
$attr[ 'appname' ] = $options[ 'appname' ];
}
if (isset($options[ 'charset' ]))
{
$attr[ 'charset' ] = $options[ 'charset' ];
}
}
else
{
$attr = [
'driver' => 'sqlsrv',
'Server' => $options[ 'server' ] . ($is_port ? ',' . $port : ''),
'Database' => $options[ 'database_name' ]
];
if (isset($options[ 'appname' ]))
{
$attr[ 'APP' ] = $options[ 'appname' ];
}
// Keep MSSQL QUOTED_IDENTIFIER is ON for standard quoting
$commands[] = 'SET QUOTED_IDENTIFIER ON';
$commands[] = $set_charset;
$config = [
'ApplicationIntent',
'AttachDBFileName',
'Authentication',
'ColumnEncryption',
'ConnectionPooling',
'Encrypt',
'Failover_Partner',
'KeyStoreAuthentication',
'KeyStorePrincipalId',
'KeyStoreSecret',
'LoginTimeout',
'MultipleActiveResultSets',
'MultiSubnetFailover',
'Scrollable',
'TraceFile',
'TraceOn',
'TransactionIsolation',
'TransparentNetworkIPResolution',
'TrustServerCertificate',
'WSID',
];
foreach ($config as $value)
{
$keyname = strtolower(preg_replace(['/([a-z\d])([A-Z])/', '/([^_])([A-Z][a-z])/'], '$1_$2', $value));
if (isset($options[ $keyname ]))
{
$attr[ $value ] = $options[ $keyname ];
}
}
}
break;
case 'sqlite':
$dsn = $type . ':' . $this->database_file;
$this->username = null;
$this->password = null;
$attr = [
'driver' => 'sqlite',
$options[ 'database_file' ]
];
break;
}
}
if (!isset($attr))
{
throw new InvalidArgumentException('Incorrect connection options');
}
$driver = $attr[ 'driver' ];
if (!in_array($driver, PDO::getAvailableDrivers()))
{
throw new InvalidArgumentException("Unsupported PDO driver: {$driver}");
}
unset($attr[ 'driver' ]);
$stack = [];
foreach ($attr as $key => $value)
{
$stack[] = is_int($key) ? $value : $key . '=' . $value;
}
$dsn = $driver . ':' . implode(';', $stack);
if (
in_array($this->type, ['mysql', 'pgsql', 'sybase', 'mssql']) &&
isset($options[ 'charset' ])
)
{
$commands[] = "SET NAMES '{$options[ 'charset' ]}'" . (
$this->type === 'mysql' && isset($options[ 'collation' ]) ?
" COLLATE '{$options[ 'collation' ]}'" : ''
);
}
$this->dsn = $dsn;
try {
$this->pdo = new PDO(
$dsn,
$this->username,
$this->password,
$this->option
$dsn,
isset($options[ 'username' ]) ? $options[ 'username' ] : null,
isset($options[ 'password' ]) ? $options[ 'password' ] : null,
$option
);
foreach ($commands as $value)
{
$this->pdo->exec($value);
$this->pdo->exec($value);
}
}
catch (PDOException $e) {
throw new Exception($e->getMessage());
throw new PDOException($e->getMessage());
}
}
public function query($query, $map = [])
{
$raw = $this->raw($query, $map);
$query = $this->buildRaw($raw, $map);
return $this->exec($query, $map);
}
public function exec($query, $map = [])
{
$this->statement = null;
if ($this->debug_mode)
{
echo $this->generate($query, $map);
$this->debug_mode = false;
return false;
}
if ($this->logging)
{
$this->logs[] = [$query, $map];
}
else
{
$this->logs = [[$query, $map]];
}
$statement = $this->pdo->prepare($query);
if (!$statement)
{
$this->errorInfo = $this->pdo->errorInfo();
$this->statement = null;
return false;
}
$this->statement = $statement;
foreach ($map as $key => $value)
{
$statement->bindValue($key, $value[ 0 ], $value[ 1 ]);
}
$execute = $statement->execute();
$this->errorInfo = $statement->errorInfo();
if (!$execute)
{
$this->statement = null;
}
return $statement;
}
protected function generate($query, $map)
{
$identifier = [
'mysql' => '`$1`',
'mssql' => '[$1]'
];
$query = preg_replace(
'/"([a-zA-Z0-9_]+)"/i',
isset($identifier[ $this->type ]) ? $identifier[ $this->type ] : '"$1"',
$query
);
foreach ($map as $key => $value)
{
if ($value[ 1 ] === PDO::PARAM_STR)
{
$replace = $this->quote($value[ 0 ]);
}
elseif ($value[ 1 ] === PDO::PARAM_NULL)
{
$replace = 'NULL';
}
elseif ($value[ 1 ] === PDO::PARAM_LOB)
{
$replace = '{LOB_DATA}';
}
else
{
$replace = $value[ 0 ];
}
$query = str_replace($key, $replace, $query);
}
return $query;
}
public static function raw($string, $map = [])
{
$raw = new Raw();
$raw->map = $map;
$raw->value = $string;
return $raw;
}
public function query($query)
protected function isRaw($object)
{
$this->queryString = $query;
return $this->pdo->query($query);
return $object instanceof Raw;
}
public function exec($query)
protected function buildRaw($raw, &$map)
{
$this->queryString = $query;
if (!$this->isRaw($raw))
{
return false;
}
$query = preg_replace_callback(
'/((FROM|TABLE|INTO|UPDATE)\s*)?\<([a-zA-Z0-9_\.]+)\>/i',
function ($matches)
{
if (!empty($matches[ 2 ]))
{
return $matches[ 2 ] . ' ' . $this->tableQuote($matches[ 3 ]);
}
return $this->columnQuote($matches[ 3 ]);
},
$raw->value);
$raw_map = $raw->map;
if (!empty($raw_map))
{
foreach ($raw_map as $key => $value)
{
$map[ $key ] = $this->typeMap($value, gettype($value));
}
}
return $this->pdo->exec($query);
return $query;
}
public function quote($string)
......@@ -145,550 +475,1373 @@ class medoo
return $this->pdo->quote($string);
}
protected function column_quote($string)
protected function tableQuote($table)
{
if (!preg_match('/^[a-zA-Z0-9_]+$/i', $table))
{
throw new InvalidArgumentException("Incorrect table name \"$table\"");
}
return '"' . $this->prefix . $table . '"';
}
protected function mapKey()
{
return ':MeDoO_' . $this->guid++ . '_mEdOo';
}
protected function typeMap($value, $type)
{
$map = [
'NULL' => PDO::PARAM_NULL,
'integer' => PDO::PARAM_INT,
'double' => PDO::PARAM_STR,
'boolean' => PDO::PARAM_BOOL,
'string' => PDO::PARAM_STR,
'object' => PDO::PARAM_STR,
'resource' => PDO::PARAM_LOB
];
if ($type === 'boolean')
{
$value = ($value ? '1' : '0');
}
elseif ($type === 'NULL')
{
$value = null;
}
return [$value, $map[ $type ]];
}
protected function columnQuote($string)
{
return '"' . str_replace('.', '"."', $string) . '"';
if (!preg_match('/^[a-zA-Z0-9_]+(\.?[a-zA-Z0-9_]+)?$/i', $string))
{
throw new InvalidArgumentException("Incorrect column name \"$string\"");
}
if (strpos($string, '.') !== false)
{
return '"' . $this->prefix . str_replace('.', '"."', $string) . '"';
}
return '"' . $string . '"';
}
protected function column_push($columns)
protected function columnPush(&$columns, &$map, $root, $is_join = false)
{
if ($columns == '*')
if ($columns === '*')
{
return $columns;
}
$stack = [];
if (is_string($columns))
{
$columns = array($columns);
$columns = [$columns];
}
$stack = array();
foreach ($columns as $key => $value)
{
preg_match('/([a-zA-Z0-9_\-\.]*)\s*\(([a-zA-Z0-9_\-]*)\)/i', $value, $match);
if (!is_int($key) && is_array($value) && $root && count(array_keys($columns)) === 1)
{
$stack[] = $this->columnQuote($key);
if (
isset($match[1]) &&
isset($match[2])
)
$stack[] = $this->columnPush($value, $map, false, $is_join);
}
elseif (is_array($value))
{
array_push($stack, $this->column_quote( $match[1] ) . ' AS ' . $this->column_quote( $match[2] ));
$stack[] = $this->columnPush($value, $map, false, $is_join);
}
else
elseif (!is_int($key) && $raw = $this->buildRaw($value, $map))
{
preg_match('/(?<column>[a-zA-Z0-9_\.]+)(\s*\[(?<type>(String|Bool|Int|Number))\])?/i', $key, $match);
$stack[] = $raw . ' AS ' . $this->columnQuote($match[ 'column' ]);
}
elseif (is_int($key) && is_string($value))
{
array_push($stack, $this->column_quote( $value ));
if ($is_join && strpos($value, '*') !== false)
{
throw new InvalidArgumentException('Cannot use table.* to select all columns while joining table');
}
preg_match('/(?<column>[a-zA-Z0-9_\.]+)(?:\s*\((?<alias>[a-zA-Z0-9_]+)\))?(?:\s*\[(?<type>(?:String|Bool|Int|Number|Object|JSON))\])?/i', $value, $match);
if (!empty($match[ 'alias' ]))
{
$stack[] = $this->columnQuote($match[ 'column' ]) . ' AS ' . $this->columnQuote($match[ 'alias' ]);
$columns[ $key ] = $match[ 'alias' ];
if (!empty($match[ 'type' ]))
{
$columns[ $key ] .= ' [' . $match[ 'type' ] . ']';
}
}
else
{
$stack[] = $this->columnQuote($match[ 'column' ]);
}
}
}
return implode($stack, ',');
return implode(',', $stack);
}
protected function array_quote($array)
protected function arrayQuote($array)
{
$temp = array();
$stack = [];
foreach ($array as $value)
{
$temp[] = is_int($value) ? $value : $this->pdo->quote($value);
$stack[] = is_int($value) ? $value : $this->pdo->quote($value);
}
return implode($temp, ',');
return implode(',', $stack);
}
protected function inner_conjunct($data, $conjunctor, $outer_conjunctor)
protected function innerConjunct($data, $map, $conjunctor, $outer_conjunctor)
{
$haystack = array();
$stack = [];
foreach ($data as $value)
{
$haystack[] = '(' . $this->data_implode($value, $conjunctor) . ')';
$stack[] = '(' . $this->dataImplode($value, $map, $conjunctor) . ')';
}
return implode($outer_conjunctor . ' ', $haystack);
return implode($outer_conjunctor . ' ', $stack);
}
protected function data_implode($data, $conjunctor, $outer_conjunctor = null)
protected function dataImplode($data, &$map, $conjunctor)
{
$wheres = array();
$stack = [];
foreach ($data as $key => $value)
{
$type = gettype($value);
if (
$type === 'array' &&
preg_match("/^(AND|OR)(\s+#.*)?$/", $key, $relation_match)
)
{
$relationship = $relation_match[ 1 ];
$stack[] = $value !== array_keys(array_keys($value)) ?
'(' . $this->dataImplode($value, $map, ' ' . $relationship) . ')' :
'(' . $this->innerConjunct($value, $map, ' ' . $relationship, $conjunctor) . ')';
continue;
}
$map_key = $this->mapKey();
if (
($key == 'AND' || $key == 'OR') &&
is_array($value)
is_int($key) &&
preg_match('/([a-zA-Z0-9_\.]+)\[(?<operator>\>\=?|\<\=?|\!?\=)\]([a-zA-Z0-9_\.]+)/i', $value, $match)
)
{
$wheres[] = 0 !== count(array_diff_key($value, array_keys(array_keys($value)))) ?
'(' . $this->data_implode($value, ' ' . $key) . ')' :
'(' . $this->inner_conjunct($value, ' ' . $key, $conjunctor) . ')';
$stack[] = $this->columnQuote($match[ 1 ]) . ' ' . $match[ 'operator' ] . ' ' . $this->columnQuote($match[ 3 ]);
}
else
{
preg_match('/([\w\.]+)(\[(\>|\>\=|\<|\<\=|\!|\<\>)\])?/i', $key, $match);
if (isset($match[3]))
preg_match('/([a-zA-Z0-9_\.]+)(\[(?<operator>\>\=?|\<\=?|\!|\<\>|\>\<|\!?~|REGEXP)\])?/i', $key, $match);
$column = $this->columnQuote($match[ 1 ]);
if (isset($match[ 'operator' ]))
{
if ($match[3] == '')
$operator = $match[ 'operator' ];
if (in_array($operator, ['>', '>=', '<', '<=']))
{
$wheres[] = $this->column_quote($match[1]) . ' ' . $match[3] . '= ' . $this->quote($value);
$condition = $column . ' ' . $operator . ' ';
if (is_numeric($value))
{
$condition .= $map_key;
$map[ $map_key ] = [$value, is_float($value) ? PDO::PARAM_STR : PDO::PARAM_INT];
}
elseif ($raw = $this->buildRaw($value, $map))
{
$condition .= $raw;
}
else
{
$condition .= $map_key;
$map[ $map_key ] = [$value, PDO::PARAM_STR];
}
$stack[] = $condition;
}
elseif ($match[3] == '!')
elseif ($operator === '!')
{
$column = $this->column_quote($match[1]);
switch (gettype($value))
switch ($type)
{
case 'NULL':
$wheres[] = $column . ' IS NOT NULL';
$stack[] = $column . ' IS NOT NULL';
break;
case 'array':
$wheres[] = $column . ' NOT IN (' . $this->array_quote($value) . ')';
$placeholders = [];
foreach ($value as $index => $item)
{
$stack_key = $map_key . $index . '_i';
$placeholders[] = $stack_key;
$map[ $stack_key ] = $this->typeMap($item, gettype($item));
}
$stack[] = $column . ' NOT IN (' . implode(', ', $placeholders) . ')';
break;
case 'object':
if ($raw = $this->buildRaw($value, $map))
{
$stack[] = $column . ' != ' . $raw;
}
break;
case 'integer':
case 'double':
$wheres[] = $column . ' != ' . $value;
break;
case 'string':
$wheres[] = $column . ' != ' . $this->quote($value);
case 'boolean':
case 'string':
$stack[] = $column . ' != ' . $map_key;
$map[ $map_key ] = $this->typeMap($value, $type);
break;
}
}
else
elseif ($operator === '~' || $operator === '!~')
{
if ($match[3] == '<>')
if ($type !== 'array')
{
$value = [ $value ];
}
$connector = ' OR ';
$data = array_values($value);
if (is_array($data[ 0 ]))
{
if (is_array($value))
if (isset($value[ 'AND' ]) || isset($value[ 'OR' ]))
{
if (is_numeric($value[0]) && is_numeric($value[1]))
{
$wheres[] = $this->column_quote($match[1]) . ' BETWEEN ' . $value[0] . ' AND ' . $value[1];
}
else
{
$wheres[] = $this->column_quote($match[1]) . ' BETWEEN ' . $this->quote($value[0]) . ' AND ' . $this->quote($value[1]);
}
$connector = ' ' . array_keys($value)[ 0 ] . ' ';
$value = $data[ 0 ];
}
}
else
$like_clauses = [];
foreach ($value as $index => $item)
{
if (is_numeric($value))
$item = strval($item);
if (!preg_match('/(\[.+\]|[\*\?\!\%#^-_]|%.+|.+%)/', $item))
{
$wheres[] = $this->column_quote($match[1]) . ' ' . $match[3] . ' ' . $value;
$item = '%' . $item . '%';
}
else
{
$datetime = strtotime($value);
if ($datetime)
{
$wheres[] = $this->column_quote($match[1]) . ' ' . $match[3] . ' ' . $this->quote(date('Y-m-d H:i:s', $datetime));
}
$like_clauses[] = $column . ($operator === '!~' ? ' NOT' : '') . ' LIKE ' . $map_key . 'L' . $index;
$map[ $map_key . 'L' . $index ] = [$item, PDO::PARAM_STR];
}
$stack[] = '(' . implode($connector, $like_clauses) . ')';
}
elseif ($operator === '<>' || $operator === '><')
{
if ($type === 'array')
{
if ($operator === '><')
{
$column .= ' NOT';
}
$stack[] = '(' . $column . ' BETWEEN ' . $map_key . 'a AND ' . $map_key . 'b)';
$data_type = (is_numeric($value[ 0 ]) && is_numeric($value[ 1 ])) ? PDO::PARAM_INT : PDO::PARAM_STR;
$map[ $map_key . 'a' ] = [$value[ 0 ], $data_type];
$map[ $map_key . 'b' ] = [$value[ 1 ], $data_type];
}
}
elseif ($operator === 'REGEXP')
{
$stack[] = $column . ' REGEXP ' . $map_key;
$map[ $map_key ] = [$value, PDO::PARAM_STR];
}
}
else
{
if (is_int($key))
switch ($type)
{
$wheres[] = $this->quote($value);
case 'NULL':
$stack[] = $column . ' IS NULL';
break;
case 'array':
$placeholders = [];
foreach ($value as $index => $item)
{
$stack_key = $map_key . $index . '_i';
$placeholders[] = $stack_key;
$map[ $stack_key ] = $this->typeMap($item, gettype($item));
}
$stack[] = $column . ' IN (' . implode(', ', $placeholders) . ')';
break;
case 'object':
if ($raw = $this->buildRaw($value, $map))
{
$stack[] = $column . ' = ' . $raw;
}
break;
case 'integer':
case 'double':
case 'boolean':
case 'string':
$stack[] = $column . ' = ' . $map_key;
$map[ $map_key ] = $this->typeMap($value, $type);
break;
}
}
}
}
return implode($conjunctor . ' ', $stack);
}
protected function whereClause($where, &$map)
{
$where_clause = '';
if (is_array($where))
{
$where_keys = array_keys($where);
$conditions = array_diff_key($where, array_flip(
['GROUP', 'ORDER', 'HAVING', 'LIMIT', 'LIKE', 'MATCH']
));
if (!empty($conditions))
{
$where_clause = ' WHERE ' . $this->dataImplode($conditions, $map, ' AND');
}
if (isset($where[ 'MATCH' ]) && $this->type === 'mysql')
{
$MATCH = $where[ 'MATCH' ];
if (is_array($MATCH) && isset($MATCH[ 'columns' ], $MATCH[ 'keyword' ]))
{
$mode = '';
$mode_array = [
'natural' => 'IN NATURAL LANGUAGE MODE',
'natural+query' => 'IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION',
'boolean' => 'IN BOOLEAN MODE',
'query' => 'WITH QUERY EXPANSION'
];
if (isset($MATCH[ 'mode' ], $mode_array[ $MATCH[ 'mode' ] ]))
{
$mode = ' ' . $mode_array[ $MATCH[ 'mode' ] ];
}
$columns = implode(', ', array_map([$this, 'columnQuote'], $MATCH[ 'columns' ]));
$map_key = $this->mapKey();
$map[ $map_key ] = [$MATCH[ 'keyword' ], PDO::PARAM_STR];
$where_clause .= ($where_clause !== '' ? ' AND ' : ' WHERE') . ' MATCH (' . $columns . ') AGAINST (' . $map_key . $mode . ')';
}
}
if (isset($where[ 'GROUP' ]))
{
$GROUP = $where[ 'GROUP' ];
if (is_array($GROUP))
{
$stack = [];
foreach ($GROUP as $column => $value)
{
$stack[] = $this->columnQuote($value);
}
$where_clause .= ' GROUP BY ' . implode(',', $stack);
}
elseif ($raw = $this->buildRaw($GROUP, $map))
{
$where_clause .= ' GROUP BY ' . $raw;
}
else
{
$where_clause .= ' GROUP BY ' . $this->columnQuote($GROUP);
}
if (isset($where[ 'HAVING' ]))
{
if ($raw = $this->buildRaw($where[ 'HAVING' ], $map))
{
$where_clause .= ' HAVING ' . $raw;
}
else
{
$column = $this->column_quote($match[1]);
$where_clause .= ' HAVING ' . $this->dataImplode($where[ 'HAVING' ], $map, ' AND');
}
}
}
switch (gettype($value))
if (isset($where[ 'ORDER' ]))
{
$ORDER = $where[ 'ORDER' ];
if (is_array($ORDER))
{
$stack = [];
foreach ($ORDER as $column => $value)
{
if (is_array($value))
{
case 'NULL':
$wheres[] = $column . ' IS NULL';
break;
$stack[] = 'FIELD(' . $this->columnQuote($column) . ', ' . $this->arrayQuote($value) . ')';
}
elseif ($value === 'ASC' || $value === 'DESC')
{
$stack[] = $this->columnQuote($column) . ' ' . $value;
}
elseif (is_int($column))
{
$stack[] = $this->columnQuote($value);
}
}
case 'array':
$wheres[] = $column . ' IN (' . $this->array_quote($value) . ')';
break;
$where_clause .= ' ORDER BY ' . implode(',', $stack);
}
elseif ($raw = $this->buildRaw($ORDER, $map))
{
$where_clause .= ' ORDER BY ' . $raw;
}
else
{
$where_clause .= ' ORDER BY ' . $this->columnQuote($ORDER);
}
case 'integer':
case 'double':
$wheres[] = $column . ' = ' . $value;
break;
if (
isset($where[ 'LIMIT' ]) &&
in_array($this->type, ['oracle', 'mssql'])
)
{
$LIMIT = $where[ 'LIMIT' ];
case 'string':
$wheres[] = $column . ' = ' . $this->quote($value);
break;
if (is_numeric($LIMIT))
{
$LIMIT = [0, $LIMIT];
}
if (
is_array($LIMIT) &&
is_numeric($LIMIT[ 0 ]) &&
is_numeric($LIMIT[ 1 ])
)
{
$where_clause .= ' OFFSET ' . $LIMIT[ 0 ] . ' ROWS FETCH NEXT ' . $LIMIT[ 1 ] . ' ROWS ONLY';
}
}
}
if (isset($where[ 'LIMIT' ]) && !in_array($this->type, ['oracle', 'mssql']))
{
$LIMIT = $where[ 'LIMIT' ];
if (is_numeric($LIMIT))
{
$where_clause .= ' LIMIT ' . $LIMIT;
}
elseif (
is_array($LIMIT) &&
is_numeric($LIMIT[ 0 ]) &&
is_numeric($LIMIT[ 1 ])
)
{
$where_clause .= ' LIMIT ' . $LIMIT[ 1 ] . ' OFFSET ' . $LIMIT[ 0 ];
}
}
}
elseif ($raw = $this->buildRaw($where, $map))
{
$where_clause .= ' ' . $raw;
}
return $where_clause;
}
protected function selectContext($table, &$map, $join, &$columns = null, $where = null, $column_fn = null)
{
preg_match('/(?<table>[a-zA-Z0-9_]+)\s*\((?<alias>[a-zA-Z0-9_]+)\)/i', $table, $table_match);
if (isset($table_match[ 'table' ], $table_match[ 'alias' ]))
{
$table = $this->tableQuote($table_match[ 'table' ]);
$table_query = $table . ' AS ' . $this->tableQuote($table_match[ 'alias' ]);
}
else
{
$table = $this->tableQuote($table);
$table_query = $table;
}
$is_join = false;
$join_key = is_array($join) ? array_keys($join) : null;
if (
isset($join_key[ 0 ]) &&
strpos($join_key[ 0 ], '[') === 0
)
{
$is_join = true;
$table_query .= ' ' . $this->buildJoin($table, $join);
}
else
{
if (is_null($columns))
{
if (
!is_null($where) ||
(is_array($join) && isset($column_fn))
)
{
$where = $join;
$columns = null;
}
else
{
$where = null;
$columns = $join;
}
}
else
{
$where = $columns;
$columns = $join;
}
}
if (isset($column_fn))
{
if ($column_fn === 1)
{
$column = '1';
if (is_null($where))
{
$where = $columns;
}
}
elseif ($raw = $this->buildRaw($column_fn, $map))
{
$column = $raw;
}
else
{
if (empty($columns) || $this->isRaw($columns))
{
$columns = '*';
$where = $join;
}
$column = $column_fn . '(' . $this->columnPush($columns, $map, true) . ')';
}
}
else
{
$column = $this->columnPush($columns, $map, true, $is_join);
}
return 'SELECT ' . $column . ' FROM ' . $table_query . $this->whereClause($where, $map);
}
protected function buildJoin($table, $join)
{
$table_join = [];
$join_array = [
'>' => 'LEFT',
'<' => 'RIGHT',
'<>' => 'FULL',
'><' => 'INNER'
];
foreach($join as $sub_table => $relation)
{
preg_match('/(\[(?<join>\<\>?|\>\<?)\])?(?<table>[a-zA-Z0-9_]+)\s?(\((?<alias>[a-zA-Z0-9_]+)\))?/', $sub_table, $match);
if ($match[ 'join' ] !== '' && $match[ 'table' ] !== '')
{
if (is_string($relation))
{
$relation = 'USING ("' . $relation . '")';
}
if (is_array($relation))
{
// For ['column1', 'column2']
if (isset($relation[ 0 ]))
{
$relation = 'USING ("' . implode('", "', $relation) . '")';
}
else
{
$joins = [];
foreach ($relation as $key => $value)
{
$joins[] = (
strpos($key, '.') > 0 ?
// For ['tableB.column' => 'column']
$this->columnQuote($key) :
// For ['column1' => 'column2']
$table . '."' . $key . '"'
) .
' = ' .
$this->tableQuote(isset($match[ 'alias' ]) ? $match[ 'alias' ] : $match[ 'table' ]) . '."' . $value . '"';
}
$relation = 'ON ' . implode(' AND ', $joins);
}
}
$table_name = $this->tableQuote($match[ 'table' ]) . ' ';
if (isset($match[ 'alias' ]))
{
$table_name .= 'AS ' . $this->tableQuote($match[ 'alias' ]) . ' ';
}
$table_join[] = $join_array[ $match[ 'join' ] ] . ' JOIN ' . $table_name . $relation;
}
}
return implode($conjunctor . ' ', $wheres);
return implode(' ', $table_join);
}
public function where_clause($where)
protected function columnMap($columns, &$stack, $root)
{
$where_clause = '';
if ($columns === '*')
{
return $stack;
}
if (is_array($where))
foreach ($columns as $key => $value)
{
$single_condition = array_diff_key($where, array_flip(
explode(' ', 'AND OR GROUP ORDER HAVING LIMIT LIKE MATCH')
));
if (is_int($key))
{
preg_match('/([a-zA-Z0-9_]+\.)?(?<column>[a-zA-Z0-9_]+)(?:\s*\((?<alias>[a-zA-Z0-9_]+)\))?(?:\s*\[(?<type>(?:String|Bool|Int|Number|Object|JSON))\])?/i', $value, $key_match);
if ($single_condition != array())
$column_key = !empty($key_match[ 'alias' ]) ?
$key_match[ 'alias' ] :
$key_match[ 'column' ];
if (isset($key_match[ 'type' ]))
{
$stack[ $value ] = [$column_key, $key_match[ 'type' ]];
}
else
{
$stack[ $value ] = [$column_key, 'String'];
}
}
elseif ($this->isRaw($value))
{
$where_clause = ' WHERE ' . $this->data_implode($single_condition, '');
preg_match('/([a-zA-Z0-9_]+\.)?(?<column>[a-zA-Z0-9_]+)(\s*\[(?<type>(String|Bool|Int|Number))\])?/i', $key, $key_match);
$column_key = $key_match[ 'column' ];
if (isset($key_match[ 'type' ]))
{
$stack[ $key ] = [$column_key, $key_match[ 'type' ]];
}
else
{
$stack[ $key ] = [$column_key, 'String'];
}
}
elseif (!is_int($key) && is_array($value))
{
if ($root && count(array_keys($columns)) === 1)
{
$stack[ $key ] = [$key, 'String'];
}
$this->columnMap($value, $stack, false);
}
}
return $stack;
}
protected function dataMap($data, $columns, $column_map, &$stack, $root, &$result)
{
if ($root)
{
$columns_key = array_keys($columns);
if (count($columns_key) === 1 && is_array($columns[$columns_key[0]]))
{
$index_key = array_keys($columns)[0];
$data_key = preg_replace("/^[a-zA-Z0-9_]+\./i", "", $index_key);
$current_stack = [];
foreach ($data as $item)
{
$this->dataMap($data, $columns[ $index_key ], $column_map, $current_stack, false, $result);
$index = $data[ $data_key ];
$result[ $index ] = $current_stack;
}
}
if (isset($where['AND']))
else
{
$where_clause = ' WHERE ' . $this->data_implode($where['AND'], ' AND');
$current_stack = [];
$this->dataMap($data, $columns, $column_map, $current_stack, false, $result);
$result[] = $current_stack;
}
if (isset($where['OR']))
return;
}
foreach ($columns as $key => $value)
{
$isRaw = $this->isRaw($value);
if (is_int($key) || $isRaw)
{
$where_clause = ' WHERE ' . $this->data_implode($where['OR'], ' OR');
$map = $column_map[ $isRaw ? $key : $value ];
$column_key = $map[ 0 ];
$item = $data[ $column_key ];
if (isset($map[ 1 ]))
{
if ($isRaw && in_array($map[ 1 ], ['Object', 'JSON']))
{
continue;
}
if (is_null($item))
{
$stack[ $column_key ] = null;
continue;
}
switch ($map[ 1 ])
{
case 'Number':
$stack[ $column_key ] = (double) $item;
break;
case 'Int':
$stack[ $column_key ] = (int) $item;
break;
case 'Bool':
$stack[ $column_key ] = (bool) $item;
break;
case 'Object':
$stack[ $column_key ] = unserialize($item);
break;
case 'JSON':
$stack[ $column_key ] = json_decode($item, true);
break;
case 'String':
$stack[ $column_key ] = $item;
break;
}
}
else
{
$stack[ $column_key ] = $item;
}
}
if (isset($where['LIKE']))
else
{
$like_query = $where['LIKE'];
if (is_array($like_query))
{
$is_OR = isset($like_query['OR']);
$current_stack = [];
if ($is_OR || isset($like_query['AND']))
{
$connector = $is_OR ? 'OR' : 'AND';
$like_query = $is_OR ? $like_query['OR'] : $like_query['AND'];
}
else
{
$connector = 'AND';
}
$this->dataMap($data, $value, $column_map, $current_stack, false, $result);
$clause_wrap = array();
foreach ($like_query as $column => $keyword)
{
if (is_array($keyword))
{
foreach ($keyword as $key)
{
$clause_wrap[] = $this->column_quote($column) . ' LIKE ' . $this->quote('%' . $key . '%');
}
}
else
{
$clause_wrap[] = $this->column_quote($column) . ' LIKE ' . $this->quote('%' . $keyword . '%');
}
}
$where_clause .= ($where_clause != '' ? ' AND ' : ' WHERE ') . '(' . implode($clause_wrap, ' ' . $connector . ' ') . ')';
}
$stack[ $key ] = $current_stack;
}
if (isset($where['MATCH']))
}
}
public function create($table, $columns, $options = null)
{
$stack = [];
$tableName = $this->prefix . $table;
foreach ($columns as $name => $definition)
{
if (is_int($name))
{
$match_query = $where['MATCH'];
if (is_array($match_query) && isset($match_query['columns']) && isset($match_query['keyword']))
{
$where_clause .= ($where_clause != '' ? ' AND ' : ' WHERE ') . ' MATCH ("' . str_replace('.', '"."', implode($match_query['columns'], '", "')) . '") AGAINST (' . $this->quote($match_query['keyword']) . ')';
}
$stack[] = preg_replace('/\<([a-zA-Z0-9_]+)\>/i', '"$1"', $definition);
}
if (isset($where['GROUP']))
elseif (is_array($definition))
{
$where_clause .= ' GROUP BY ' . $this->column_quote($where['GROUP']);
$stack[] = $name . ' ' . implode(' ', $definition);
}
if (isset($where['ORDER']))
elseif (is_string($definition))
{
preg_match('/(^[a-zA-Z0-9_\-\.]*)(\s*(DESC|ASC))?/', $where['ORDER'], $order_match);
$stack[] = $name . ' ' . $this->query($definition);
}
}
$where_clause .= ' ORDER BY "' . str_replace('.', '"."', $order_match[1]) . '" ' . (isset($order_match[3]) ? $order_match[3] : '');
$table_option = '';
if (isset($where['HAVING']))
{
$where_clause .= ' HAVING ' . $this->data_implode($where['HAVING'], '');
}
}
if (isset($where['LIMIT']))
if (is_array($options))
{
$option_stack = [];
foreach ($options as $key => $value)
{
if (is_numeric($where['LIMIT']))
{
$where_clause .= ' LIMIT ' . $where['LIMIT'];
}
if (
is_array($where['LIMIT']) &&
is_numeric($where['LIMIT'][0]) &&
is_numeric($where['LIMIT'][1])
)
if (is_string($value) || is_int($value))
{
$where_clause .= ' LIMIT ' . $where['LIMIT'][0] . ',' . $where['LIMIT'][1];
$option_stack[] = "$key = $value";
}
}
$table_option = ' ' . implode(', ', $option_stack);
}
else
elseif (is_string($options))
{
if ($where != null)
{
$where_clause .= ' ' . $where;
}
$table_option = ' ' . $options;
}
return $where_clause;
return $this->exec("CREATE TABLE IF NOT EXISTS $tableName (" . implode(', ', $stack) . ")$table_option");
}
public function drop($table)
{
$tableName = $this->prefix . $table;
return $this->exec("DROP TABLE IF EXISTS $tableName");
}
public function select($table, $join, $columns = null, $where = null)
{
$table = '"' . $table . '"';
$join_key = is_array($join) ? array_keys($join) : null;
$map = [];
$result = [];
$column_map = [];
if (strpos($join_key[0], '[') !== false)
{
$table_join = array();
$index = 0;
$join_array = array(
'>' => 'LEFT',
'<' => 'RIGHT',
'<>' => 'FULL',
'><' => 'INNER'
);
$column = $where === null ? $join : $columns;
foreach($join as $sub_table => $relation)
{
preg_match('/(\[(\<|\>|\>\<|\<\>)\])?([a-zA-Z0-9_\-]*)/', $sub_table, $match);
$is_single = (is_string($column) && $column !== '*');
if ($match[2] != '' && $match[3] != '')
{
if (is_string($relation))
{
$relation = 'USING ("' . $relation . '")';
}
$query = $this->exec($this->selectContext($table, $map, $join, $columns, $where), $map);
if (is_array($relation))
{
// For ['column1', 'column2']
if (isset($relation[0]))
{
$relation = 'USING ("' . implode($relation, '", "') . '")';
}
// For ['column1' => 'column2']
else
{
$relation = 'ON ' . $table . '."' . key($relation) . '" = "' . $match[3] . '"."' . current($relation) . '"';
}
}
$this->columnMap($columns, $column_map, true);
$table_join[] = $join_array[ $match[2] ] . ' JOIN "' . $match[3] . '" ' . $relation;
}
}
if (!$this->statement)
{
return false;
}
$table .= ' ' . implode($table_join, ' ');
if ($columns === '*')
{
return $query->fetchAll(PDO::FETCH_ASSOC);
}
else
while ($data = $query->fetch(PDO::FETCH_ASSOC))
{
$where = $columns;
$columns = $join;
$current_stack = [];
$this->dataMap($data, $columns, $column_map, $current_stack, true, $result);
}
$query = $this->query('SELECT ' . $this->column_push($columns) . ' FROM ' . $table . $this->where_clause($where));
if ($is_single)
{
$single_result = [];
$result_key = $column_map[ $column ][ 0 ];
foreach ($result as $item)
{
$single_result[] = $item[ $result_key ];
}
return $single_result;
}
return $query ? $query->fetchAll(
(is_string($columns) && $columns != '*') ? PDO::FETCH_COLUMN : PDO::FETCH_ASSOC
) : false;
return $result;
}
public function insert($table, $datas)
{
$lastId = array();
$stack = [];
$columns = [];
$fields = [];
$map = [];
// Check indexed or associative array
if (!isset($datas[0]))
if (!isset($datas[ 0 ]))
{
$datas = array($datas);
$datas = [$datas];
}
foreach ($datas as $data)
{
$keys = implode('", "', array_keys($data));
$values = array();
foreach ($data as $key => $value)
{
switch (gettype($value))
$columns[] = $key;
}
}
$columns = array_unique($columns);
foreach ($datas as $data)
{
$values = [];
foreach ($columns as $key)
{
if ($raw = $this->buildRaw($data[ $key ], $map))
{
case 'NULL':
$values[] = 'NULL';
break;
$values[] = $raw;
continue;
}
case 'array':
$values[] = $this->quote(serialize($value));
break;
$map_key = $this->mapKey();
case 'integer':
case 'double':
case 'string':
$values[] = $this->quote($value);
break;
$values[] = $map_key;
if (!isset($data[ $key ]))
{
$map[ $map_key ] = [null, PDO::PARAM_NULL];
}
else
{
$value = $data[ $key ];
$type = gettype($value);
switch ($type)
{
case 'array':
$map[ $map_key ] = [
strpos($key, '[JSON]') === strlen($key) - 6 ?
json_encode($value) :
serialize($value),
PDO::PARAM_STR
];
break;
case 'object':
$value = serialize($value);
case 'NULL':
case 'resource':
case 'boolean':
case 'integer':
case 'double':
case 'string':
$map[ $map_key ] = $this->typeMap($value, $type);
break;
}
}
}
$this->exec('INSERT INTO "' . $table . '" ("' . $keys . '") VALUES (' . implode($values, ', ') . ')');
$stack[] = '(' . implode(', ', $values) . ')';
}
$lastId[] = $this->pdo->lastInsertId();
foreach ($columns as $key)
{
$fields[] = $this->columnQuote(preg_replace("/(\s*\[JSON\]$)/i", '', $key));
}
return count($lastId) > 1 ? $lastId : $lastId[ 0 ];
return $this->exec('INSERT INTO ' . $this->tableQuote($table) . ' (' . implode(', ', $fields) . ') VALUES ' . implode(', ', $stack), $map);
}
public function update($table, $data, $where = null)
{
$fields = array();
$fields = [];
$map = [];
foreach ($data as $key => $value)
{
if (is_array($value))
$column = $this->columnQuote(preg_replace("/(\s*\[(JSON|\+|\-|\*|\/)\]$)/i", '', $key));
if ($raw = $this->buildRaw($value, $map))
{
$fields[] = $this->column_quote($key) . '=' . $this->quote(serialize($value));
$fields[] = $column . ' = ' . $raw;
continue;
}
else
$map_key = $this->mapKey();
preg_match('/(?<column>[a-zA-Z0-9_]+)(\[(?<operator>\+|\-|\*|\/)\])?/i', $key, $match);
if (isset($match[ 'operator' ]))
{
preg_match('/([\w]+)(\[(\+|\-|\*|\/)\])?/i', $key, $match);
if (isset($match[3]))
if (is_numeric($value))
{
if (is_numeric($value))
{
$fields[] = $this->column_quote($match[1]) . ' = ' . $this->column_quote($match[1]) . ' ' . $match[3] . ' ' . $value;
}
$fields[] = $column . ' = ' . $column . ' ' . $match[ 'operator' ] . ' ' . $value;
}
else
{
$column = $this->column_quote($key);
}
else
{
$fields[] = $column . ' = ' . $map_key;
switch (gettype($value))
{
case 'NULL':
$fields[] = $column . ' = NULL';
break;
$type = gettype($value);
case 'array':
$fields[] = $column . ' = ' . $this->quote(serialize($value));
break;
switch ($type)
{
case 'array':
$map[ $map_key ] = [
strpos($key, '[JSON]') === strlen($key) - 6 ?
json_encode($value) :
serialize($value),
PDO::PARAM_STR
];
break;
case 'integer':
case 'double':
case 'string':
$fields[] = $column . ' = ' . $this->quote($value);
break;
}
case 'object':
$value = serialize($value);
case 'NULL':
case 'resource':
case 'boolean':
case 'integer':
case 'double':
case 'string':
$map[ $map_key ] = $this->typeMap($value, $type);
break;
}
}
}
return $this->exec('UPDATE "' . $table . '" SET ' . implode(', ', $fields) . $this->where_clause($where));
return $this->exec('UPDATE ' . $this->tableQuote($table) . ' SET ' . implode(', ', $fields) . $this->whereClause($where, $map), $map);
}
public function delete($table, $where)
{
return $this->exec('DELETE FROM "' . $table . '"' . $this->where_clause($where));
$map = [];
return $this->exec('DELETE FROM ' . $this->tableQuote($table) . $this->whereClause($where, $map), $map);
}
public function replace($table, $columns, $search = null, $replace = null, $where = null)
public function replace($table, $columns, $where = null)
{
if (is_array($columns))
if (!is_array($columns) || empty($columns))
{
$replace_query = array();
return false;
}
$map = [];
$stack = [];
foreach ($columns as $column => $replacements)
foreach ($columns as $column => $replacements)
{
if (is_array($replacements))
{
foreach ($replacements as $replace_search => $replace_replacement)
foreach ($replacements as $old => $new)
{
$replace_query[] = $column . ' = REPLACE("' . $column . '", ' . $this->quote($replace_search) . ', ' . $this->quote($replace_replacement) . ')';
$map_key = $this->mapKey();
$stack[] = $this->columnQuote($column) . ' = REPLACE(' . $this->columnQuote($column) . ', ' . $map_key . 'a, ' . $map_key . 'b)';
$map[ $map_key . 'a' ] = [$old, PDO::PARAM_STR];
$map[ $map_key . 'b' ] = [$new, PDO::PARAM_STR];
}
}
$replace_query = implode(', ', $replace_query);
$where = $search;
}
if (!empty($stack))
{
return $this->exec('UPDATE ' . $this->tableQuote($table) . ' SET ' . implode(', ', $stack) . $this->whereClause($where, $map), $map);
}
return false;
}
public function get($table, $join = null, $columns = null, $where = null)
{
$map = [];
$result = [];
$column_map = [];
$current_stack = [];
if ($where === null)
{
$column = $join;
unset($columns[ 'LIMIT' ]);
}
else
{
if (is_array($search))
$column = $columns;
unset($where[ 'LIMIT' ]);
}
$is_single = (is_string($column) && $column !== '*');
$query = $this->exec($this->selectContext($table, $map, $join, $columns, $where) . ' LIMIT 1', $map);
if (!$this->statement)
{
return false;
}
$data = $query->fetchAll(PDO::FETCH_ASSOC);
if (isset($data[ 0 ]))
{
if ($column === '*')
{
$replace_query = array();
return $data[ 0 ];
}
foreach ($search as $replace_search => $replace_replacement)
{
$replace_query[] = $columns . ' = REPLACE("' . $columns . '", ' . $this->quote($replace_search) . ', ' . $this->quote($replace_replacement) . ')';
}
$replace_query = implode(', ', $replace_query);
$where = $replace;
$this->columnMap($columns, $column_map, true);
$this->dataMap($data[ 0 ], $columns, $column_map, $current_stack, true, $result);
if ($is_single)
{
return $result[ 0 ][ $column_map[ $column ][ 0 ] ];
}
return $result[ 0 ];
}
}
public function has($table, $join, $where = null)
{
$map = [];
$column = null;
if ($this->type === 'mssql')
{
$query = $this->exec($this->selectContext($table, $map, $join, $column, $where, Medoo::raw('TOP 1 1')), $map);
}
else
{
$query = $this->exec('SELECT EXISTS(' . $this->selectContext($table, $map, $join, $column, $where, 1) . ')', $map);
}
if (!$this->statement)
{
return false;
}
$result = $query->fetchColumn();
return $result === '1' || $result === 1 || $result === true;
}
public function rand($table, $join = null, $columns = null, $where = null)
{
$type = $this->type;
$order = 'RANDOM()';
if ($type === 'mysql')
{
$order = 'RAND()';
}
elseif ($type === 'mssql')
{
$order = 'NEWID()';
}
$order_raw = $this->raw($order);
if ($where === null)
{
if ($columns === null)
{
$columns = [
'ORDER' => $order_raw
];
}
else
{
$replace_query = $columns . ' = REPLACE("' . $columns . '", ' . $this->quote($search) . ', ' . $this->quote($replace) . ')';
$column = $join;
unset($columns[ 'ORDER' ]);
$columns[ 'ORDER' ] = $order_raw;
}
}
else
{
unset($where[ 'ORDER' ]);
$where[ 'ORDER' ] = $order_raw;
}
return $this->exec('UPDATE "' . $table . '" SET ' . $replace_query . $this->where_clause($where));
return $this->select($table, $join, $columns, $where);
}
public function get($table, $columns, $where = null)
private function aggregate($type, $table, $join = null, $column = null, $where = null)
{
if (!isset($where))
$map = [];
$query = $this->exec($this->selectContext($table, $map, $join, $column, $where, strtoupper($type)), $map);
if (!$this->statement)
{
$where = array();
return false;
}
$where['LIMIT'] = 1;
$data = $this->select($table, $columns, $where);
$number = $query->fetchColumn();
return is_numeric($number) ? $number + 0 : $number;
}
public function count($table, $join = null, $column = null, $where = null)
{
return $this->aggregate('count', $table, $join, $column, $where);
}
return isset($data[0]) ? $data[0] : false;
public function avg($table, $join, $column = null, $where = null)
{
return $this->aggregate('avg', $table, $join, $column, $where);
}
public function has($table, $where)
public function max($table, $join, $column = null, $where = null)
{
return $this->query('SELECT EXISTS(SELECT 1 FROM "' . $table . '"' . $this->where_clause($where) . ')')->fetchColumn() === '1';
return $this->aggregate('max', $table, $join, $column, $where);
}
public function count($table, $where = null)
public function min($table, $join, $column = null, $where = null)
{
return 0 + ($this->query('SELECT COUNT(*) FROM "' . $table . '"' . $this->where_clause($where))->fetchColumn());
return $this->aggregate('min', $table, $join, $column, $where);
}
public function max($table, $column, $where = null)
public function sum($table, $join, $column = null, $where = null)
{
return 0 + ($this->query('SELECT MAX("' . $column . '") FROM "' . $table . '"' . $this->where_clause($where))->fetchColumn());
return $this->aggregate('sum', $table, $join, $column, $where);
}
public function min($table, $column, $where = null)
public function action($actions)
{
return 0 + ($this->query('SELECT MIN("' . $column . '") FROM "' . $table . '"' . $this->where_clause($where))->fetchColumn());
if (is_callable($actions))
{
$this->pdo->beginTransaction();
try {
$result = $actions($this);
if ($result === false)
{
$this->pdo->rollBack();
}
else
{
$this->pdo->commit();
}
}
catch (Exception $e) {
$this->pdo->rollBack();
throw $e;
}
return $result;
}
return false;
}
public function avg($table, $column, $where = null)
public function id()
{
return 0 + ($this->query('SELECT AVG("' . $column . '") FROM "' . $table . '"' . $this->where_clause($where))->fetchColumn());
if ($this->statement == null)
{
return null;
}
$type = $this->type;
if ($type === 'oracle')
{
return 0;
}
elseif ($type === 'pgsql')
{
return $this->pdo->query('SELECT LASTVAL()')->fetchColumn();
}
$lastId = $this->pdo->lastInsertId();
if ($lastId != "0" && $lastId != "")
{
return $lastId;
}
return null;
}
public function sum($table, $column, $where = null)
public function debug()
{
return 0 + ($this->query('SELECT SUM("' . $column . '") FROM "' . $table . '"' . $this->where_clause($where))->fetchColumn());
$this->debug_mode = true;
return $this;
}
public function error()
{
return $this->pdo->errorInfo();
return $this->errorInfo;
}
public function last_query()
public function last()
{
return $this->queryString;
$log = end($this->logs);
return $this->generate($log[ 0 ], $log[ 1 ]);
}
public function info()
public function log()
{
return array(
'server' => $this->pdo->getAttribute(PDO::ATTR_SERVER_INFO),
'client' => $this->pdo->getAttribute(PDO::ATTR_CLIENT_VERSION),
'driver' => $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME),
'version' => $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION),
'connection' => $this->pdo->getAttribute(PDO::ATTR_CONNECTION_STATUS)
return array_map(function ($log)
{
return $this->generate($log[ 0 ], $log[ 1 ]);
},
$this->logs
);
}
public function info()
{
$output = [
'server' => 'SERVER_INFO',
'driver' => 'DRIVER_NAME',
'client' => 'CLIENT_VERSION',
'version' => 'SERVER_VERSION',
'connection' => 'CONNECTION_STATUS'
];
foreach ($output as $key => $value)
{
$output[ $key ] = @$this->pdo->getAttribute(constant('PDO::ATTR_' . $value));
}
$output[ 'dsn' ] = $this->dsn;
return $output;
}
}
?>
\ No newline at end of file
.DS_Store
nbproject
RainTPL
-------------
The easy and fast template engine for PHP. Rain.TPL makes application easier to create & enables designers/developers to work better together.
\ No newline at end of file
<?php
//include the RainTPL class
include "inc/rain.tpl.class.php";
raintpl::configure("base_url", null );
raintpl::configure("tpl_dir", "tpl/" );
raintpl::configure("cache_dir", "tmp/" );
//initialize a Rain TPL object
$tpl = new RainTPL;
if( $cache = $tpl->cache('page', 60, 1) )
echo $cache;
else{
//variable assign example
$variable = "Hello World!";
$tpl->assign( "variable", $variable );
//loop example
$week = array( 'Monday', 'Tuersday', 'Wednesday', 'Friday', 'Saturday', 'Sunday' );
$tpl->assign( "week", $week );
//loop example 2
$user = array( array( 'name'=>'Jupiter', 'color'=>'yellow'),
array( 'name'=>'Mars', 'color'=>'red' ),
array( 'name'=>'Earth', 'color'=>'blue' ),
);
$tpl->assign( "user", $user );
//loop example with empty array
$tpl->assign( "empty_array", array() );
$info = array( 'title'=>'Rain TPL Example',
'copyright' => 'Copyright 2006 - 2011 Rain TPL<br>Project By Rain Team' );
$tpl->assign( $info );
global $global_variable;
$global_variable = 'This is a global variable';
//draw the template
echo $tpl->draw( 'page', $return_string = true );
}
?>
\ No newline at end of file
<?php
//include the RainTPL class
include "inc/rain.tpl.class.php";
// clean all the compiled templates from cache
array_map( "unlink", glob( raintpl::$cache_dir . "*.rtpl.php" ) );
echo "Cache is clean. Nice!";
?>
\ No newline at end of file
<?php
//include the RainTPL class
include "inc/rain.tpl.class.php";
raintpl::configure("base_url", null );
raintpl::configure("tpl_dir", "tpl/" );
raintpl::configure("cache_dir", "tmp/" );
//initialize a Rain TPL object
$tpl = new RainTPL;
//variable assign example
$variable = "Hello World!";
$tpl->assign( "variable", $variable );
//loop example
$week = array( 'Monday', 'Tuersday', 'Wednesday', 'Friday', 'Saturday', 'Sunday' );
$tpl->assign( "week", $week );
//loop example 2
$user = array( array( 'name'=>'Jupiter', 'color'=>'yellow'),
array( 'name'=>'Mars', 'color'=>'red' ),
array( 'name'=>'Earth', 'color'=>'blue' ),
);
$tpl->assign( "user", $user );
//loop example with empty array
$tpl->assign( "empty_array", array() );
$info = array( 'title'=>'Rain TPL Example',
'copyright' => 'Copyright 2006 - 2011 Rain TPL<br>Project By Rain Team' );
$tpl->assign( $info );
global $global_variable;
$global_variable = 'This is a global variable';
// you can draw the output
// $tpl->draw( 'page' );
// or the template output string by setting $return_string = true:
$html = $tpl->draw( 'page', $return_string = true );
// and then draw the output
echo $html;
class str{
function cut($t){
return substr($t, 1, 2 );
}
}
?>
\ No newline at end of file
<?php
// test if the browser support gz compression
if( ! ob_start("ob_gzhandler") )
// if the browser don't support gz compression init the regular output buffer
ob_start();
//include the RainTPL class
include "inc/rain.tpl.class.php";
raintpl::configure("base_url", null );
raintpl::configure("tpl_dir", "tpl/" );
raintpl::configure("cache_dir", "tmp/" );
//initialize a Rain TPL object
$tpl = new RainTPL;
//variable assign example
$variable = "Hello World!";
$tpl->assign( "variable", $variable );
//loop example
$week = array( 'Monday', 'Tuersday', 'Wednesday', 'Friday', 'Saturday', 'Sunday' );
$tpl->assign( "week", $week );
//loop example 2
$user = array( array( 'name'=>'Jupiter', 'color'=>'yellow'),
array( 'name'=>'Mars', 'color'=>'red' ),
array( 'name'=>'Earth', 'color'=>'blue' ),
);
$tpl->assign( "user", $user );
//loop example with empty array
$tpl->assign( "empty_array", array() );
$info = array( 'title'=>'Rain TPL Example',
'copyright' => 'Copyright 2006 - 2011 Rain TPL<br>Project By Rain Team' );
$tpl->assign( $info );
global $global_variable;
$global_variable = 'This is a global variable';
// you can draw the output
// $tpl->draw( 'page' );
// or the template output string by setting $return_string = true:
$html = $tpl->draw( 'page', $return_string = true );
// and then draw the output
echo $html;
class str{
function cut($t){
return substr($t, 1, 2 );
}
}
// -- end
\ No newline at end of file
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
<?php
/**
* RainTPL
* -------
* Realized by Federico Ulfo & maintained by the Rain Team
* Distributed under GNU/LGPL 3 License
*
* @version 2.7.2
*/
class RainTPL{
// -------------------------
// CONFIGURATION
// -------------------------
/**
* Template directory
*
* @var string
*/
static $tpl_dir = "tpl/";
/**
* Cache directory. Is the directory where RainTPL will compile the template and save the cache
*
* @var string
*/
static $cache_dir = "tmp/";
/**
* Template base URL. RainTPL will add this URL to the relative paths of element selected in $path_replace_list.
*
* @var string
*/
static $base_url = null;
/**
* Template extension.
*
* @var string
*/
static $tpl_ext = "html";
/**
* Path replace is a cool features that replace all relative paths of images (<img src="...">), stylesheet (<link href="...">), script (<script src="...">) and link (<a href="...">)
* Set true to enable the path replace.
*
* @var unknown_type
*/
static $path_replace = true;
/**
* You can set what the path_replace method will replace.
* Avaible options: a, img, link, script, input
*
* @var array
*/
static $path_replace_list = array( 'a', 'img', 'link', 'script', 'input' );
/**
* You can define in the black list what string are disabled into the template tags
*
* @var unknown_type
*/
static $black_list = array( '\$this', 'raintpl::', 'self::', '_SESSION', '_SERVER', '_ENV', 'eval', 'exec', 'unlink', 'rmdir' );
/**
* Check template.
* true: checks template update time, if changed it compile them
* false: loads the compiled template. Set false if server doesn't have write permission for cache_directory.
*
*/
static $check_template_update = true;
/**
* PHP tags <? ?>
* True: php tags are enabled into the template
* False: php tags are disabled into the template and rendered as html
*
* @var bool
*/
static $php_enabled = false;
/**
* Debug mode flag.
* True: debug mode is used, syntax errors are displayed directly in template. Execution of script is not terminated.
* False: exception is thrown on found error.
*
* @var bool
*/
static $debug = false;
// -------------------------
// -------------------------
// RAINTPL VARIABLES
// -------------------------
/**
* Is the array where RainTPL keep the variables assigned
*
* @var array
*/
public $var = array();
protected $tpl = array(), // variables to keep the template directories and info
$cache = false, // static cache enabled / disabled
$cache_id = null; // identify only one cache
protected static $config_name_sum = array(); // takes all the config to create the md5 of the file
// -------------------------
const CACHE_EXPIRE_TIME = 3600; // default cache expire time = hour
/**
* Assign variable
* eg. $t->assign('name','mickey');
*
* @param mixed $variable_name Name of template variable or associative array name/value
* @param mixed $value value assigned to this variable. Not set if variable_name is an associative array
*/
function assign( $variable, $value = null ){
if( is_array( $variable ) )
$this->var += $variable;
else
$this->var[ $variable ] = $value;
}
/**
* Draw the template
* eg. $html = $tpl->draw( 'demo', TRUE ); // return template in string
* or $tpl->draw( $tpl_name ); // echo the template
*
* @param string $tpl_name template to load
* @param boolean $return_string true=return a string, false=echo the template
* @return string
*/
function draw( $tpl_name, $return_string = false ){
try {
// compile the template if necessary and set the template filepath
$this->check_template( $tpl_name );
} catch (RainTpl_Exception $e) {
$output = $this->printDebug($e);
die($output);
}
// Cache is off and, return_string is false
// Rain just echo the template
if( !$this->cache && !$return_string ){
extract( $this->var );
include $this->tpl['compiled_filename'];
unset( $this->tpl );
}
// cache or return_string are enabled
// rain get the output buffer to save the output in the cache or to return it as string
else{
//----------------------
// get the output buffer
//----------------------
ob_start();
extract( $this->var );
include $this->tpl['compiled_filename'];
$raintpl_contents = ob_get_clean();
//----------------------
// save the output in the cache
if( $this->cache )
file_put_contents( $this->tpl['cache_filename'], "<?php if(!class_exists('raintpl')){exit;}?>" . $raintpl_contents );
// free memory
unset( $this->tpl );
// return or print the template
if( $return_string ) return $raintpl_contents; else echo $raintpl_contents;
}
}
/**
* If exists a valid cache for this template it returns the cache
*
* @param string $tpl_name Name of template (set the same of draw)
* @param int $expiration_time Set after how many seconds the cache expire and must be regenerated
* @return string it return the HTML or null if the cache must be recreated
*/
function cache( $tpl_name, $expire_time = self::CACHE_EXPIRE_TIME, $cache_id = null ){
// set the cache_id
$this->cache_id = $cache_id;
if( !$this->check_template( $tpl_name ) && file_exists( $this->tpl['cache_filename'] ) && ( time() - filemtime( $this->tpl['cache_filename'] ) < $expire_time ) )
return substr( file_get_contents( $this->tpl['cache_filename'] ), 43 );
else{
//delete the cache of the selected template
if (file_exists($this->tpl['cache_filename']))
unlink($this->tpl['cache_filename'] );
$this->cache = true;
}
}
/**
* Configure the settings of RainTPL
*
*/
static function configure( $setting, $value = null ){
if( is_array( $setting ) )
foreach( $setting as $key => $value )
self::configure( $key, $value );
else if( property_exists( __CLASS__, $setting ) ){
self::$$setting = $value;
self::$config_name_sum[ $setting ] = $value; // take trace of all config
}
}
// check if has to compile the template
// return true if the template has changed
protected function check_template( $tpl_name ){
if( !isset($this->tpl['checked']) ){
$tpl_basename = basename( $tpl_name ); // template basename
$tpl_basedir = strpos($tpl_name,"/") ? dirname($tpl_name) . '/' : null; // template basedirectory
$tpl_dir = self::$tpl_dir . $tpl_basedir; // template directory
$this->tpl['tpl_filename'] = $tpl_dir . $tpl_basename . '.' . self::$tpl_ext; // template filename
$temp_compiled_filename = self::$cache_dir . $tpl_basename . "." . md5( $tpl_dir . serialize(self::$config_name_sum));
$this->tpl['compiled_filename'] = $temp_compiled_filename . '.rtpl.php'; // cache filename
$this->tpl['cache_filename'] = $temp_compiled_filename . '.s_' . $this->cache_id . '.rtpl.php'; // static cache filename
// if the template doesn't exsist throw an error
if( self::$check_template_update && !file_exists( $this->tpl['tpl_filename'] ) ){
$e = new RainTpl_NotFoundException( 'Template '. $tpl_basename .' not found!' );
throw $e->setTemplateFile($this->tpl['tpl_filename']);
}
// file doesn't exsist, or the template was updated, Rain will compile the template
if( !file_exists( $this->tpl['compiled_filename'] ) || ( self::$check_template_update && filemtime($this->tpl['compiled_filename']) < filemtime( $this->tpl['tpl_filename'] ) ) ){
$this->compileFile( $tpl_basename, $tpl_basedir, $this->tpl['tpl_filename'], self::$cache_dir, $this->tpl['compiled_filename'] );
return true;
}
$this->tpl['checked'] = true;
}
}
/**
* execute stripslaches() on the xml block. Invoqued by preg_replace_callback function below
* @access protected
*/
protected function xml_reSubstitution($capture) {
return "<?php echo '<?xml ".stripslashes($capture[1])." ?>'; ?>";
}
/**
* Compile and write the compiled template file
* @access protected
*/
protected function compileFile( $tpl_basename, $tpl_basedir, $tpl_filename, $cache_dir, $compiled_filename ){
//read template file
$this->tpl['source'] = $template_code = file_get_contents( $tpl_filename );
//xml substitution
$template_code = preg_replace( "/<\?xml(.*?)\?>/s", "##XML\\1XML##", $template_code );
//disable php tag
if( !self::$php_enabled )
$template_code = str_replace( array("<?","?>"), array("&lt;?","?&gt;"), $template_code );
//xml re-substitution
$template_code = preg_replace_callback ( "/##XML(.*?)XML##/s", array($this, 'xml_reSubstitution'), $template_code );
//compile template
$template_compiled = "<?php if(!class_exists('raintpl')){exit;}?>" . $this->compileTemplate( $template_code, $tpl_basedir );
// fix the php-eating-newline-after-closing-tag-problem
$template_compiled = str_replace( "?>\n", "?>\n\n", $template_compiled );
// create directories
if( !is_dir( $cache_dir ) )
mkdir( $cache_dir, 0755, true );
if( !is_writable( $cache_dir ) )
throw new RainTpl_Exception ('Cache directory ' . $cache_dir . 'doesn\'t have write permission. Set write permission or set RAINTPL_CHECK_TEMPLATE_UPDATE to false. More details on http://www.raintpl.com/Documentation/Documentation-for-PHP-developers/Configuration/');
//write compiled file
file_put_contents( $compiled_filename, $template_compiled );
}
/**
* Compile template
* @access protected
*/
protected function compileTemplate( $template_code, $tpl_basedir ){
//tag list
$tag_regexp = array( 'loop' => '(\{loop(?: name){0,1}="\${0,1}[^"]*"\})',
'loop_close' => '(\{\/loop\})',
'if' => '(\{if(?: condition){0,1}="[^"]*"\})',
'elseif' => '(\{elseif(?: condition){0,1}="[^"]*"\})',
'else' => '(\{else\})',
'if_close' => '(\{\/if\})',
'function' => '(\{function="[^"]*"\})',
'noparse' => '(\{noparse\})',
'noparse_close'=> '(\{\/noparse\})',
'ignore' => '(\{ignore\}|\{\*)',
'ignore_close' => '(\{\/ignore\}|\*\})',
'include' => '(\{include="[^"]*"(?: cache="[^"]*")?\})',
'template_info'=> '(\{\$template_info\})',
'function' => '(\{function="(\w*?)(?:.*?)"\})'
);
$tag_regexp = "/" . join( "|", $tag_regexp ) . "/";
//split the code with the tags regexp
$template_code = preg_split ( $tag_regexp, $template_code, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
//path replace (src of img, background and href of link)
$template_code = $this->path_replace( $template_code, $tpl_basedir );
//compile the code
$compiled_code = $this->compileCode( $template_code );
//return the compiled code
return $compiled_code;
}
/**
* Compile the code
* @access protected
*/
protected function compileCode( $parsed_code ){
//variables initialization
$compiled_code = $open_if = $comment_is_open = $ignore_is_open = null;
$loop_level = 0;
//read all parsed code
while( $html = array_shift( $parsed_code ) ){
//close ignore tag
if( !$comment_is_open && ( strpos( $html, '{/ignore}' ) !== FALSE || strpos( $html, '*}' ) !== FALSE ) )
$ignore_is_open = false;
//code between tag ignore id deleted
elseif( $ignore_is_open ){
//ignore the code
}
//close no parse tag
elseif( strpos( $html, '{/noparse}' ) !== FALSE )
$comment_is_open = false;
//code between tag noparse is not compiled
elseif( $comment_is_open )
$compiled_code .= $html;
//ignore
elseif( strpos( $html, '{ignore}' ) !== FALSE || strpos( $html, '{*' ) !== FALSE )
$ignore_is_open = true;
//noparse
elseif( strpos( $html, '{noparse}' ) !== FALSE )
$comment_is_open = true;
//include tag
elseif( preg_match( '/\{include="([^"]*)"(?: cache="([^"]*)"){0,1}\}/', $html, $code ) ){
//variables substitution
$include_var = $this->var_replace( $code[ 1 ], $left_delimiter = null, $right_delimiter = null, $php_left_delimiter = '".' , $php_right_delimiter = '."', $loop_level );
// if the cache is active
if( isset($code[ 2 ]) ){
//dynamic include
$compiled_code .= '<?php $tpl = new '.get_class($this).';' .
'if( $cache = $tpl->cache( $template = basename("'.$include_var.'") ) )' .
' echo $cache;' .
'else{' .
' $tpl_dir_temp = self::$tpl_dir;' .
' $tpl->assign( $this->var );' .
( !$loop_level ? null : '$tpl->assign( "key", $key'.$loop_level.' ); $tpl->assign( "value", $value'.$loop_level.' );' ).
' $tpl->draw( dirname("'.$include_var.'") . ( substr("'.$include_var.'",-1,1) != "/" ? "/" : "" ) . basename("'.$include_var.'") );'.
'} ?>';
}
else{
//dynamic include
$compiled_code .= '<?php $tpl = new '.get_class($this).';' .
'$tpl_dir_temp = self::$tpl_dir;' .
'$tpl->assign( $this->var );' .
( !$loop_level ? null : '$tpl->assign( "key", $key'.$loop_level.' ); $tpl->assign( "value", $value'.$loop_level.' );' ).
'$tpl->draw( dirname("'.$include_var.'") . ( substr("'.$include_var.'",-1,1) != "/" ? "/" : "" ) . basename("'.$include_var.'") );'.
'?>';
}
}
//loop
elseif( preg_match( '/\{loop(?: name){0,1}="\${0,1}([^"]*)"\}/', $html, $code ) ){
//increase the loop counter
$loop_level++;
//replace the variable in the loop
$var = $this->var_replace( '$' . $code[ 1 ], $tag_left_delimiter=null, $tag_right_delimiter=null, $php_left_delimiter=null, $php_right_delimiter=null, $loop_level-1 );
//loop variables
$counter = "\$counter$loop_level"; // count iteration
$key = "\$key$loop_level"; // key
$value = "\$value$loop_level"; // value
//loop code
$compiled_code .= "<?php $counter=-1; if( isset($var) && is_array($var) && sizeof($var) ) foreach( $var as $key => $value ){ $counter++; ?>";
}
//close loop tag
elseif( strpos( $html, '{/loop}' ) !== FALSE ) {
//iterator
$counter = "\$counter$loop_level";
//decrease the loop counter
$loop_level--;
//close loop code
$compiled_code .= "<?php } ?>";
}
//if
elseif( preg_match( '/\{if(?: condition){0,1}="([^"]*)"\}/', $html, $code ) ){
//increase open if counter (for intendation)
$open_if++;
//tag
$tag = $code[ 0 ];
//condition attribute
$condition = $code[ 1 ];
// check if there's any function disabled by black_list
$this->function_check( $tag );
//variable substitution into condition (no delimiter into the condition)
$parsed_condition = $this->var_replace( $condition, $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level );
//if code
$compiled_code .= "<?php if( $parsed_condition ){ ?>";
}
//elseif
elseif( preg_match( '/\{elseif(?: condition){0,1}="([^"]*)"\}/', $html, $code ) ){
//tag
$tag = $code[ 0 ];
//condition attribute
$condition = $code[ 1 ];
//variable substitution into condition (no delimiter into the condition)
$parsed_condition = $this->var_replace( $condition, $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level );
//elseif code
$compiled_code .= "<?php }elseif( $parsed_condition ){ ?>";
}
//else
elseif( strpos( $html, '{else}' ) !== FALSE ) {
//else code
$compiled_code .= '<?php }else{ ?>';
}
//close if tag
elseif( strpos( $html, '{/if}' ) !== FALSE ) {
//decrease if counter
$open_if--;
// close if code
$compiled_code .= '<?php } ?>';
}
//function
elseif( preg_match( '/\{function="(\w*)(.*?)"\}/', $html, $code ) ){
//tag
$tag = $code[ 0 ];
//function
$function = $code[ 1 ];
// check if there's any function disabled by black_list
$this->function_check( $tag );
if( empty( $code[ 2 ] ) )
$parsed_function = $function . "()";
else
// parse the function
$parsed_function = $function . $this->var_replace( $code[ 2 ], $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level );
//if code
$compiled_code .= "<?php echo $parsed_function; ?>";
}
// show all vars
elseif ( strpos( $html, '{$template_info}' ) !== FALSE ) {
//tag
$tag = '{$template_info}';
//if code
$compiled_code .= '<?php echo "<pre>"; print_r( $this->var ); echo "</pre>"; ?>';
}
//all html code
else{
//variables substitution (es. {$title})
$html = $this->var_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true );
//const substitution (es. {#CONST#})
$html = $this->const_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true );
//functions substitution (es. {"string"|functions})
$compiled_code .= $this->func_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true );
}
}
if( $open_if > 0 ) {
$e = new RainTpl_SyntaxException('Error! You need to close an {if} tag in ' . $this->tpl['tpl_filename'] . ' template');
throw $e->setTemplateFile($this->tpl['tpl_filename']);
}
return $compiled_code;
}
/**
* Reduce a path, eg. www/library/../filepath//file => www/filepath/file
* @param type $path
* @return type
*/
protected function reduce_path( $path ){
$path = str_replace( "://", "@not_replace@", $path );
$path = str_replace( "//", "/", $path );
$path = str_replace( "@not_replace@", "://", $path );
return preg_replace('/\w+\/\.\.\//', '', $path );
}
/**
* replace the path of image src, link href and a href.
* url => template_dir/url
* url# => url
* http://url => http://url
*
* @param string $html
* @return string html sostituito
*/
protected function path_replace( $html, $tpl_basedir ){
if( self::$path_replace ){
$tpl_dir = self::$base_url . self::$tpl_dir . $tpl_basedir;
// reduce the path
$path = $this->reduce_path($tpl_dir);
$exp = $sub = array();
if( in_array( "img", self::$path_replace_list ) ){
$exp = array( '/<img(.*?)src=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<img(.*?)src=(?:")([^"]+?)#(?:")/i', '/<img(.*?)src="(.*?)"/', '/<img(.*?)src=(?:\@)([^"]+?)(?:\@)/i' );
$sub = array( '<img$1src=@$2://$3@', '<img$1src=@$2@', '<img$1src="' . $path . '$2"', '<img$1src="$2"' );
}
if( in_array( "script", self::$path_replace_list ) ){
$exp = array_merge( $exp , array( '/<script(.*?)src=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<script(.*?)src=(?:")([^"]+?)#(?:")/i', '/<script(.*?)src="(.*?)"/', '/<script(.*?)src=(?:\@)([^"]+?)(?:\@)/i' ) );
$sub = array_merge( $sub , array( '<script$1src=@$2://$3@', '<script$1src=@$2@', '<script$1src="' . $path . '$2"', '<script$1src="$2"' ) );
}
if( in_array( "link", self::$path_replace_list ) ){
$exp = array_merge( $exp , array( '/<link(.*?)href=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<link(.*?)href=(?:")([^"]+?)#(?:")/i', '/<link(.*?)href="(.*?)"/', '/<link(.*?)href=(?:\@)([^"]+?)(?:\@)/i' ) );
$sub = array_merge( $sub , array( '<link$1href=@$2://$3@', '<link$1href=@$2@' , '<link$1href="' . $path . '$2"', '<link$1href="$2"' ) );
}
if( in_array( "a", self::$path_replace_list ) ){
$exp = array_merge( $exp , array( '/<a(.*?)href=(?:")(http\:\/\/|https\:\/\/|javascript:)([^"]+?)(?:")/i', '/<a(.*?)href="(.*?)"/', '/<a(.*?)href=(?:\@)([^"]+?)(?:\@)/i' ) );
$sub = array_merge( $sub , array( '<a$1href=@$2$3@', '<a$1href="' . self::$base_url . '$2"', '<a$1href="$2"' ) );
}
if( in_array( "input", self::$path_replace_list ) ){
$exp = array_merge( $exp , array( '/<input(.*?)src=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<input(.*?)src=(?:")([^"]+?)#(?:")/i', '/<input(.*?)src="(.*?)"/', '/<input(.*?)src=(?:\@)([^"]+?)(?:\@)/i' ) );
$sub = array_merge( $sub , array( '<input$1src=@$2://$3@', '<input$1src=@$2@', '<input$1src="' . $path . '$2"', '<input$1src="$2"' ) );
}
return preg_replace( $exp, $sub, $html );
}
else
return $html;
}
// replace const
function const_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){
// const
return preg_replace( '/\{\#(\w+)\#{0,1}\}/', $php_left_delimiter . ( $echo ? " echo " : null ) . '\\1' . $php_right_delimiter, $html );
}
// replace functions/modifiers on constants and strings
function func_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){
preg_match_all( '/' . '\{\#{0,1}(\"{0,1}.*?\"{0,1})(\|\w.*?)\#{0,1}\}' . '/', $html, $matches );
for( $i=0, $n=count($matches[0]); $i<$n; $i++ ){
//complete tag ex: {$news.title|substr:0,100}
$tag = $matches[ 0 ][ $i ];
//variable name ex: news.title
$var = $matches[ 1 ][ $i ];
//function and parameters associate to the variable ex: substr:0,100
$extra_var = $matches[ 2 ][ $i ];
// check if there's any function disabled by black_list
$this->function_check( $tag );
$extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level );
// check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value
$is_init_variable = preg_match( "/^(\s*?)\=[^=](.*?)$/", $extra_var );
//function associate to variable
$function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null;
//variable path split array (ex. $news.title o $news[title]) or object (ex. $news->title)
$temp = preg_split( "/\.|\[|\-\>/", $var );
//variable name
$var_name = $temp[ 0 ];
//variable path
$variable_path = substr( $var, strlen( $var_name ) );
//parentesis transform [ e ] in [" e in "]
$variable_path = str_replace( '[', '["', $variable_path );
$variable_path = str_replace( ']', '"]', $variable_path );
//transform .$variable in ["$variable"]
$variable_path = preg_replace('/\.\$(\w+)/', '["$\\1"]', $variable_path );
//transform [variable] in ["variable"]
$variable_path = preg_replace('/\.(\w+)/', '["\\1"]', $variable_path );
//if there's a function
if( $function_var ){
// check if there's a function or a static method and separate, function by parameters
$function_var = str_replace("::", "@double_dot@", $function_var );
// get the position of the first :
if( $dot_position = strpos( $function_var, ":" ) ){
// get the function and the parameters
$function = substr( $function_var, 0, $dot_position );
$params = substr( $function_var, $dot_position+1 );
}
else{
//get the function
$function = str_replace( "@double_dot@", "::", $function_var );
$params = null;
}
// replace back the @double_dot@ with ::
$function = str_replace( "@double_dot@", "::", $function );
$params = str_replace( "@double_dot@", "::", $params );
}
else
$function = $params = null;
$php_var = $var_name . $variable_path;
// compile the variable for php
if( isset( $function ) ){
if( $php_var )
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter;
else
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $params ) )" : "$function()" ) . $php_right_delimiter;
}
else
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter;
$html = str_replace( $tag, $php_var, $html );
}
return $html;
}
function var_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){
//all variables
if( preg_match_all( '/' . $tag_left_delimiter . '\$(\w+(?:\.\${0,1}[A-Za-z0-9_]+)*(?:(?:\[\${0,1}[A-Za-z0-9_]+\])|(?:\-\>\${0,1}[A-Za-z0-9_]+))*)(.*?)' . $tag_right_delimiter . '/', $html, $matches ) ){
for( $parsed=array(), $i=0, $n=count($matches[0]); $i<$n; $i++ )
$parsed[$matches[0][$i]] = array('var'=>$matches[1][$i],'extra_var'=>$matches[2][$i]);
foreach( $parsed as $tag => $array ){
//variable name ex: news.title
$var = $array['var'];
//function and parameters associate to the variable ex: substr:0,100
$extra_var = $array['extra_var'];
// check if there's any function disabled by black_list
$this->function_check( $tag );
$extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level );
// check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value
$is_init_variable = preg_match( "/^[a-z_A-Z\.\[\](\-\>)]*=[^=]*$/", $extra_var );
//function associate to variable
$function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null;
//variable path split array (ex. $news.title o $news[title]) or object (ex. $news->title)
$temp = preg_split( "/\.|\[|\-\>/", $var );
//variable name
$var_name = $temp[ 0 ];
//variable path
$variable_path = substr( $var, strlen( $var_name ) );
//parentesis transform [ e ] in [" e in "]
$variable_path = str_replace( '[', '["', $variable_path );
$variable_path = str_replace( ']', '"]', $variable_path );
//transform .$variable in ["$variable"] and .variable in ["variable"]
$variable_path = preg_replace('/\.(\${0,1}\w+)/', '["\\1"]', $variable_path );
// if is an assignment also assign the variable to $this->var['value']
if( $is_init_variable )
$extra_var = "=\$this->var['{$var_name}']{$variable_path}" . $extra_var;
//if there's a function
if( $function_var ){
// check if there's a function or a static method and separate, function by parameters
$function_var = str_replace("::", "@double_dot@", $function_var );
// get the position of the first :
if( $dot_position = strpos( $function_var, ":" ) ){
// get the function and the parameters
$function = substr( $function_var, 0, $dot_position );
$params = substr( $function_var, $dot_position+1 );
}
else{
//get the function
$function = str_replace( "@double_dot@", "::", $function_var );
$params = null;
}
// replace back the @double_dot@ with ::
$function = str_replace( "@double_dot@", "::", $function );
$params = str_replace( "@double_dot@", "::", $params );
}
else
$function = $params = null;
//if it is inside a loop
if( $loop_level ){
//verify the variable name
if( $var_name == 'key' )
$php_var = '$key' . $loop_level;
elseif( $var_name == 'value' )
$php_var = '$value' . $loop_level . $variable_path;
elseif( $var_name == 'counter' )
$php_var = '$counter' . $loop_level;
else
$php_var = '$' . $var_name . $variable_path;
}else
$php_var = '$' . $var_name . $variable_path;
// compile the variable for php
if( isset( $function ) )
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter;
else
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter;
$html = str_replace( $tag, $php_var, $html );
}
}
return $html;
}
/**
* Check if function is in black list (sandbox)
*
* @param string $code
* @param string $tag
*/
protected function function_check( $code ){
$preg = '#(\W|\s)' . implode( '(\W|\s)|(\W|\s)', self::$black_list ) . '(\W|\s)#';
// check if the function is in the black list (or not in white list)
if( count(self::$black_list) && preg_match( $preg, $code, $match ) ){
// find the line of the error
$line = 0;
$rows=explode("\n",$this->tpl['source']);
while( !strpos($rows[$line],$code) )
$line++;
// stop the execution of the script
$e = new RainTpl_SyntaxException('Unallowed syntax in ' . $this->tpl['tpl_filename'] . ' template');
throw $e->setTemplateFile($this->tpl['tpl_filename'])
->setTag($code)
->setTemplateLine($line);
}
}
/**
* Prints debug info about exception or passes it further if debug is disabled.
*
* @param RainTpl_Exception $e
* @return string
*/
protected function printDebug(RainTpl_Exception $e){
if (!self::$debug) {
throw $e;
}
$output = sprintf('<h2>Exception: %s</h2><h3>%s</h3><p>template: %s</p>',
get_class($e),
$e->getMessage(),
$e->getTemplateFile()
);
if ($e instanceof RainTpl_SyntaxException) {
if (null != $e->getTemplateLine()) {
$output .= '<p>line: ' . $e->getTemplateLine() . '</p>';
}
if (null != $e->getTag()) {
$output .= '<p>in tag: ' . htmlspecialchars($e->getTag()) . '</p>';
}
if (null != $e->getTemplateLine() && null != $e->getTag()) {
$rows=explode("\n", htmlspecialchars($this->tpl['source']));
$rows[$e->getTemplateLine()] = '<font color=red>' . $rows[$e->getTemplateLine()] . '</font>';
$output .= '<h3>template code</h3>' . implode('<br />', $rows) . '</pre>';
}
}
$output .= sprintf('<h3>trace</h3><p>In %s on line %d</p><pre>%s</pre>',
$e->getFile(), $e->getLine(),
nl2br(htmlspecialchars($e->getTraceAsString()))
);
return $output;
}
}
/**
* Basic Rain tpl exception.
*/
class RainTpl_Exception extends Exception{
/**
* Path of template file with error.
*/
protected $templateFile = '';
/**
* Returns path of template file with error.
*
* @return string
*/
public function getTemplateFile()
{
return $this->templateFile;
}
/**
* Sets path of template file with error.
*
* @param string $templateFile
* @return RainTpl_Exception
*/
public function setTemplateFile($templateFile)
{
$this->templateFile = (string) $templateFile;
return $this;
}
}
/**
* Exception thrown when template file does not exists.
*/
class RainTpl_NotFoundException extends RainTpl_Exception{
}
/**
* Exception thrown when syntax error occurs.
*/
class RainTpl_SyntaxException extends RainTpl_Exception{
/**
* Line in template file where error has occured.
*
* @var int | null
*/
protected $templateLine = null;
/**
* Tag which caused an error.
*
* @var string | null
*/
protected $tag = null;
/**
* Returns line in template file where error has occured
* or null if line is not defined.
*
* @return int | null
*/
public function getTemplateLine()
{
return $this->templateLine;
}
/**
* Sets line in template file where error has occured.
*
* @param int $templateLine
* @return RainTpl_SyntaxException
*/
public function setTemplateLine($templateLine)
{
$this->templateLine = (int) $templateLine;
return $this;
}
/**
* Returns tag which caused an error.
*
* @return string
*/
public function getTag()
{
return $this->tag;
}
/**
* Sets tag which caused an error.
*
* @param string $tag
* @return RainTpl_SyntaxException
*/
public function setTag($tag)
{
$this->tag = (string) $tag;
return $this;
}
}
// -- end
*.php
registration-system/frameworks/raintpl/tpl/img/bottom.gif

250 B

registration-system/frameworks/raintpl/tpl/img/logo.gif

3.93 KiB

registration-system/frameworks/raintpl/tpl/img/top.gif

414 B

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8 />
<title>{$title}</title>
<!-- this link will be substituted with the right path : href="THEMES/acid/style.css" -->
<link href="style.css" type="text/css" rel="stylesheet" >
</head>
<body>
<!-- this img will be substituted with the right path : src="THEMES/acid/images.gif" -->
<div id="logo"><a href="http://www.raintpl.com"><img src="img/logo.gif"></a></div>
<!-- content -->
<div id="content">
<h2>Variable example</h2>
<div class="layout">
<h3>Variable example</h3>
{* all code between noparse tags is not compiled *}
<tt>variable {noparse}{$variable}{/noparse} = <b>{$variable}</b></tt>
<br/><br/>
<h3>Variable assignment</h3>
<tt>assignment {$number=10} and print {$number}</tt>
<br/><br/>
<h3>Operation with strings</h3>
<tt>
{$variable . $number}<br/>
{$number + 20}
</tt>
<br/><br/>
<h3>Variable Modifiers</h3>
<tt>
{$variable|substr:0,7}<br/>
a modifier on string: {"hello world"|strtoupper}
</tt>
<br/><br/>
<h3>Global variables</h3>
<tt>The variable is declared as global into the PHP {$GLOBALS.global_variable}</tt>
<br/><br/>
<h3>Show all declared variables</h3>
To show all declared variable use {noparse}{$template_info}{/noparse}.<br/><br/>
<tt>
{$template_info}
</tt>
<br/><br/>
</div>
<h2>Constants</h2>
<div class="layout">
<h3>Constant</h3>
<tt>Constant: {#true#}</tt>
<br/><br/>
<h3>Modier on constant as follow</h3>
<tt>Negation of false is true: {PHP_VERSION|round}</tt>
</div>
<h2>Loop example</h2>
<div class="layout">
<h3>Simple loop example</h3>
<tt>
<ul>
{loop="week"}
<li>{$key} = {$value}</li>
{/loop}
</ul>
</tt>
<br/><br/>
<h3>Loop example with associative array</h3>
<tt>
<ul>
<li>ID _ Name _ Color</li>
{loop="user"}
<li class="color{$counter%2+1}">{$key}) - {$value.name|strtoupper} - {$value.color}</li>
{/loop}
</ul>
</tt>
<br/><br/>
<h3>Loop an empty array</h3>
<tt>
<ul>
{loop="empty_array"}
<li class="color{$counter%2+1}">{$key}) - {$value.name} - {$value.color}</li>
{else}
<b>The array is empty</b>
{/loop}
</ul>
</tt>
</div>
<h2>If Example</h2>
<div class="layout">
<h3>simple if example</h3>
<tt>
{if="$number==10"}OK!
{else}NO!{/if}
</tt>
<br/><br/>
<h3>example of if, elseif, else example</h3>
<tt>
{if="substr($variable,0,1)=='A'"}First character is A
{elseif="substr($variable,0,1)=='B'"}First character is B
{else}First character of variable is not A neither B
{/if}
</tt>
<br/><br/>
<h3>use of ? : operator (number==10?'OK!':'no')</h3>
You can also use the ? operator instead of if
<tt>{$number==10? 'OK!' : 'no'}</tt>
</div>
<h2>Include Example</h2>
<div class="layout">
<h3>Example of include file</h3>
<tt>{include="test"}</tt>
</div>
<h2>Functions</h2>
<div class="layout">
<h3>Example of function: ucfirst(strtolower($title))</h3>
<tt>{function="ucfirst(strtolower($title))"}</tt>
</div>
<h2>Path Replace (WYSIWYG)</h2>
<div class="layout">
<h3>WYSIWYG</h3>
RainTPL replaces relative paths of images, css and links automatically with the correct server paths.
<br/><br/>
<h3>Path replace on relative path of image</h3>
into the template the image is wrote as:
<code>&lt;img src="img/logo.gif" alt="logo"/&gt;</code>
in the compiled template the path is replaced with the correct path <b>tpl/img/logo.gif</b>:<br/>
<img src="img/logo.gif" alt="logo"/>
<br/><br/><br/>
<a href="javascript:alert('Javascript is not replaced');">RainTpl is javascript friendly</a>
<b>Absolute paths and path ending with # are not replaced</b>
<br/><br/>For more info read the documentation:
<tt><a href="http://www.raintpl.com/Documentation/Documentation-for-web-designers/WYSIWYG/">http://www.raintpl.com/Documentation/Documentation-for-web-designers/WYSIWYG/</a></tt>
</div>
</div>
<div id="footer">{$copyright}</div>
</body>
</html>
/* CSS Document */
body{ margin:0px; color:#333; font: 13px Helvetica; background:#eee;}
a{ color: #333; }
a:hover{ color: #999; }
img{border:0px;}
#logo{width:100%;height:80px;background:url('img/top.gif') repeat-x #666;}
#content{ height: 100%;padding:20px; }
#footer{background: url('img/bottom.gif') repeat-x;color:#ccff00; padding:15px; text-align:center;}
#footer a{color:#ccff00;}
.layout{background:#fff;border: 1px solid #ccc; padding:20px;margin-bottom:30px;}
code{ display:block;font:12px monospace; background: #e9ffe9;padding: 15px; border: solid 1px #ccddcc; margin-bottom:10px;}
tt{ display:block; font:12px monospace; background: #f6fdfd; padding: 15px; border: solid 1px #ccdddd; margin-bottom:0 0 10px 0; }
.color1{background:#eeeeff;}
.color2{background:#ddddee;}
\ No newline at end of file
<div class="output">This is test.html</div>
\ No newline at end of file
<?php
class soft_protect
{
private $elements = array();
public function add($elements, $regex)
{
array_push($this->elements, array($elements, $regex));
return $this;
}
public function write()
{
$lines = array();
array_push($lines, "<script type='text/javascript'>");
foreach($this->elements as $element)
{
$elems = array();
foreach($element[0] as $protectkey)
{
array_push($elems, "'".addslashes($protectkey)."'");
}
array_push($lines, "FAPI.attachSoftProtector([".implode(",", $elems)."], ".$element[1].");");
}
array_push($lines, "</script>");
return implode("\r\n", $lines);
}
}
\ No newline at end of file