Init Repo

This commit is contained in:
root
2019-09-06 23:53:10 +08:00
commit f0ef89dfbb
7905 changed files with 914138 additions and 0 deletions

View File

@ -0,0 +1,306 @@
<?php
class LtAutoloader
{
public $conf = array(
/**
* 是否自动加载定义了函数的文件
*
* 可选项:
* # true 自动加载
* # false 跳过函数只自动加载定义了class或者interface的文件
*/
"load_function" => true,
/**
* 要扫描的文件类型
*
* 若该属性设置为array("php","inc","php3")
* 则扩展名为"php","inc","php3"的文件会被扫描,
* 其它扩展名的文件会被忽略
*/
"allow_file_extension" => array("php", "inc"),
/**
* 不扫描的目录
*
* 若该属性设置为array(".svn", ".setting")
* 则所有名为".setting"的目录也会被忽略
*/
"skip_dir_names" => array(".svn"),
);
public $storeHandle;
public $autoloadPath;
protected $functionFileMapping;
protected $fileStore;
public function init()
{
if (!is_object($this->storeHandle))
{
$this->storeHandle = new LtStoreMemory;
$this->fileStore = new LtStoreFile;
$this->fileStore->prefix = 'LtAutoloader-token-cache';
$this->fileStore->useSerialize = true;
$this->fileStore->init();
}
// Whether scanning directory
if (0 == $this->storeHandle->get(".class_total") && 0 == $this->storeHandle->get(".function_total"))
{
$this->storeHandle->add(".class_total", 0);
$this->storeHandle->add(".function_total", 0);
$this->storeHandle->add(".functions", array(), 0);
$autoloadPath = $this->preparePath($this->autoloadPath);
foreach($autoloadPath as $key => $path)
{
if (is_file($path))
{
$this->addFileMap($path);
unset($autoloadPath[$key]);
}
}
$this->scanDirs($autoloadPath);
unset($autoloadPath);
}
// Whether loading function files
if ($this->conf["load_function"])
{
$this->loadFunction();
}
spl_autoload_register(array($this, "loadClass"));
}
public function loadFunction()
{
if ($functionFiles = $this->storeHandle->get(".functions"))
{
foreach ($functionFiles as $functionFile)
{
include($functionFile);
}
}
}
public function loadClass($className)
{
if ($classFile = $this->storeHandle->get(strtolower($className)))
{
include($classFile);
}
}
protected function convertPath($path)
{
$path = str_replace("\\", "/", $path);
if (!is_readable($path))
{
trigger_error("Directory is not exists/readable: {$path}");
return false;
}
$path = rtrim(realpath($path), '\\/');
if ("WINNT" != PHP_OS && preg_match("/\s/i", $path))
{
trigger_error("Directory contains space/tab/newline is not supported: {$path}");
return false;
}
return $path;
}
/**
* The string or an Multidimensional array into a one-dimensional array
*
* @param array $ or string $var
* @return array one-dimensional array
*/
protected function preparePath($var)
{
$ret = array();
if (!is_array($var))
{
$var = array($var);
}
$i = 0;
while (isset($var[$i]))
{
if (!is_array($var[$i]) && $path = $this->convertPath($var[$i]))
{
$ret[] = $path;
}
else
{
foreach($var[$i] as $v)
{
$var[] = $v;
}
}
unset($var[$i]);
$i ++;
}
return $ret;
}
/**
* Using iterative algorithm scanning subdirectories
* save autoloader filemap
*
* @param array $dirs one-dimensional
* @return
*/
protected function scanDirs($dirs)
{
$i = 0;
while (isset($dirs[$i]))
{
$dir = $dirs[$i];
$files = scandir($dir);
foreach ($files as $file)
{
if (in_array($file, array(".", "..")) || in_array($file, $this->conf["skip_dir_names"]))
{
continue;
}
$currentFile = $dir . DIRECTORY_SEPARATOR . $file;
if (is_file($currentFile))
{
$this->addFileMap($currentFile);
}
else if (is_dir($currentFile))
{
// if $currentFile is a directory, pass through the next loop.
$dirs[] = $currentFile;
}
else
{
trigger_error("$currentFile is not a file or a directory.");
}
} //end foreach
unset($dirs[$i]);
$i ++;
} //end while
}
protected function parseLibNames($src)
{
$libNames = array();
$tokens = token_get_all($src);
$level = 0;
$found = false;
$name = '';
foreach ($tokens as $token)
{
if (is_string($token))
{
if ('{' == $token)
{
$level ++;
}
else if ('}' == $token)
{
$level --;
}
}
else
{
list($id, $text) = $token;
if (T_CURLY_OPEN == $id || T_DOLLAR_OPEN_CURLY_BRACES == $id)
{
$level ++;
}
if (0 < $level)
{
continue;
}
switch ($id)
{
case T_STRING:
if ($found)
{
$libNames[strtolower($name)][] = $text;
$found = false;
}
break;
case T_CLASS:
case T_INTERFACE:
case T_FUNCTION:
$found = true;
$name = $text;
break;
}
}
}
return $libNames;
}
protected function addClass($className, $file)
{
$key = strtolower($className);
if ($existedClassFile = $this->storeHandle->get($key))
{
trigger_error("duplicate class [$className] found in:\n$existedClassFile\n$file\n");
return false;
}
else
{
$this->storeHandle->add($key, $file);
$this->storeHandle->update(".class_total", $this->storeHandle->get(".class_total") + 1);
return true;
}
}
protected function addFunction($functionName, $file)
{
$functionName = strtolower($functionName);
if (isset($this->functionFileMapping[$functionName]))
{
$existedFunctionFile = $this->functionFileMapping[$functionName];
trigger_error("duplicate function [$functionName] found in:\n$existedFunctionFile\n$file\n");
return false;
}
else
{
$this->functionFileMapping[$functionName] = $file;
$this->storeHandle->update(".functions", array_unique(array_values($this->functionFileMapping)));
$this->storeHandle->update(".function_total", count($this->functionFileMapping));
return true;
}
}
protected function addFileMap($file)
{
if (!in_array(pathinfo($file, PATHINFO_EXTENSION), $this->conf["allow_file_extension"]))
{
return false;
}
$libNames = array();
if ($this->fileStore instanceof LtStore)
{
$cachedFileLastModified = (int) @filemtime($this->fileStore->getFilePath($file));
if ($cachedFileLastModified < filemtime($file) || !is_array(($libNames = $this->fileStore->get($file))))
{
$libNames = $this->parseLibNames(trim(file_get_contents($file)));
if (0 < $cachedFileLastModified)
{
$this->fileStore->update($file, $libNames);
}
else
{
$this->fileStore->add($file, $libNames);
}
}
}
else
{
$libNames = $this->parseLibNames(trim(file_get_contents($file)));
}
foreach ($libNames as $libType => $libArray)
{
$method = "function" == $libType ? "addFunction" : "addClass";
foreach ($libArray as $libName)
{
$this->$method($libName, $file);
}
}
return true;
}
}

View File

@ -0,0 +1,9 @@
<?php
interface LtCacheAdapter
{
public function connect($hostConf);
public function add($key, $value, $ttl = 0, $tableName, $connectionResource);
public function del($key, $tableName, $connectionResource);
public function get($key, $tableName, $connectionResource);
public function update($key, $value, $ttl = 0, $tableName, $connectionResource);
}

View File

@ -0,0 +1,40 @@
<?php
class LtCacheAdapterApc implements LtCacheAdapter
{
public function connect($hostConf)
{
return true;
}
public function add($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return apc_add($this->getRealKey($tableName, $key), $value, $ttl);
}
public function del($key, $tableName, $connectionResource)
{
return apc_delete($this->getRealKey($tableName, $key));
}
public function get($key, $tableName, $connectionResource)
{
return apc_fetch($this->getRealKey($tableName, $key));
}
public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
if ($this->del($key, $tableName, $connectionResource))
{
return $this->add($key, $value, $ttl, $tableName, $connectionResource);
}
else
{
return false;
}
}
protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
}

View File

@ -0,0 +1,49 @@
<?php
class LtCacheAdapterEAccelerator implements LtCacheAdapter
{
public function connect($hostConf)
{
return true;
}
public function add($key, $value, $ttl=0, $tableName, $connectionResource)
{
$value = serialize($value); //eAccelerator doesn't serialize object
return eaccelerator_put($this->getRealKey($tableName, $key), $value, $ttl);
}
public function del($key, $tableName, $connectionResource)
{
return eaccelerator_rm($this->getRealKey($tableName, $key));
}
public function get($key, $tableName, $connectionResource)
{
$value = eaccelerator_get($this->getRealKey($tableName, $key));
if (!empty($value))
{
return unserialize($value);
}
else
{
return false;
}
}
public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
if ($this->del($key, $tableName, $connectionResource))
{
return $this->add($key, $value, $ttl, $tableName, $connectionResource);
}
else
{
return false;
}
}
protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
}

View File

@ -0,0 +1,68 @@
<?php
class LtCacheAdapterFile implements LtCacheAdapter
{
public function connect($hostConf)
{
$fileStore = new LtStoreFile;
$fileStore->prefix = 'LtCache-file';
$fileStore->useSerialize = true;
$fileStore->init();
return $fileStore;
}
public function add($key, $value, $ttl = 0, $tableName, $connectionResource)
{
if (0 != $ttl)
{
$ttl += time();
}
if (true == $connectionResource->add($this->getRealKey($tableName, $key), array("ttl" => $ttl, "value" => $value)))
{
return true;
}
else
{
if ($this->get($key,$tableName,$connectionResource))
{
return false;
}
else
{
$this->del($key,$tableName,$connectionResource);
return $connectionResource->add($this->getRealKey($tableName, $key), array("ttl" => $ttl, "value" => $value));
}
}
}
public function del($key, $tableName, $connectionResource)
{
return $connectionResource->del($this->getRealKey($tableName, $key));
}
public function get($key, $tableName, $connectionResource)
{
$cachedArray = $connectionResource->get($this->getRealKey($tableName, $key));
if (is_array($cachedArray) && (0 == $cachedArray["ttl"] || $cachedArray["ttl"] > time()))
{
return $cachedArray["value"];
}
else
{
return false;
}
}
public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
if (0 != $ttl)
{
$ttl += time();
}
return $connectionResource->update($this->getRealKey($tableName, $key), array("ttl" => $ttl, "value" => $value));
}
protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
}

View File

@ -0,0 +1,33 @@
<?php
class LtCacheAdapterMemcache implements LtCacheAdapter
{
public function connect($hostConf)
{
return memcache_connect($hostConf["host"], $hostConf["port"]);
}
public function add($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return $connectionResource->add($this->getRealKey($tableName, $key), $value, false, $ttl);
}
public function del($key, $tableName, $connectionResource)
{
return $connectionResource->delete($this->getRealKey($tableName, $key), 0);
}
public function get($key, $tableName, $connectionResource)
{
return $connectionResource->get($this->getRealKey($tableName, $key));
}
public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return $connectionResource->replace($this->getRealKey($tableName, $key), $value, false, $ttl);
}
protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
}

View File

@ -0,0 +1,35 @@
<?php
class LtCacheAdapterMemcached implements LtCacheAdapter
{
public function connect($hostConf)
{
$connectionResource = new Memcached();
$connectionResource->addServer($hostConf["host"], $hostConf["port"]);
return $connectionResource;
}
public function add($key, $value, $ttl=0, $tableName, $connectionResource)
{
return $connectionResource->add($this->getRealKey($tableName, $key), $value, $ttl);
}
public function del($key, $tableName, $connectionResource)
{
return $connectionResource->delete($this->getRealKey($tableName, $key));
}
public function get($key, $tableName, $connectionResource)
{
return $connectionResource->get($this->getRealKey($tableName, $key));
}
public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return $connectionResource->replace($this->getRealKey($tableName, $key), $value, $ttl);
}
protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
}

View File

@ -0,0 +1,55 @@
<?php
class LtCacheAdapterPhps implements LtCacheAdapter
{
public function connect($hostConf)
{
$fileStore = new LtStoreFile;
if (isset($hostConf['host']) && is_string($hostConf['host']))
{
$fileStore->cacheFileRoot = $hostConf['host'];
$fileStore->prefix = 'Ltcache-phps-';
$fileStore->init();
return $fileStore;
}
else
{
trigger_error("Must set [host]");
return false;
}
}
public function add($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return $connectionResource->add($this->getRealKey($tableName, $key), $this->valueToString($value), $ttl);
}
public function del($key, $tableName, $connectionResource)
{
return $connectionResource->del($this->getRealKey($tableName, $key));
}
public function get($key, $tableName, $connectionResource)
{
return $this->stringToValue($connectionResource->get($this->getRealKey($tableName, $key)));
}
public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return $connectionResource->update($this->getRealKey($tableName, $key), $this->valueToString($value), $ttl);
}
protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
protected function valueToString($value)
{
return serialize($value);
}
protected function stringToValue($str)
{
return unserialize($str);
}
}

View File

@ -0,0 +1,43 @@
<?php
class LtCacheAdapterXcache implements LtCacheAdapter
{
public function connect($hostConf)
{
return true;
}
public function add($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return xcache_set($this->getRealKey($tableName, $key), $value, $ttl);
}
public function del($key, $tableName, $connectionResource)
{
return xcache_unset($this->getRealKey($tableName, $key));
}
public function get($key, $tableName, $connectionResource)
{
$key = $this->getRealKey($tableName, $key);
if (xcache_isset($key))
{
return xcache_get($key);
}
return false;
}
public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
$key = $this->getRealKey($tableName, $key);
if (xcache_isset($key))
{
return xcache_set($key, $value, $ttl);
}
return false;
}
protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
}

View File

@ -0,0 +1,76 @@
<?php
class LtCache
{
public $configHandle;
public $group;
public $node;
protected $ch;
public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}
public function init()
{
$this->ch = new LtCacheHandle;
$this->ch->configHandle = $this->configHandle;
$this->ch->init();
$this->ch->group = $this->getGroup();
$this->ch->node = $this->getNode();
}
public function getTDG($tableName)
{
$tdg = new LtCacheTableDataGateway;
$tdg->tableName = $tableName;
$tdg->ch = $this->ch;
return $tdg;
}
public function changeNode($node)
{
$this->node = $node;
$this->dbh->node = $node;
}
protected function getGroup()
{
if ($this->group)
{
return $this->group;
}
$servers = $this->configHandle->get("cache.servers");
if (1 == count($servers))
{
return key($servers);
}
return false;
}
protected function getNode()
{
if ($this->node)
{
return $this->node;
}
$servers = $this->configHandle->get("cache.servers");
if (1 == count($servers[$this->getGroup()]))
{
return key($servers[$this->getGroup()]);
}
return false;
}
}

View File

@ -0,0 +1,14 @@
<?php
class LtCacheAdapterFactory
{
public function getConnectionAdapter($adapter)
{
$adapterClassName = "LtCacheAdapter" . ucfirst($adapter);
if(!class_exists($adapterClassName))
{
trigger_error("Invalid adapter: $adapter");
return null;
}
return new $adapterClassName;
}
}

View File

@ -0,0 +1,49 @@
<?php
class LtCacheConfigBuilder
{
protected $servers = array();
protected $defaultConfig = array(
"adapter" => "phps", //apc,xcach,ea; file, phps; memcached
//"prefix" => ""
//"host" => "localhost", //some ip, hostname
//"port" => 3306,
);
public function addSingleHost($hostConfig)
{
$this->addHost("group_0", "node_0", "master", $hostConfig);
}
public function addHost($groupId, $nodeId = "node_0", $role = "master", $hostConfig)
{
if (isset($this->servers[$groupId][$nodeId][$role]))
{//以相同role的第一个host为默认配置
$ref = $this->servers[$groupId][$nodeId][$role][0];
}
else if ("slave" == $role && isset($this->servers[$groupId][$nodeId]["master"]))
{//slave host以master的第一个host为默认配置
$ref = $this->servers[$groupId][$nodeId]["master"][0];
}
else if (isset($this->servers[$groupId]) && count($this->servers[$groupId]))
{//以本group第一个node的master第一个host为默认配置
$refNode = key($this->servers[$groupId]);
$ref = $this->servers[$groupId][$refNode]["master"][0];
}
else
{
if (!isset($hostConfig["adapter"]))
{
trigger_error("No db adapter specified");
}
$ref = $this->defaultConfig;
}
$conf = array_merge($ref, $hostConfig);
$this->servers[$groupId][$nodeId][$role][] = $conf;
}
public function getServers()
{
return $this->servers;
}
}

View File

@ -0,0 +1,52 @@
<?php
class LtCacheConnectionManager
{
public $configHandle;
protected $connectionAdapter;
public function getConnection($group, $node, $role)
{
if ($connection = $this->getNewConnection($group, $node, $role))
{
return array(
"connectionAdapter" => $this->connectionAdapter,
"connectionResource" => $connection
);
}
else
{
trigger_error("no cache server can be connected");
return false;
}
}
protected function getNewConnection($group, $node, $role)
{
$servers = $this->configHandle->get("cache.servers");
$hostTotal = count($servers[$group][$node][$role]);
$hostIndexArray = array_keys($servers[$group][$node][$role]);
while ($hostTotal)
{
$hashNumber = substr(microtime(),7,1) % $hostTotal;
$hostConfig = $servers[$group][$node][$role][$hostIndexArray[$hashNumber]];
$cacheFactory = new LtCacheAdapterFactory;
$this->connectionAdapter = $cacheFactory->getConnectionAdapter($hostConfig["adapter"]);
if ($connection = $this->connectionAdapter->connect($hostConfig))
{
return $connection;
}
else
{
//trigger_error('connection fail', E_USER_WARNING);
//delete the unavailable server
for ($i = $hashNumber; $i < $hostTotal - 1; $i ++)
{
$hostIndexArray[$i] = $hostIndexArray[$i+1];
}
unset($hostIndexArray[$hostTotal-1]);
$hostTotal --;
}//end else
}//end while
return false;
}
}

View File

@ -0,0 +1,52 @@
<?php
class LtCacheHandle
{
public $configHandle;
public $group;
public $node;
public $role = "master";
public $connectionManager;
public $connectionResource;
protected $connectionAdapter;
public function __construct()
{
}
public function init()
{
$this->connectionManager = new LtCacheConnectionManager;
$this->connectionManager->configHandle =$this->configHandle;
}
public function add($key, $value, $ttl = 0, $tableName)
{
$this->initConnection();
return $this->connectionAdapter->add($key, $value, $ttl, $tableName, $this->connectionResource);
}
public function del($key, $tableName)
{
$this->initConnection();
return $this->connectionAdapter->del($key, $tableName, $this->connectionResource);
}
public function get($key, $tableName)
{
$this->initConnection();
return $this->connectionAdapter->get($key, $tableName, $this->connectionResource);
}
public function update($key, $value, $ttl = 0, $tableName)
{
$this->initConnection();
return $this->connectionAdapter->update($key, $value, $ttl, $tableName, $this->connectionResource);
}
protected function initConnection()
{
$connectionInfo = $this->connectionManager->getConnection($this->group, $this->node, $this->role);
$this->connectionAdapter = $connectionInfo["connectionAdapter"];
$this->connectionResource = $connectionInfo["connectionResource"];
}
}

View File

@ -0,0 +1,27 @@
<?php
class LtCacheTableDataGateway
{
public $tableName;
public $ch;
public function add($key, $value, $ttl = 0)
{
return $this->ch->add($key, $value, $ttl, $this->tableName);
}
public function del($key)
{
return $this->ch->del($key, $this->tableName);
}
public function get($key)
{
return $this->ch->get($key, $this->tableName);
}
public function update($key, $value, $ttl = 0)
{
return $this->ch->update($key, $value, $ttl, $this->tableName);
}
}

View File

@ -0,0 +1,91 @@
<?php
class LtCaptcha
{
public $configHandle;
public $storeHandle;
public $imageEngine;
public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}
public function init()
{
if (!is_object($this->storeHandle))
{
$this->storeHandle = new LtStoreFile;
$this->storeHandle->prefix = 'LtCaptcha-seed-';
$this->storeHandle->init();
}
}
public function getImageResource($seed)
{
if (empty($seed))
{
trigger_error("empty seed");
return false;
}
if (!is_object($this->imageEngine))
{
if ($imageEngine = $this->configHandle->get("captcha.image_engine"))
{
if (class_exists($imageEngine))
{
$this->imageEngine = new $imageEngine;
$this->imageEngine->conf = $this->configHandle->get("captcha.image_engine_conf");
}
else
{
trigger_error("captcha.image_engine : $imageEngine not exists");
}
}
else
{
trigger_error("empty captcha.image_engine");
return false;
}
}
$word = $this->generateRandCaptchaWord($seed);
$this->storeHandle->add($seed, $word);
return $this->imageEngine->drawImage($word);
}
public function verify($seed, $userInput)
{
if ($word = $this->storeHandle->get($seed))
{
$this->storeHandle->del($seed);
return $userInput === $word;
}
else
{
return false;
}
}
protected function generateRandCaptchaWord()
{
$allowChars = $this->configHandle->get("captcha.allow_chars");
$length = $this->configHandle->get("captcha.length");
$allowedSymbolsLength = strlen($allowChars) - 1;
$captchaWord = "";
for ($i = 0; $i < $length; $i ++)
{
$captchaWord .= $allowChars[mt_rand(0, $allowedSymbolsLength)];
}
return $captchaWord;
}
}

View File

@ -0,0 +1,197 @@
<?php
/**
* Lotus Captcha component is inspired by "cool-php-captcha" project
* http://code.google.com/p/cool-php-captcha
*/
class LtCaptchaImageEngine
{
public $conf;
protected $maxWordLength = 9;
/**
* * Background color in RGB-array
*/
protected $backgroundColor = array(255, 255, 255);
/**
* * Foreground colors in RGB-array
*/
protected $colors = array(
array(27, 78, 181), // blue
array(22, 163, 35), // green
array(214, 36, 7), // red
);
/**
* * Shadow color in RGB-array or null
*/
protected $shadowColor = null; //array(0, 0, 0);
/**
* Font configuration
*
* - font: TTF file
* - spacing: relative pixel space between character
* - minSize: min font size
* - maxSize: max font size
*/
protected $fonts = array('Antykwa' => array('spacing' => -3, 'minSize' => 27, 'maxSize' => 30, 'font' => 'AntykwaBold.ttf'),
'Candice' => array('spacing' => -1.5, 'minSize' => 28, 'maxSize' => 31, 'font' => 'Candice.ttf'),
'DingDong' => array('spacing' => -2, 'minSize' => 24, 'maxSize' => 30, 'font' => 'Ding-DongDaddyO.ttf'),
'Duality' => array('spacing' => -2, 'minSize' => 30, 'maxSize' => 38, 'font' => 'Duality.ttf'),
'Jura' => array('spacing' => -2, 'minSize' => 28, 'maxSize' => 32, 'font' => 'Jura.ttf'),
'StayPuft' => array('spacing' => -1.5, 'minSize' => 28, 'maxSize' => 32, 'font' => 'StayPuft.ttf'),
'Times' => array('spacing' => -2, 'minSize' => 28, 'maxSize' => 34, 'font' => 'TimesNewRomanBold.ttf'),
'VeraSans' => array('spacing' => -1, 'minSize' => 20, 'maxSize' => 28, 'font' => 'VeraSansBold.ttf'),
);
/**
* * Wave configuracion in X and Y axes
*/
protected $Yperiod = 12;
protected $Yamplitude = 14;
protected $Xperiod = 11;
protected $Xamplitude = 5;
/**
* * GD image
*/
protected $im;
public function drawImage($text)
{
/**
* * Initialization
*/
$this->ImageAllocate();
$fontcfg = $this->fonts[array_rand($this->fonts)];
$this->WriteText($text, $fontcfg);
/**
* * Transformations
*/
$this->WaveImage();
if ($this->conf['blur'] && function_exists('imagefilter'))
{
imagefilter($this->im, IMG_FILTER_GAUSSIAN_BLUR);
}
$this->ReduceImage();
return $this->im;
}
/**
* Creates the image resources
*/
protected function ImageAllocate()
{
// Cleanup
if (!empty($this->im))
{
imagedestroy($this->im);
}
$this->im = imagecreatetruecolor($this->conf['width'] * $this->conf['scale'], $this->conf['height'] * $this->conf['scale']);
// Background color
$this->GdBgColor = imagecolorallocate($this->im,
$this->backgroundColor[0],
$this->backgroundColor[1],
$this->backgroundColor[2]
);
imagefilledrectangle($this->im, 0, 0, $this->conf['width'] * $this->conf['scale'], $this->conf['height'] * $this->conf['scale'], $this->GdBgColor);
// Foreground color
$color = $this->colors[mt_rand(0, sizeof($this->colors)-1)];
$this->GdFgColor = imagecolorallocate($this->im, $color[0], $color[1], $color[2]);
// Shadow color
if (!empty($this->shadowColor) && is_array($this->shadowColor) && sizeof($this->shadowColor) >= 3)
{
$this->GdShadowColor = imagecolorallocate($this->im,
$this->shadowColor[0],
$this->shadowColor[1],
$this->shadowColor[2]
);
}
}
/**
* Text insertion
*/
protected function WriteText($text, $fontcfg = array())
{
if (empty($fontcfg))
{
// Select the font configuration
$fontcfg = $this->fonts[array_rand($this->fonts)];
}
// Full path of font file
$fontfile = dirname(__FILE__) . '/fonts/' . $fontcfg['font'];
/**
* * Increase font-size for shortest words: 9% for each glyp missing
*/
$lettersMissing = $this->maxWordLength - strlen($text);
$fontSizefactor = 1 + ($lettersMissing * 0.09);
// Text generation (char by char)
$x = 20 * $this->conf['scale'];
$y = round(($this->conf['height'] * 27 / 40) * $this->conf['scale']);
$length = strlen($text);
for ($i = 0; $i < $length; $i++)
{
$degree = rand($this->conf['max_rotation'] * -1, $this->conf['max_rotation']);
$fontsize = rand($fontcfg['minSize'], $fontcfg['maxSize']) * $this->conf['scale'] * $fontSizefactor;
$letter = substr($text, $i, 1);
if ($this->shadowColor)
{
$coords = imagettftext($this->im, $fontsize, $degree,
$x + $this->conf['scale'], $y + $this->conf['scale'],
$this->GdShadowColor, $fontfile, $letter);
}
$coords = imagettftext($this->im, $fontsize, $degree,
$x, $y,
$this->GdFgColor, $fontfile, $letter);
$x += ($coords[2] - $x) + ($fontcfg['spacing'] * $this->conf['scale']);
}
}
/**
* Wave filter
*/
protected function WaveImage()
{
// X-axis wave generation
$xp = $this->conf['scale'] * $this->Xperiod * rand(1, 3);
$k = rand(0, 100);
for ($i = 0; $i < ($this->conf['width'] * $this->conf['scale']); $i++)
{
imagecopy($this->im, $this->im,
$i-1, sin($k + $i / $xp) * ($this->conf['scale'] * $this->Xamplitude),
$i, 0, 1, $this->conf['height'] * $this->conf['scale']);
}
// Y-axis wave generation
$k = rand(0, 100);
$yp = $this->conf['scale'] * $this->Yperiod * rand(1, 2);
for ($i = 0; $i < ($this->conf['height'] * $this->conf['scale']); $i++)
{
imagecopy($this->im, $this->im,
sin($k + $i / $yp) * ($this->conf['scale'] * $this->Yamplitude), $i-1,
0, $i, $this->conf['width'] * $this->conf['scale'], 1);
}
}
/**
* Reduce the image to the final size
*/
protected function ReduceImage()
{
$imResampled = imagecreatetruecolor($this->conf['width'], $this->conf['height']);
imagecopyresampled($imResampled, $this->im,
0, 0, 0, 0,
$this->conf['width'], $this->conf['height'],
$this->conf['width'] * $this->conf['scale'], $this->conf['height'] * $this->conf['scale']
);
imagedestroy($this->im);
$this->im = $imResampled;
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,84 @@
<?php
class LtConfig
{
public $storeHandle;
protected $conf;
public function __construct()
{
if (!is_object($this->storeHandle))
{
$this->storeHandle = new LtStoreMemory;
}
}
public function init()
{
//don't removeme, I am the placeholder
}
public function get($key)
{
$storedConfig = $this->storeHandle->get($key);
if ($storedConfig instanceof LtConfigExpression)
{
$str = $storedConfig->__toString();
if ($storedConfig->autoRetrived)
{
eval("\$value=$str;");
return $value;
}
else
{
return $str;
}
}
else
{
return $storedConfig;
}
}
/**
* 警告
* 这里会包含两个用户定义的配置文件,为了不和配置文件里的变量名发生重名
* 本方法不定义和使用变量名
*/
public function loadConfigFile($configFile)
{
if (0 == $this->storeHandle->get(".config_total"))
{
if (null === $configFile || !is_file($configFile))
{
trigger_error("no config file specified or invalid config file");
}
$this->conf = include($configFile);
if (!is_array($this->conf))
{
trigger_error("config file do NOT return array: $configFile");
}
elseif (!empty($this->conf))
{
if (0 == $this->storeHandle->get(".config_total"))
{
$this->storeHandle->add(".config_total", 0);
}
$this->addConfig($this->conf);
}
}
}
public function addConfig($configArray)
{
foreach($configArray as $key => $value)
{
if (!$this->storeHandle->update($key, $value))
{
if ($this->storeHandle->add($key, $value))
{
$this->storeHandle->update(".config_total", $this->storeHandle->get(".config_total") + 1, 0);
}
}
}
}
}

View File

@ -0,0 +1,17 @@
<?php
class LtConfigExpression
{
private $_expression;
public $autoRetrived;
public function __construct($string, $autoRetrived = true)
{
$this->_expression = (string) $string;
$this->autoRetrived = $autoRetrived;
}
public function __toString()
{
return $this->_expression;
}
}

View File

@ -0,0 +1,136 @@
<?php
class LtCookie
{
public $configHandle;
private $secretKey;
public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}
public function init()
{
$this->secretKey = $this->configHandle->get("cookie.secret_key");
if(empty($this->secretKey))
{
trigger_error("cookie.secret_key empty");
}
}
/**
* Decrypt the encrypted cookie
*
* @param string $encryptedText
* @return string
*/
protected function decrypt($encryptedText)
{
$key = $this->secretKey;
$cryptText = base64_decode($encryptedText);
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($ivSize, MCRYPT_RAND);
$decryptText = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $cryptText, MCRYPT_MODE_ECB, $iv);
return trim($decryptText);
}
/**
* Encrypt the cookie
*
* @param string $plainText
* @return string
*/
protected function encrypt($plainText)
{
$key = $this->secretKey;
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($ivSize, MCRYPT_RAND);
$encryptText = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $plainText, MCRYPT_MODE_ECB, $iv);
return trim(base64_encode($encryptText));
}
/**
* Set cookie value to deleted with $name
*
* @param array $args
* @return boolean
*/
public function delCookie($name, $path = '/', $domain = null)
{
if (isset($_COOKIE[$name]))
{
if (is_array($_COOKIE[$name]))
{
foreach($_COOKIE[$name] as $k => $v)
{
setcookie($name . '[' . $k . ']', '', time() - 86400, $path, $domain);
}
}
else
{
setcookie($name, '', time() - 86400, $path, $domain);
}
}
}
/**
* Get cookie value with $name
*
* @param string $name
* @return mixed
*/
public function getCookie($name)
{
$ret = null;
if (isset($_COOKIE[$name]))
{
if (is_array($_COOKIE[$name]))
{
$ret = array();
foreach($_COOKIE[$name] as $k => $v)
{
$v = $this->decrypt($v);
$ret[$k] = $v;
}
}
else
{
$ret = $this->decrypt($_COOKIE[$name]);
}
}
return $ret;
}
/**
* Set cookie
*
* @param array $args
* @return boolean
*/
public function setCookie($name, $value = '', $expire = null, $path = '/', $domain = null, $secure = 0)
{
if (is_array($value))
{
foreach($value as $k => $v)
{
$v = $this->encrypt($v);
setcookie($name . '[' . $k . ']', $v, $expire, $path, $domain, $secure);
}
}
else
{
$value = $this->encrypt($value);
setcookie($name, $value, $expire, $path, $domain, $secure);
}
}
}

View File

@ -0,0 +1,12 @@
<?php
interface LtDbConnectionAdapter
{
/**
* @todo 兼容使用Unix Domain Socket方式连接数据库可以不指定port
*/
public function connect($connConf);
public function exec($sql, $connResource);
public function query($sql, $connResource);
public function lastInsertId($connResource);
public function escape($sql, $connResource);
}

View File

@ -0,0 +1,34 @@
<?php
class LtDbConnectionAdapterMysql implements LtDbConnectionAdapter
{
public function connect($connConf)
{
return mysql_connect($connConf["host"] . ":" . $connConf["port"], $connConf["username"], $connConf["password"]);
}
public function exec($sql, $connResource)
{
return mysql_query($sql, $connResource) ? mysql_affected_rows($connResource) : false;
}
public function query($sql, $connResource)
{
$result = mysql_query($sql, $connResource);
$rows = array();
while($row = mysql_fetch_assoc($result))
{
$rows[] = $row;
}
return $rows;
}
public function lastInsertId($connResource)
{
return mysql_insert_id($connResource);
}
public function escape($sql, $connResource)
{
return mysql_real_escape_string($sql, $connResource);
}
}

View File

@ -0,0 +1,35 @@
<?php
class LtDbConnectionAdapterMysqli implements LtDbConnectionAdapter
{
public function connect($connConf)
{
return new mysqli($connConf["host"], $connConf["username"], $connConf["password"], $connConf["dbname"], $connConf["port"]);
}
public function exec($sql, $connResource)
{
$connResource->query($sql);
return $connResource->affected_rows;
}
public function query($sql, $connResource)
{
$rows = array();
$result = $connResource->query($sql);
while($row = $result->fetch_assoc())
{
$rows[] = $row;
}
return $rows;
}
public function lastInsertId($connResource)
{
return $connResource->insert_id;
}
public function escape($sql, $connResource)
{
return mysqli_real_escape_string($connResource, $sql);
}
}

View File

@ -0,0 +1,65 @@
<?php
class LtDbConnectionAdapterPdo implements LtDbConnectionAdapter
{
public function connect($connConf)
{
// $option = array(PDO::ATTR_PERSISTENT => true);
if (isset($connConf['pconnect']) && true == $connConf['pconnect'])
{
$option[PDO::ATTR_PERSISTENT] = true;
}
else
{
$option[PDO::ATTR_PERSISTENT] = false;
}
switch ($connConf['adapter'])
{
case "pdo_mysql":
$dsn = "mysql:host={$connConf['host']};dbname={$connConf['dbname']}";
break;
case "pdo_sqlite":
$connConf["host"] = rtrim($connConf["host"], '\\/') . DIRECTORY_SEPARATOR;
if (!is_dir($connConf["host"]))
{
if (!@mkdir($connConf["host"], 0777, true))
{
trigger_error("Can not create {$connConf['host']}");
}
}
$dsn = "{$connConf['sqlite_version']}:{$connConf['host']}{$connConf['dbname']}";
break;
case "pdo_pgsql":
$dsn = "pgsql:host={$connConf['host']} port={$connConf['port']} dbname={$connConf['dbname']} user={$connConf['username']} password={$connConf['password']}";
break;
case "odbc":
$dsn = "odbc:" . $connConf["host"];
break;
}
return new PDO($dsn, $connConf['username'], $connConf['password'], $option);
}
public function exec($sql, $connResource)
{
return $connResource->exec($sql);
}
public function query($sql, $connResource)
{
return $connResource->query($sql)->fetchAll(PDO::FETCH_ASSOC);
}
/**
*
* @todo pgsql support
*/
public function lastInsertId($connResource)
{
return $connResource->lastInsertId();
}
public function escape($sql, $connResource)
{
// quote返回值带最前面和最后面的单引号, 这里去掉, DbHandler中加
return trim($connResource->quote($sql), "'");
}
}

View File

@ -0,0 +1,46 @@
<?php
class LtDbConnectionAdapterPgsql implements LtDbConnectionAdapter
{
public function connect($connConf)
{
if (isset($connConf['pconnect']) && true == $connConf['pconnect'])
{
$func = 'pg_pconnect';
}
else
{
$func = 'pg_connect';
}
return $func("host={$connConf['host']} port={$connConf['port']} user={$connConf['username']} password={$connConf['password']}");
}
public function exec($sql, $connResource)
{
$result = pg_query($connResource, $sql);
return pg_affected_rows($result);
}
public function query($sql, $connResource)
{
$result = pg_query($connResource, $sql);
return pg_fetch_all($result);
}
// SELECT CURRVAL(
// pg_get_serial_sequence('my_tbl_name','id_col_name'));"
// ------------------------------------------------------
// CREATE FUNCTION last_insert_id() RETURNS bigint AS $$
// SELECT lastval();
// $$ LANGUAGE SQL VOLATILE;
public function lastInsertId($connResource)
{
$result = pg_query($connResource, "SELECT lastval()");
$row = pg_fetch_array($result, 0, PGSQL_NUM);
return $row[0];
}
public function escape($sql, $connResource)
{
return pg_escape_string($sql);
}
}

View File

@ -0,0 +1,72 @@
<?php
/**
* Sqlite 预定义了类 SQLiteDatabase 本实现没有使用。
* 这里使用的全部是过程函数。
* 无论是函数还是类本实现只支持sqlite的2.x系列版本。
* php5.3新增扩展sqlite3用来支持3.x版本。
* PDO则同时支持2.x和3.x版本。
*/
class LtDbConnectionAdapterSqlite implements LtDbConnectionAdapter
{
public function connect($connConf)
{
if (isset($connConf['pconnect']) && true == $connConf['pconnect'])
{
$func = 'sqlite_popen';
}
else
{
$func = 'sqlite_open';
}
$connConf["host"] = rtrim($connConf["host"], '\\/') . DIRECTORY_SEPARATOR;
if(!is_dir($connConf["host"]))
{
if(!@mkdir($connConf["host"], 0777, true))
{
trigger_error("Can not create {$connConf['host']}");
}
}
$error = '';
$connResource = $func($connConf["host"] . $connConf["dbname"], 0666, $error);
if (!$connResource)
{
trigger_error($error, E_USER_ERROR);
}
else
{
return $connResource;
}
}
public function exec($sql, $connResource)
{
if(empty($sql))
{
return 0;
}
sqlite_exec($connResource, $sql);
// echo '<pre>';
// print_r(debug_backtrace());
// debug_print_backtrace();
// echo '</pre>';
// delete from table 结果为0原因未知。
// 使用 delete from table where 1 能返回正确结果
return sqlite_changes($connResource);
}
public function query($sql, $connResource)
{
$result = sqlite_query($connResource, $sql, SQLITE_ASSOC);
return sqlite_fetch_all($result, SQLITE_ASSOC);
}
public function lastInsertId($connResource)
{
return sqlite_last_insert_rowid($connResource);
}
public function escape($sql, $connResource)
{
return sqlite_escape_string($sql);
}
}

View File

@ -0,0 +1,31 @@
<?php
interface LtDbSqlAdapter
{
/**
* Return SQL statements
*/
public function setCharset($charset);
public function setSchema($schema);
public function showSchemas($database);
public function showTables($schema);
public function showFields($table);
public function beginTransaction();
public function commit();
public function rollBack();
public function limit($limit, $offset);
/**
* Retrive recordset
*/
public function getSchemas($queryResult);
public function getTables($queryResult);
public function getFields($queryResult);
/**
* Parse SQL
*/
public function detectQueryType($sql);
}

View File

@ -0,0 +1,90 @@
<?php
class LtDbSqlAdapterMysql implements LtDbSqlAdapter
{
public function setCharset($charset)
{
return "SET NAMES " . str_replace('-', '', $charset);
}
public function setSchema($schema)
{
return "USE $schema";
}
public function showSchemas($database)
{
return "SHOW DATABASES";
}
public function showTables($schema)
{
return "SHOW TABLES";
}
public function showFields($table)
{
return "DESCRIBE $table";
}
public function beginTransaction()
{
return "START TRANSACTION";
}
public function commit()
{
return "COMMIT";
}
public function rollBack()
{
return "ROLLBACK";
}
public function limit($limit, $offset)
{
return " LIMIT $limit OFFSET $offset";
}
public function getSchemas($queryResult)
{
}
public function getTables($queryResult)
{
}
public function getFields($queryResult)
{
foreach ($queryResult as $key => $value)
{
$fields[$value['Field']]['name'] = $value['Field'];
$fields[$value['Field']]['type'] = $value['Type'];
/*
* not null is NO or empty, null is YES
*/
$fields[$value['Field']]['notnull'] = (bool) ($value['Null'] != 'YES');
$fields[$value['Field']]['default'] = $value['Default'];
$fields[$value['Field']]['primary'] = (strtolower($value['Key']) == 'pri');
}
return $fields;
}
public function detectQueryType($sql)
{
if (preg_match("/^\s*SELECT|^\s*EXPLAIN|^\s*SHOW|^\s*DESCRIBE/i", $sql))
{
$ret = 'SELECT';
}
else if (preg_match("/^\s*INSERT/i", $sql))
{
$ret = 'INSERT';
}
else if (preg_match("/^\s*UPDATE|^\s*DELETE|^\s*REPLACE/i", $sql))
{
$ret = 'CHANGE_ROWS';
}
else if (preg_match("/^\s*USE|^\s*SET/i", $sql))
{
$ret = 'SET_SESSION_VAR';
}
else
{
$ret = 'OTHER';
}
return $ret;
}
}

View File

@ -0,0 +1,81 @@
<?php
class LtDbSqlAdapterPgsql implements LtDbSqlAdapter
{
public function setCharset($charset)
{
return "SET client_encoding TO '$charset'";
}
public function setSchema($schema)
{
return "SET search_path TO $schema";
}
public function beginTransaction()
{
return "";
}
public function commit()
{
return "";
}
public function rollBack()
{
return "";
}
public function showSchemas($database)
{
}
public function showTables($schema)
{
return "SELECT case when n.nspname='public' then c.relname else n.nspname||'.'||c.relname end as relname
FROM pg_class c join pg_namespace n on (c.relnamespace=n.oid)
WHERE c.relkind = 'r'
AND n.nspname NOT IN ('information_schema','pg_catalog')
AND n.nspname NOT LIKE 'pg_temp%'
AND n.nspname NOT LIKE 'pg_toast%'
ORDER BY relname";
}
public function showFields($table)
{
return "SELECT a.attnum, a.attname AS field, t.typname AS type,
format_type(a.atttypid, a.atttypmod) AS complete_type,
a.attnotnull AS isnotnull,
( SELECT 't' FROM pg_index
WHERE c.oid = pg_index.indrelid
AND pg_index.indkey[0] = a.attnum
AND pg_index.indisprimary = 't') AS pri,
(SELECT pg_attrdef.adsrc FROM pg_attrdef
WHERE c.oid = pg_attrdef.adrelid
AND pg_attrdef.adnum=a.attnum) AS default
FROM pg_attribute a, pg_class c, pg_type t
WHERE c.relname = '$table'
AND a.attnum > 0
AND a.attrelid = c.oid
AND a.atttypid = t.oid
ORDER BY a.attnum";
}
public function limit($limit, $offset)
{
return " LIMIT $limit OFFSET $offset";
}
public function getSchemas($queryResult)
{
}
public function getTables($queryResult)
{
}
public function getFields($queryResult)
{
}
public function detectQueryType($sql)
{
}
}

View File

@ -0,0 +1,120 @@
<?php
class LtDbSqlAdapterSqlite implements LtDbSqlAdapter
{
public function setCharset($charset)
{
// return 'PRAGMA encoding = "' . $charset . '"';
return '';
}
public function setSchema($schema)
{
return '';
}
public function beginTransaction()
{
return 'BEGIN TRANSACTION';
}
public function commit()
{
return 'COMMIT TRANSACTION';
}
public function rollBack()
{
return 'ROLLBACK TRANSACTION';
}
public function showSchemas($database)
{
//return "SHOW DATABASES";
return '';
}
public function showTables($schema)
{
// 临时表及其索引不在 SQLITE_MASTER 表中而在 SQLITE_TEMP_MASTER 中出现
return "SELECT name FROM sqlite_master WHERE type='table' UNION ALL SELECT name FROM sqlite_temp_master WHERE type='table' ORDER BY name";
}
public function showFields($table)
{
return "PRAGMA table_info('" . $table . "')";
}
public function limit($limit, $offset)
{
return " LIMIT $limit OFFSET $offset";
}
public function getSchemas($queryResult)
{
}
public function getTables($queryResult)
{
return $queryResult;
}
public function getFields($queryResult)
{
$fields = array();
foreach ($queryResult as $key => $value)
{
// 字段名
$fields[$value['name']]['name'] = $value['name'];
// 字段类型
$fulltype = $value['type'];
$size = null;
$precision = null;
$scale = null;
if (preg_match('/^([^\(]+)\(\s*(\d+)\s*,\s*(\d+)\s*\)$/',$fulltype, $matches))
{
$type = $matches[1];
$precision = $matches[2];
$scale = $matches[3]; // aka precision
}
elseif (preg_match('/^([^\(]+)\(\s*(\d+)\s*\)$/',$fulltype, $matches))
{
$type = $matches[1];
$size = $matches[2];
}
else
{
$type = $fulltype;
}
$fields[$value['name']]['type'] = $type;
/**
* not null is 99, null is 0
*/
$fields[$value['name']]['notnull'] = (bool) ($value['notnull'] != 0);
$fields[$value['name']]['default'] = $value['dflt_value'];
$fields[$value['name']]['primary'] = (bool) ($value['pk'] == 1 && strtoupper($fulltype) == 'INTEGER');
}
return $fields;
}
public function detectQueryType($sql)
{
if (preg_match("/^\s*SELECT|^\s*PRAGMA/i", $sql))
{
$ret = 'SELECT';
}
else if (preg_match("/^\s*INSERT/i", $sql))
{
$ret = 'INSERT';
}
else if (preg_match("/^\s*UPDATE|^\s*DELETE|^\s*REPLACE/i", $sql))
{
$ret = 'CHANGE_ROWS';
}
else if (preg_match("/^\s*USE|^\s*SET/i", $sql))
{
$ret = 'SET_SESSION_VAR';
}
else
{
$ret = 'OTHER';
}
return $ret;
}
}

View File

@ -0,0 +1,91 @@
<?php
class LtDb
{
public $configHandle;
public $group;
public $node;
protected $dbh;
public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}
public function init()
{
$this->dbh = new LtDbHandle;
$this->dbh->configHandle = $this->configHandle;
$this->dbh->group = $this->getGroup();
$this->dbh->node = $this->getNode();
$this->dbh->init();
}
public function getDbHandle()
{
return $this->dbh;
}
public function getTDG($tableName)
{
$tg = new LtDbTableDataGateway;
$tg->configHandle = $this->configHandle;
$tg->tableName = $tableName;
$tg->createdColumn = 'created';
$tg->modifiedColumn = 'modified';
$tg->dbh = $this->dbh;
return $tg;
}
public function getSqlMapClient()
{
$smc = new LtDbSqlMapClient;
$smc->configHandle = $this->configHandle;
$smc->dbh = $this->dbh;
return $smc;
}
public function changeNode($node)
{
$this->node = $node;
$this->dbh->node = $node;
}
protected function getGroup()
{
if ($this->group)
{
return $this->group;
}
$servers = $this->configHandle->get("db.servers");
if (1 == count($servers))
{
return key($servers);
}
return false;
}
protected function getNode()
{
if ($this->node)
{
return $this->node;
}
$servers = $this->configHandle->get("db.servers");
if (1 == count($servers[$this->getGroup()]))
{
return key($servers[$this->getGroup()]);
}
return false;
}
}

View File

@ -0,0 +1,15 @@
<?php
class LtDbAdapterFactory
{
public function getConnectionAdapter($connectionAdapterType)
{
$LtDbConnectionAdapter = "LtDbConnectionAdapter" . ucfirst($connectionAdapterType);
return new $LtDbConnectionAdapter;
}
public function getSqlAdapter($sqlAdapterType)
{
$LtDbSqlAdapter = "LtDbSqlAdapter" . ucfirst($sqlAdapterType);
return new $LtDbSqlAdapter;
}
}

View File

@ -0,0 +1,122 @@
<?php
class LtDbConfigBuilder
{
protected $servers = array();
protected $tables = array();
protected $adapters = array(
//"php_ext" => array("connection_adapter" => "", "sql_adapter" => "")
"pgsql" => array("connection_adapter" => "pgsql", "sql_adapter" => "pgsql"),
"pdo_pgsql" => array("connection_adapter" => "pdo", "sql_adapter" => "pgsql"),
"oci" => array("connection_adapter" => "oci", "sql_adapter" => "oracle"),
"pdo_oci" => array("connection_adapter" => "pdo", "sql_adapter" => "oracle"),
"mssql" => array("connection_adapter" => "mssql", "sql_adapter" => "mssql"),
"pdo_dblib" => array("connection_adapter" => "pdo", "sql_adapter" => "mssql"),
"mysql" => array("connection_adapter" => "mysql", "sql_adapter" => "mysql"),
"mysqli" => array("connection_adapter" => "mysqli", "sql_adapter" => "mysql"),
"pdo_mysql" => array("connection_adapter" => "pdo", "sql_adapter" => "mysql"),
"sqlite" => array("connection_adapter" => "sqlite", "sql_adapter" => "sqlite"),
"sqlite3" => array("connection_adapter" => "sqlite3", "sql_adapter" => "sqlite"),
"pdo_sqlite" => array("connection_adapter" => "pdo", "sql_adapter" => "sqlite"),
);
protected $defaultConfig = array(
"host" => "localhost", //some ip, hostname
//"port" => 3306,
"username" => "root",
"password" => null,
//"adapter" => "mysql", //mysql,mysqli,pdo_mysql,sqlite,pdo_sqlite
"charset" => "UTF-8",
"pconnect" => true, //true,false
"connection_ttl" => 3600, //any seconds
"dbname" => null, //default dbname
"schema" => null, //default schema
"connection_adapter" => null,
"sql_adapter" => null,
);
protected $defaultAdapterConfigs = array(
"pgsql" => array(
"port" => 5432,
),
"oracle" => array(
"port" => 1521,
),
"mssql" => array(
"port" => 1433,
),
"mysql" => array(
"port" => 3306,
"pconnect" => false,
"connection_ttl" => 30,
),
);
public function addSingleHost($hostConfig)
{
$this->addHost("group_0", "node_0", "master", $hostConfig);
}
public function addHost($groupId, $nodeId = "node_0", $role = "master", $hostConfig)
{
if (isset($this->servers[$groupId][$nodeId][$role]))
{//以相同role的第一个host为默认配置
$ref = $this->servers[$groupId][$nodeId][$role][0];
}
else if ("slave" == $role && isset($this->servers[$groupId][$nodeId]["master"]))
{//slave host以master的第一个host为默认配置
$ref = $this->servers[$groupId][$nodeId]["master"][0];
}
else if (isset($this->servers[$groupId]) && count($this->servers[$groupId]))
{//以本group第一个node的master第一个host为默认配置
$refNode = key($this->servers[$groupId]);
$ref = $this->servers[$groupId][$refNode]["master"][0];
}
else
{
if (!isset($hostConfig["adapter"]))
{
trigger_error("No db adapter specified");
}
$ref = $this->defaultConfig;
if (isset($this->defaultAdapterConfigs[$this->adapters[$hostConfig["adapter"]]["sql_adapter"]]))
{
$ref = array_merge($ref, $this->defaultAdapterConfigs[$this->adapters[$hostConfig["adapter"]]["sql_adapter"]]);
}
}
$conf = array_merge($ref, $hostConfig);
$conf = array_merge($conf, $this->adapters[$conf["adapter"]]);
$conf = $this->convertDbnameToSchema($conf);
$this->servers[$groupId][$nodeId][$role][] = $conf;
}
public function getServers()
{
return $this->servers;
}
public function getTables()
{
return $this->tables;
}
public function buildTablesConfig()
{
}
/**
* Convert dbname to schema for: FrontBase, MySQL, mSQL, MS SQL Server, MaxDB, Sybase
* See: http://www.php.net/manual-lookup.php?pattern=_select_db
*/
protected function convertDbnameToSchema($conf)
{
if (preg_match("/fbsql|mysql|msql|mssql|maxdb|sybase/i", $conf["sql_adapter"]) && isset($conf["dbname"]))
{
$conf["schema"] = $conf["dbname"];
$conf["dbname"] = null;
}
return $conf;
}
}

View File

@ -0,0 +1,117 @@
<?php
class LtDbConnectionManager
{
/**
* Connection management
* array(
* "connection" => connection resource id,
* "expire_time" => expire time,
* "schema" => default schema name,
* "charset" => char set / encoding
* )
*/
static public $connectionPool;
public $configHandle;
protected $connectionAdapter;
protected $sqlAdapter;
private $servers;
public function getConnection($group, $node, $role = "master")
{
if(empty($this->servers))
{
$this->servers = $this->configHandle->get("db.servers");
}
if (($connection = $this->getNewConnection($group, $node, $role)) ||($connection = $this->getCachedConnection($group, $node, $role)))
{
return array(
"connectionAdapter" => $this->connectionAdapter,
"connectionResource" => $connection
);
}
else
{
trigger_error("db server can not be connected: group=$group, node=$node, role=$role", E_USER_ERROR);
return false;
}
}
protected function getConnectionKey($connConf)
{
return $connConf['adapter'] . $connConf['host'] . $connConf['port'] . $connConf['username'] . $connConf['dbname'];
}
protected function saveConnection($connConf, $connection, $ttl)
{
$connectionInfo = array(
"connection" => $connection,
"expire_time" => time() + $ttl,
"schema" => $connConf["schema"],
"charset" => $connConf["charset"],
);
self::$connectionPool[$this->getConnectionKey($connConf)] = $connectionInfo;
}
protected function getCachedConnection($group, $node, $role)
{
foreach($this->servers[$group][$node][$role] as $hostConfig)
{
$key = $this->getConnectionKey($hostConfig);
if(isset(self::$connectionPool[$key]) && time() < self::$connectionPool[$key]['expire_time'])
{//cached connection resource FOUND
$connectionInfo = self::$connectionPool[$key];
if ($connectionInfo["schema"] != $hostConfig["schema"] || $connectionInfo["charset"] != $hostConfig["charset"])
{//检查当前schema和charset与用户要操作的目标不一致
$hostConfig = $this->servers[$group][$node][$role][$hostIndexArray[$hashNumber]];
$dbFactory = new LtDbAdapterFactory;
$this->connectionAdapter = $dbFactory->getConnectionAdapter($hostConfig["connection_adapter"]);
$this->sqlAdapter = $dbFactory->getSqlAdapter($hostConfig["sql_adapter"]);
if ($connectionInfo["schema"] != $hostConfig["schema"])
{
$this->connectionAdapter->exec($this->sqlAdapter->setSchema($hostConfig["schema"]), $connectionInfo["connection"]);
}
if ($connectionInfo["charset"] != $hostConfig["charset"])
{
$this->connectionAdapter->exec($this->sqlAdapter->setCharset($hostConfig["charset"]), $connectionInfo["connection"]);
}
$this->saveConnection($hostConfig, $connectionInfo["connection"], $hostConfig["connection_ttl"]);
}
return $connectionInfo["connection"];
}
}
return false;
}
protected function getNewConnection($group, $node, $role)
{
$hostTotal = count($this->servers[$group][$node][$role]);
$hostIndexArray = array_keys($this->servers[$group][$node][$role]);
while ($hostTotal)
{
$hashNumber = substr(microtime(),7,1) % $hostTotal;
$hostConfig = $this->servers[$group][$node][$role][$hostIndexArray[$hashNumber]];
$dbFactory = new LtDbAdapterFactory;
$this->connectionAdapter = $dbFactory->getConnectionAdapter($hostConfig["connection_adapter"]);
$this->sqlAdapter = $dbFactory->getSqlAdapter($hostConfig["sql_adapter"]);
if ($connection = $this->connectionAdapter->connect($hostConfig))
{
$this->connectionAdapter->exec($this->sqlAdapter->setSchema($hostConfig["schema"]), $connection);
$this->connectionAdapter->exec($this->sqlAdapter->setCharset($hostConfig["charset"]), $connection);
$this->saveConnection($hostConfig, $connection, $hostConfig["connection_ttl"]);
return $connection;
}
else
{
//trigger_error('connection fail', E_USER_WARNING);
//delete the unavailable server
for ($i = $hashNumber; $i < $hostTotal - 1; $i ++)
{
$hostIndexArray[$i] = $hostIndexArray[$i+1];
}
unset($hostIndexArray[$hostTotal-1]);
$hostTotal --;
}//end else
}//end while
return false;
}
}

View File

@ -0,0 +1,200 @@
<?php
class LtDbHandle
{
public $configHandle;
public $group;
public $node;
public $role = "master";
public $connectionAdapter;
public $connectionResource;
public $sqlAdapter;
protected $connectionManager;
private $servers;
public function __construct()
{
}
public function init()
{
if(empty($this->servers))
{
$this->servers = $this->configHandle->get("db.servers");
}
$this->connectionManager = new LtDbConnectionManager;
$this->connectionManager->configHandle = $this->configHandle;
$this->sqlAdapter = $this->getCurrentSqlAdapter();
$connectionInfo = $this->connectionManager->getConnection($this->group, $this->node, $this->role);
$this->connectionAdapter = $connectionInfo["connectionAdapter"];
$this->connectionResource = $connectionInfo["connectionResource"];
}
/**
* Trancaction methods
*/
public function beginTransaction()
{
return $this->connectionAdapter->exec($this->sqlAdapter->beginTransaction(), $this->connectionResource);
}
public function commit()
{
return $this->connectionAdapter->exec($this->sqlAdapter->commit(), $this->connectionResource);
}
public function rollBack()
{
return $this->connectionAdapter->exec($this->sqlAdapter->rollBack(), $this->connectionResource);
}
/**
* Execute an sql query
*
* @param $sql
* @param $bind
* @param $forceUseMaster
* @return false on query failed
* --sql type-- --return value--
* SELECT, SHOW, DESECRIBE, EXPLAIN rowset or NULL when no record found
* INSERT the ID generated for an AUTO_INCREMENT column
* UPDATE, DELETE, REPLACE affected count
* USE, DROP, ALTER, CREATE, SET etc true
* @notice 每次只能执行一条SQL
* 不要通过此接口执行USE DATABASE, SET NAMES这样的语句
*/
public function query($sql, $bind = null, $forceUseMaster = false)
{
$sql = trim($sql);
if (empty($sql))
{
trigger_error('Empty the SQL statement');
}
$queryType = $this->sqlAdapter->detectQueryType($sql);
switch ($queryType)
{
case "SELECT":
if (!$forceUseMaster && isset($this->servers[$this->group][$this->node]["slave"]))
{
$this->role = "slave";
}
$queryMethod = "select";
break;
case "INSERT":
$this->role = "master";
$queryMethod = "insert";
break;
case "CHANGE_ROWS":
$this->role = "master";
$queryMethod = "changeRows";
break;
case "SET_SESSION_VAR":
$queryMethod = "setSessionVar";
break;
case "OTHER":
default:
$this->role = "master";
$queryMethod = "other";
break;
}
$connectionInfo = $this->connectionManager->getConnection($this->group, $this->node, $this->role);
$this->connectionAdapter = $connectionInfo["connectionAdapter"];
$this->connectionResource = $connectionInfo["connectionResource"];
if (is_array($bind) && 0 < count($bind))
{
$sql = $this->bindParameter($sql, $bind);
}
return $this->$queryMethod($sql, $this->connectionResource);
}
/**
* function posted by renlu
*/
public function escape($str)
{
return $this->connectionAdapter->escape($str, $this->connectionResource);
}
/**
* function posted by renlu
*/
public function insertid()
{
return $this->connectionAdapter->lastInsertId($this->connectionResource);
}
/**
* Generate complete sql from sql template (with placeholder) and parameter
*
* @param $sql
* @param $parameter
* @return string
* @todo 兼容pgsql等其它数据库pgsql的某些数据类型不接受单引号引起来的值
*/
public function bindParameter($sql, $parameter)
{
// 注意替换结果尾部加一个空格
$sql = preg_replace("/:([a-zA-Z0-9_\-\x7f-\xff][a-zA-Z0-9_\-\x7f-\xff]*)\s*([,\)]?)/", "\x01\x02\x03\\1\x01\x02\x03\\2 ", $sql);
foreach($parameter as $key => $value)
{
$find[] = "\x01\x02\x03$key\x01\x02\x03";
if ($value instanceof LtDbSqlExpression)
{
$replacement[] = $value->__toString();
}
else
{
$replacement[] = "'" . $this->connectionAdapter->escape($value, $this->connectionResource) . "'";
}
}
$sql = str_replace($find, $replacement, $sql);
return $sql;
}
protected function getCurrentSqlAdapter()
{
$factory = new LtDbAdapterFactory;
$host = key($this->servers[$this->group][$this->node][$this->role]);
return $factory->getSqlAdapter($this->servers[$this->group][$this->node][$this->role][$host]["sql_adapter"]);
}
protected function select($sql, $connResource)
{
$result = $this->connectionAdapter->query($sql, $connResource);
if (empty($result))
{
return null;
}
else
{
return $result;
}
}
protected function insert($sql, $connResource)
{
if ($result = $this->connectionAdapter->exec($sql, $connResource))
{
return $this->connectionAdapter->lastInsertId($connResource);
}
else
{
return $result;
}
}
protected function changeRows($sql, $connResource)
{
return $this->connectionAdapter->exec($sql, $connResource);
}
/**
*
* @todo 更新连接缓存
*/
protected function setSessionVar($sql, $connResource)
{
return false === $this->connectionAdapter->exec($sql, $connResource) ? false : true;
}
protected function other($sql, $connResource)
{
return false === $this->connectionAdapter->exec($sql, $connResource) ? false : true;
}
}

View File

@ -0,0 +1,15 @@
<?php
class LtDbSqlExpression
{
private $_expression;
public function __construct($string)
{
$this->_expression = (string) $string;
}
public function __toString()
{
return (string) $this->_expression;
}
}

View File

@ -0,0 +1,16 @@
<?php
/**
* 加工工厂类由开发者自行开发,继承自这个类
*/
abstract class LtAbstractDbSqlMapFilterObject {
// query()方法返回的结果集,用于加工的原料
public $result;
/**
* 需要被继承实现逻辑的操作类输入query()方法返回的结果集
* 经过处理后返回开发者定义的对象或结构
*/
abstract protected function process();
}

View File

@ -0,0 +1,14 @@
<?php
class LtDbSqlMapClient
{
public $configHandle;
public $dbh;
public function execute($mapId, $bind = null)
{
$sqlMap = $this->configHandle->get($this->dbh->group . "." . $mapId);
$forceUseMaster = isset($sqlMap["force_use_master"]) ? $sqlMap["force_use_master"] : false;
return $this->dbh->query($sqlMap["sql"], $bind, $forceUseMaster);
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
* 用于加工DB句柄query方法返回的数组
* 开发者在一次会话中可配置多个Filter
*/
class LtDbSqlMapResultFactory {
// Filter列表
public $filters;
public $configHandle;
public function init() {
}
/**
* 工厂入口sql map client调用的方法
* 在这个方法中调用开发者自定义的
* LtAbstractSqlMapFilterObject.process()方法
* 可配置多个process方法
*/
public function run() {
}
}

View File

@ -0,0 +1,300 @@
<?php
/**
* Database Table abstract
*
* @todo pretty join support
*/
class LtDbTableDataGateway
{
public $configHandle;
public $dbh;
/**
* The created field name
*
* @var string
*/
public $createdColumn;
/**
* The modified field name
*
* @var string
*/
public $modifiedColumn;
/**
* The table name
*
* @var string
*/
public $tableName;
/**
* The fields array
*
* @var array
*/
protected $fields;
/**
* The primary key
*
* @var string
*/
protected $primaryKey;
protected $servers;
/**
* Build table's field list
*
* @return array
*/
protected function buildFieldList()
{
if (!empty($this->fields))
{
return true;
}
$servers = $this->configHandle->get('db.servers');
$group = $this->dbh->group;
$node = $this->dbh->node;
$role = $this->dbh->role;
$table = $this->tableName;
$host = key($servers[$group][$node][$role]);
$key = md5($group . $node . $role . $table . $host . $table);
if (!$value = $this->configHandle->get($key))
{
$sql = $this->dbh->sqlAdapter->showFields($this->tableName);
$rs = $this->dbh->query($sql);
$this->fields = $this->dbh->sqlAdapter->getFields($rs);
foreach($this->fields as $field)
{
if ($field['primary'] == 1)
{
$this->primaryKey = $field['name'];
break;
}
}
$value['fields'] = $this->fields;
$value['primaryKey'] = $this->primaryKey;
$this->configHandle->addConfig(array($key => $value));
}
else
{
$this->fields = $value['fields'];
$this->primaryKey = $value['primaryKey'];
}
}
/**
* A shortcut to SELECT COUNT(*) FROM table WHERE condition
*
* @param array $args
* @return integer
* @example count(array('expression' => 'id < :id', 'value' => array('id' => 10)));
*/
public function count($args = null)
{
$selectTemplate = 'SELECT COUNT(*) AS total FROM %s%s';
$where = isset($args['where']['expression']) ? ' WHERE ' . $args['where']['expression'] : '';
$bind = isset($args['where']['value']) ? $args['where']['value'] : array();
$join = isset($args['join']) ? ' ' . $args['join'] : '';
$sql = sprintf($selectTemplate, $this->tableName, $join . $where);
$queryResult = $this->dbh->query($sql, $bind);
return $queryResult[0]['total'];
}
/**
* Delete a row by primary key
*
* @param string $primaryKeyId
* @return string
* @example delete(10);
*/
public function delete($primaryKeyId)
{
$this->buildFieldList();
$where['expression'] = $this->primaryKey . '=:' . $this->primaryKey;
$where['value'][$this->primaryKey] = $primaryKeyId;
return $this->deleteRows($where);
}
/**
* Delete many rows from table
* Please use this method carefully!
*
* @param array $args
* @return integer
* @example deleteRows(array('expression' => "id > :id", 'value' => array('id' => 2)));
*/
public function deleteRows($args = null)
{
$deleteTemplate = 'DELETE FROM %s%s';
$where = isset($args['expression']) ? ' WHERE ' . $args['expression'] : '';
$bind = isset($args['value']) ? $args['value'] : array();
$sql = sprintf($deleteTemplate, $this->tableName, $where);
return $this->dbh->query($sql, $bind);
}
/**
* Fetch one row from table by primary key
*
* @param string $primaryKeyId
* @param array $args
* @param boolean $useSlave
* @return array
* @example fetch(10)
*/
public function fetch($primaryKeyId, $args = null, $useSlave = true)
{
$this->buildFieldList();
$fetchRowsArgs['where']['expression'] = $this->tableName . '.' . $this->primaryKey . '=:' . $this->primaryKey;
$fetchRowsArgs['where']['value'][$this->primaryKey] = $primaryKeyId;
$fetchRowsArgs['fields'] = isset($args['fields']) ? $args['fields'] : null;
$fetchRowsArgs['join'] = isset($args['join']) ? $args['join'] : null;
$fetchResult = $this->fetchRows($fetchRowsArgs, $useSlave);
return $fetchResult ? $fetchResult[0] : $fetchResult;
}
/**
* Fetch many rows from table
*
* @param array $args
* @param boolean $useSlave
* @return array
* @example fetchRows(array('where' => array('expression' => "id > :id", 'value' => array('id' => 2))));
*/
public function fetchRows($args = null, $useSlave = true)
{
$this->buildFieldList();
$selectTemplate = 'SELECT %s FROM %s%s';
$fields = isset($args['fields']) ? $args['fields'] : '*';
$where = isset($args['where']['expression']) ? ' WHERE ' . $args['where']['expression'] : '';
$bind = isset($args['where']['value']) ? $args['where']['value'] : array();
$join = isset($args['join']) ? ' ' . $args['join'] : '';
$orderby = isset($args['orderby']) ? ' ORDER BY ' . $args['orderby'] : '';
$groupby = isset($args['groupby']) ? ' GROUP BY ' . $args['groupby'] : '';
$sql = sprintf($selectTemplate, $fields, $this->tableName, $join . $where . $groupby . $orderby);
if (isset($args['limit']))
{
$offset = isset($args['offset']) ? $args['offset'] : 0;
$sql = $sql . ' ' . $this->dbh->sqlAdapter->limit($args['limit'], $offset);
}
return $this->dbh->query($sql, $bind);
}
/**
* Insert one row into table, then return the inserted row's pk
*
* @param array $args
* @return string
* @example insert(array('name' => 'lily', 'age' => '12'));
*/
public function insert($args = null)
{
$this->buildFieldList();
$insertTemplate = 'INSERT INTO %s (%s) VALUES (%s)';
$fields = array();
$placeHolders = array();
foreach($args as $field => $value)
{
if (isset($this->fields[$field]))
{
$fields[] = $field;
$placeholders[] = ":$field";
$values[$field] = $value;
}
}
if (isset($this->fields[$this->createdColumn]) && !isset($args[$this->createdColumn]))
{
$fields[] = $this->createdColumn;
$placeholders[] = ':' . $this->createdColumn;
$values[$this->createdColumn] = time();
}
if (isset($this->fields[$this->modifiedColumn]) && !isset($args[$this->modifiedColumn]))
{
$fields[] = $this->modifiedColumn;
$placeholders[] = ':' . $this->modifiedColumn;
$values[$this->modifiedColumn] = time();
}
$sql = sprintf($insertTemplate, $this->tableName, implode(",", $fields), implode(",", $placeholders));
$bind = $values;
$queryResult = $this->dbh->query($sql, $bind);
return isset($args[$this->primaryKey]) ? $args[$this->primaryKey] : $queryResult;
}
/**
* Update one row by primary key
*
* @param string $primaryKeyId
* @param array $args
* @return integer
* @example update(1, array('name' => 'lily', 'age' => '18'));
*/
public function update($primaryKeyId, $args = null)
{
$this->buildFieldList();
$where['expression'] = $this->primaryKey . '=:' . $this->primaryKey;
$where['value'][$this->primaryKey] = $primaryKeyId;
return $this->updateRows($where, $args);
}
/**
* Update manay rows
* Please use this method carefully!
*
* @param array $where
* @param array $args
* @return integer
* @example updateRows(array('expression' => "id > :id", 'value' => array('id' => 2)), array('name' => 'kiwi', 'age' => '1'));
*/
public function updateRows($where, $args = null)
{
$this->buildFieldList();
$updateTemplate = 'UPDATE %s SET %s%s';
$fields = array();
$bindParameters = array();
$placeholderStyle = isset($where['value']) && array_key_exists(0, $where['value']) ? 'questionMark' : 'named';
foreach($args as $field => $value)
{
if (isset($this->fields[$field]))
{
if ($args[$field] instanceof DbExpression)
{
$fields[] = "$field=" . $args[$field]->__toString();
}
else
{
if ('named' == $placeholderStyle)
{
$fields[] = "$field=:$field";
$bindParameters[$field] = $args[$field];
}
else
{
$fields[] = "$field=?";
$bindParameters[] = $args[$field];
}
}
}
}
if (isset($this->fields[$this->modifiedColumn]) && !isset($args[$this->modifiedColumn]))
{
if ('named' == $placeholderStyle)
{
$fields[] = $this->modifiedColumn . '=:' . $this->modifiedColumn;
$bindParameters[$this->modifiedColumn] = time();
}
else
{
$fields[] = $this->modifiedColumn . '=?';
$bindParameters[] = time();
}
}
$whereCause = isset($where['expression']) ? ' WHERE ' . $where['expression'] : '';
$bind = isset($where['value']) ? array_merge($bindParameters, $where['value']) : $bindParameters;
$sql = sprintf($updateTemplate, $this->tableName, implode(",", $fields), $whereCause);
return $this->dbh->query($sql, $bind);
}
}

View File

@ -0,0 +1,16 @@
<?php
class LtInflector
{
public $conf = array("separator" => "_");
public function camelize($uncamelized_words)
{
$uncamelized_words = $this->conf["separator"] . str_replace($this->conf["separator"] , " ", strtolower($uncamelized_words));
return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $this->conf["separator"] );
}
public function uncamelize($camelCaps)
{
return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $this->conf["separator"] . "$2", $camelCaps));
}
}

View File

@ -0,0 +1,42 @@
<?php
class LtLogger
{
public $conf = array(
"separator" => "\t",
"log_file" => ""
);
private $fileHandle;
protected function getFileHandle()
{
if (null === $this->fileHandle)
{
if (empty($this->conf["log_file"]))
{
trigger_error("no log file spcified.");
}
$logDir = dirname($this->conf["log_file"]);
if (!is_dir($logDir))
{
mkdir($logDir, 0777, true);
}
$this->fileHandle = fopen($this->conf["log_file"], "a");
}
return $this->fileHandle;
}
public function log($logData)
{
if ("" == $logData || array() == $logData)
{
return false;
}
if (is_array($logData))
{
$logData = implode($this->conf["separator"], $logData);
}
$logData = $logData. "\n";
fwrite($this->getFileHandle(), $logData);
}
}

View File

@ -0,0 +1,157 @@
<?php
class Lotus
{
/**
* Lotus Option array
*
* @var array array(
* "proj_dir" =>
* "app_name" =>
* "autoload_dir" =>
* );
*/
public $option;
public $devMode = true;
public $defaultStoreDir;
protected $proj_dir;
protected $app_dir;
protected $data_dir;
protected $lotusRuntimeDir;
protected $coreCacheHandle;
public function __construct()
{
$this->lotusRuntimeDir = dirname(__FILE__) . DIRECTORY_SEPARATOR;
}
public function init()
{
$underMVC = false;
if (isset($this->option["proj_dir"]) && !empty($this->option["proj_dir"]))
{
$this->proj_dir = rtrim($this->option["proj_dir"], '\\/') . '/';
if (isset($this->option["app_name"]) && !empty($this->option["app_name"]))
{
$this->app_dir = $this->proj_dir . "app/" . $this->option["app_name"] . "/";
$this->data_dir = $this->proj_dir . "data/" . $this->option["app_name"] . "/";
$underMVC = true;
}
else
{
trigger_error("Lotus option [app_name] is missing.");
}
}
/**
* Load core component
*/
require_once $this->lotusRuntimeDir . "Store.php";
require_once $this->lotusRuntimeDir . "StoreMemory.php";
require_once $this->lotusRuntimeDir . "StoreFile.php";
if ($this->defaultStoreDir)
{
if ($defaultStoreDir = realpath($this->defaultStoreDir))
{
LtStoreFile::$defaultStoreDir = $defaultStoreDir;
}
else
{
trigger_error("invalid [default store dir]: " . $this->defaultStoreDir);
}
}
if (!$this->devMode)
{
/**
* accelerate LtAutoloader, LtConfig
*/
$this->coreCacheHandle = new LtStoreFile;
$prefix = sprintf("%u", crc32(serialize($this->app_dir)));
$this->coreCacheHandle->prefix = 'Lotus-' . $prefix;
$this->coreCacheHandle->useSerialize = true;
$this->coreCacheHandle->init();
}
/**
* Init Autoloader, do this before init all other lotusphp component.
*/
$this->prepareAutoloader();
/**
* init Config
*/
$this->prepareConfig();
/**
* Run dispatcher when under MVC mode
*/
if ($underMVC)
{
$this->runMVC();
}
}
/**
* Autoload all lotus components and user-defined libraries;
*/
protected function prepareAutoloader()
{
require_once $this->lotusRuntimeDir . "Autoloader/Autoloader.php";
$autoloader = new LtAutoloader;
$autoloader->autoloadPath[] = $this->lotusRuntimeDir;
if (isset($this->option["autoload_dir"]))
{
$autoloader->autoloadPath[] = $this->option["autoload_dir"];
}
if ($this->proj_dir)
{
is_dir($this->proj_dir . 'lib') && $autoloader->autoloadPath[] = $this->proj_dir . 'lib';
is_dir($this->app_dir . 'action') && $autoloader->autoloadPath[] = $this->app_dir . 'action';
is_dir($this->app_dir . 'lib') && $autoloader->autoloadPath[] = $this->app_dir . 'lib';
}
if (!$this->devMode)
{
$autoloader->storeHandle = $this->coreCacheHandle;
}
$autoloader->init();
}
protected function prepareConfig()
{
$this->configHandle = LtObjectUtil::singleton('LtConfig');
if (!$this->devMode)
{
$configFile = 'conf/conf.php';
$this->configHandle->storeHandle = $this->coreCacheHandle;
}
else
{
$configFile = 'conf/conf_dev.php';
}
$this->configHandle->init();
if ($this->app_dir && is_file($this->app_dir . $configFile))
{
$this->configHandle->loadConfigFile($this->app_dir . $configFile);
}
}
protected function runMVC()
{
$router = LtObjectUtil::singleton('LtRouter');
$router->init();
$dispatcher = LtObjectUtil::singleton('LtDispatcher');
$dispatcher->viewDir = $this->app_dir . 'view/';
$dispatcher->viewTplDir = $this->data_dir . 'templateView/';
if (!$this->devMode)
{
$dispatcher->viewTplAutoCompile = false;
}
else
{
$dispatcher->viewTplAutoCompile = true;
}
$dispatcher->dispatchAction($router->module, $router->action);
}
}

View File

@ -0,0 +1,236 @@
<?php
/**
* The Action class
*/
abstract class LtAction
{
/**
* The context object
*
* @var object
*/
public $context;
public $viewDir;
public $viewTplDir;
public $viewTplAutoCompile;
/**
* The dtd config for validator
*
* @var array
*/
protected $dtds = array();
/**
* The Access Control List
*
* @var array
*/
protected $acl;
/**
* The current user's roles
*
* @var array
*/
protected $roles = array();
/**
* A flag to indicate if subclass call LtAction::__construct()
*
* @var boolean
*/
protected $constructed = false;
/**
* The response type
*
* @var string
*/
protected $responseType = "html";
/**
* Result properties
*/
protected $code;
protected $message;
public $data;
protected $view;
protected $layout;
/**
* The constructor function, initialize the URI property
*/
public function __construct()
{
$this->constructed = true;
}
public function executeChain()
{
if (!$this->constructed)
{
//DebugHelper::debug('SUBCLASS_NOT_CALL_PARENT_CONSTRUCTOR', array('class' => $actionClassName));
trigger_error('SUBCLASS_NOT_CALL_PARENT_CONSTRUCTOR');
}
$this->afterConstruct();
$validateResult = $this->validateInput();
if (0 == $validateResult["error_total"])
{
if ($this->checkPrivilege())
{
$this->beforeExecute();
$this->execute();
}
else
{
$this->code = 403;
$this->message = "Access denied";
}
}
else
{
$this->code = 407;
$this->message = "Invalid input";
$this->data['error_messages'] = $validateResult["error_messages"];
}
$this->writeResponse();
}
/**
* Do something after subClass::__construct().
*/
protected function afterConstruct()
{
}
/**
* Validate the data from client
*
* @return array
*/
protected function validateInput()
{
$validateResult = array("error_total" => 0, "error_messages" => array());
if (!empty($this->dtds) && class_exists('LtValidator'))
{
$validator = new LtValidator;
$validator->init();
foreach ($this->dtds as $variable => $dtd)
{
$from = isset($dtd->from) ? $dtd->from : 'request';
foreach ($dtd->rules as $ruleKey => $ruleValue)
{
if ($ruleValue instanceof ConfigExpression)
{
eval('$_ruleValue = ' . $ruleValue->__toString());
$dtd->rules[$ruleKey] = $_ruleValue;
}
}
$error_messages = $validator->validate($this->context->$from($variable), $dtd);
if (!empty($error_messages))
{
$validateResult['error_total'] ++;
$validateResult['error_messages'][$variable] = $error_messages;
}
}
}
return $validateResult;
}
/**
* Check if current user have privilege to do this
*
* @return boolen
*/
protected function checkPrivilege()
{
$allow = true;
if (!empty($this->roles) && class_exists('LtRbac'))
{
$module = $this->context->uri["module"];
$action = $this->context->uri["action"];
$roles = array_merge(array("*"), $this->roles);
$rbac = new LtRbac();
$rbac->init();
$allow = $rbac->checkAcl($roles, "$module/$action");
}
return $allow;
}
/**
* Do something before subClass::execute().
*/
protected function beforeExecute()
{
}
protected function execute()
{
}
protected function writeResponse()
{
switch ($this->responseType)
{
case 'json':
echo json_encode(array("code" => $this->code,
"message" => $this->message,
"data" => $this->data
));
exit; //
break;
case 'tpl':
if (null === $this->view)
{
$this->view = new LtTemplateView;
}
$this->view->component = false; // 是否组件
$this->view->context = $this->context;
$this->view->code = $this->code;
$this->view->message = $this->message;
$this->view->data = $this->data;
$this->view->layoutDir = $this->viewDir . "layout/";
$this->view->layout = $this->layout;
$this->view->templateDir = $this->viewDir;
$this->view->compiledDir = $this->viewTplDir;
$this->view->autoCompile = $this->viewTplAutoCompile;
if (empty($this->template))
{
$this->template = $this->context->uri["module"] . "-" . $this->context->uri["action"];
}
$this->view->template = $this->template;
$this->view->render();
break;
case 'html':
case 'wml':
default:
if (null === $this->view)
{
$this->view = new LtView;
}
$this->view->context = $this->context;
$this->view->code = $this->code;
$this->view->message = $this->message;
$this->view->data = $this->data;
$this->view->layoutDir = $this->viewDir . "layout/";
$this->view->layout = $this->layout;
$this->view->templateDir = $this->viewDir;
if (empty($this->template))
{
$this->template = $this->context->uri["module"] . "-" . $this->context->uri["action"];
}
$this->view->template = $this->template;
$this->view->render();
break;
}
}
}

View File

@ -0,0 +1,134 @@
<?php
/**
* The Component class
*/
abstract class LtComponent
{
/**
* The context object
*
* @var object
*/
public $context;
public $viewDir;
public $viewTplDir;
public $viewTplAutoCompile;
/**
* A flag to indicate if subclass call LtComponent::__construct()
*
* @var boolean
*/
public $constructed = false;
/**
* The response type
*
* @var string
*/
protected $responseType = "html";
/**
* Result properties
*/
protected $code;
protected $message;
public $data;
protected $view;
protected $layout;
/**
* The constructor function
*/
public function __construct()
{
$this->constructed = true;
}
public function executeChain()
{
if (!$this->constructed)
{
//DebugHelper::debug('SUBCLASS_NOT_CALL_PARENT_CONSTRUCTOR', array('class' => $actionClassName));
}
$this->afterConstruct();
$this->beforeExecute();
$this->execute();
$this->writeResponse();
}
protected function afterConstruct()
{
}
/**
* Do something before subClass::execute().
*/
protected function beforeExecute()
{
}
protected function execute()
{
}
protected function writeResponse()
{
switch ($this->responseType)
{
case 'json':
echo json_encode(array("code" => $this->code,
"message" => $this->message,
"data" => $this->data
));
exit;
break;
case 'tpl':
if (null === $this->view)
{
$this->view = new LtTemplateView;
}
$this->view->component = true; // 是否组件
$this->view->context = $this->context;
$this->view->code = $this->code;
$this->view->message = $this->message;
$this->view->data = $this->data;
$this->view->layoutDir = $this->viewDir . "layout/";
$this->view->layout = $this->layout;
$this->view->templateDir = $this->viewDir . "component/";
$this->view->compiledDir = $this->viewTplDir . "component/";
$this->view->autoCompile = $this->viewTplAutoCompile;
if (empty($this->template))
{
$this->template = $this->context->uri["module"] . "-" . $this->context->uri["action"];
}
$this->view->template = $this->template;
$this->view->render();
break;
case 'html':
case 'wml':
default:
if (null === $this->view)
{
$this->view = new LtView;
}
$this->view->context = $this->context;
$this->view->code = $this->code;
$this->view->message = $this->message;
$this->view->data = $this->data;
$this->view->layoutDir = $this->viewDir . "layout/";
$this->view->layout = $this->layout;
$this->view->templateDir = $this->viewDir . "component/";
if (empty($this->template))
{
$this->template = $this->context->uri["module"] . "-" . $this->context->uri["action"];
}
$this->view->template = $this->template;
$this->view->render();
break;
}
}
}

View File

@ -0,0 +1,98 @@
<?php
class LtContext
{
/**
* The uri property
*
* @var array
*/
public $uri;
protected $strip;
public function __construct()
{
}
/**
* return the client input in $_SERVER['argv']
*
* @param integer $offset
* @return string
*/
public function argv($offset)
{
return isset($_SERVER['argv']) && isset($_SERVER['argv'][$offset]) ? $_SERVER['argv'][$offset] : null;
}
/**
* return the client input in $_FILES
*
* @param string $name
* @return array
*/
public function file($name)
{
return isset($_FILES[$name]) ? $_FILES[$name] : null;
}
/**
* return the client input in $_GET
*
* @param string $name
* @return string
*/
public function get($name)
{
return isset($_GET[$name]) ? $_GET[$name] : null;
}
/**
* return the client input in $_POST
*
* @param string $name
* @return string
*/
public function post($name)
{
return isset($_POST[$name]) ? $_POST[$name] : null;
}
/**
* return the client input in $_REQUEST
*
* @param string $name
* @return string
*/
public function request($name)
{
return isset($_REQUEST[$name]) ? $_REQUEST[$name] : null;
}
/**
* return the client input in $_SERVER
*
* @param string $name
* @return string
*/
public function server($name)
{
if ('REMOTE_ADDR' == $name)
{
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$clientIp = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
else
{
$clientIp = $_SERVER[$name];
}
return $clientIp;
}
else
{
return isset($_SERVER[$name]) ? $_SERVER[$name] : null;
}
}
}

View File

@ -0,0 +1,74 @@
<?php
/**
* The Dispatcher class
*/
class LtDispatcher
{
public $viewDir;
public $viewTplDir;
public $viewTplAutoCompile;
public $data;
public function __construct()
{
}
protected function _dispatch($module, $action, $context = null, $classType = "Action")
{
$classType = ucfirst($classType);
$actionClassName = $module . $action . $classType;
if (!class_exists($actionClassName))
{
//DebugHelper::debug("{$classType}_CLASS_NOT_FOUND", array(strtolower($classType) => $action));
trigger_error("{$actionClassName} CLASS NOT FOUND! module={$module} action={$action} classType={$classType}");
}
else
{
if (!($context instanceof LtContext))
{
$newContext = new LtContext;
}
else
{
$newContext = clone $context;
}
$newContext->uri['module'] = $module;
$newContext->uri[strtolower($classType)] = $action;
$actionInstance = new $actionClassName();
$actionInstance->context = $newContext;
$actionInstance->viewDir = $this->viewDir;
$actionInstance->viewTplDir = $this->viewTplDir; // 模板编译目录
$actionInstance->viewTplAutoCompile = $this->viewTplAutoCompile;
$actionInstance->executeChain();
$this->data = $actionInstance->data;
}
}
/**
* Disptach the module/action calling.
*
* @param $module string
* @param $action string
* @return void
* @todo allow one action dispatch another action
*/
public function dispatchAction($module, $action, $context = null)
{
$this->_dispatch($module, $action, $context);
}
/**
* Disptach the module/component calling.
*
* @param $module string
* @param $component string
* @param $data mixed
* @return void
*/
public function dispatchComponent($module, $component, $context = null)
{
$cloneOfContext = clone $context;
$this->_dispatch($module, $component, $cloneOfContext, "Component");
}
}

View File

@ -0,0 +1,385 @@
<?php
class LtTemplateView
{
public $layout;
public $layoutDir;
public $template;
public $templateDir;
public $compiledDir;
public $autoCompile; // bool
public $component; // bool
private $tpl_include_files;
public function __construct()
{
/**
* 自动编译通过对比文件修改时间确定是否编译,
* 当禁止自动编译时, 需要手工删除编译后的文件来重新编译.
*
* 支持component include自动编译
*/
$this->autoCompile = true;
$this->component = false;
}
public function render()
{
if (empty($this->compiledDir))
{
$this->compiledDir = dirname($this->templateDir) . "/viewTpl/";
}
if (!empty($this->layout))
{
include $this->template(true);
}
else if ($this->component)
{
return; // 模板内使用{component module action}合并文件
}
else
{
include $this->template();
}
}
/**
* 返回编译后的模板路径, 如果不存在则编译生成并返回路径.
* 如果文件存在且允许自动编译, 则对比模板文件和编译后的文件修改时间
* 当修改模板后自支重新编译
*
* @param bool $islayout 是否使用布局
* @return string 返回编译后的模板路径
*/
public function template($islayout = false)
{
$this->layoutDir = rtrim($this->layoutDir, '\\/') . '/';
$this->compiledDir = rtrim($this->compiledDir, '\\/') . '/';
$this->templateDir = rtrim($this->templateDir, '\\/') . '/';
if ($islayout)
{
$tplfile = $this->layoutDir . $this->layout . '.php';
$objfile = $this->compiledDir . 'layout/' . $this->layout . '@' . $this->template . '.php';
}
else
{
$tplfile = $this->templateDir . $this->template . '.php';
$objfile = $this->compiledDir . $this->template . '.php';
}
if (is_file($objfile))
{
if ($this->autoCompile)
{
$iscompile = true;
$tpl_include_files = include($objfile);
$last_modified_time = array();
foreach($tpl_include_files as $f)
{
$last_modified_time[] = filemtime($f);
}
if (filemtime($objfile) == max($last_modified_time))
{
$iscompile = false;
}
}
else
{
$iscompile = false;
}
}
else
{
// 目标文件不存在,编译模板
$iscompile = true;
}
if ($iscompile)
{
$this->tpl_include_files[] = $objfile;
$this->tpl_include_files[] = $tplfile;
$dir = pathinfo($objfile, PATHINFO_DIRNAME);
if (!is_dir($dir))
{
if (!mkdir($dir, 0777, true))
{
trigger_error("Can not create $dir");
}
}
$str = file_get_contents($tplfile);
if (!$str)
{
trigger_error('Template file Not found or have no access!', E_USER_ERROR);
}
$str = $this->parse($str);
if ($this->autoCompile)
{
$prefix = "<?php\r\nif(isset(\$iscompile)&&true==\$iscompile)\r\nreturn " . var_export(array_unique($this->tpl_include_files), true) . ";?>";
$prefix = preg_replace("/([\r\n])+/", "\r\n", $prefix);
$postfix = "\r\n<!--Template compilation time : " . date('Y-m-d H:i:s') . "-->\r\n";
}
else
{
$prefix = '';
$postfix = '';
}
$str = $prefix . $str . $postfix;
if (!file_put_contents($objfile, $str))
{
if (file_put_contents($objfile . '.tmp', $str))
{
copy($objfile . '.tmp', $objfile); // win下不能重命名已经存在的文件
unlink($objfile . '.tmp');
}
}
@chmod($objfile,0777);
}
return $objfile;
}
/**
* 解析{}内字符串,替换php代码
*
* @param string $str
* @return string
*/
protected function parse($str)
{
$str = $this->removeComments($str);
$str = $this->parseIncludeComponent($str);
// 回车 换行
$str = str_replace("{CR}", "<?php echo \"\\r\";?>", $str);
$str = str_replace("{LF}", "<?php echo \"\\n\";?>", $str);
// if else elseif
$str = preg_replace("/\{if\s+(.+?)\}/", "<?php if(\\1) { ?>", $str);
$str = preg_replace("/\{else\}/", "<?php } else { ?>", $str);
$str = preg_replace("/\{elseif\s+(.+?)\}/", "<?php } elseif (\\1) { ?>", $str);
$str = preg_replace("/\{\/if\}/", "<?php } ?>", $str);
// loop
$str = preg_replace("/\{loop\s+(\S+)\s+(\S+)\}/e", "\$this->addquote('<?php if(isset(\\1) && is_array(\\1)) foreach(\\1 as \\2) { ?>')", $str);
$str = preg_replace("/\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}/e", "\$this->addquote('<?php if(isset(\\1) && is_array(\\1)) foreach(\\1 as \\2=>\\3) { ?>')", $str);
$str = preg_replace("/\{\/loop\}/", "<?php } ?>", $str);
// url生成
$str = preg_replace("/\{url\(([^}]+)\)\}/", "<?php echo LtObjectUtil::singleton('LtUrl')->generate(\\1);?>", $str);
// 函数
$str = preg_replace("/\{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\s*\(([^{}]*)\))\}/", "<?php echo \\1;?>", $str);
$str = preg_replace("/\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\(([^{}]*)\))\}/", "<?php echo \$\\1;?>", $str);
// 变量
/**
* 放弃支持$name.name.name
* $str = preg_replace("/\{(\\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\.([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/", "<?php echo \\1['\\2'];?>", $str);
*/
// 其它变量
$str = preg_replace("/\{(\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/", "<?php echo \\1;?>", $str);
$str = preg_replace("/\{(\\$[a-zA-Z0-9_\.\[\]\'\"\$\x7f-\xff]+)\}/e", "\$this->addquote('<?php echo \\1;?>')", $str);
// 类->属性 类->方法
$str = preg_replace("/\{(\\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff][+\-\>\$\'\"\,\[\]\(\)a-zA-Z0-9_\x7f-\xff]+)\}/es", "\$this->addquote('<?php echo \\1;?>')", $str);
// 常量
$str = preg_replace("/\{([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)\}/", "<?php echo \\1;?>", $str);
// 静态变量
$str = preg_replace("/\{([a-zA-Z0-9_]*::?\\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/", "<?php echo \\1;?>", $str);
$str = preg_replace("/\{([a-zA-Z0-9_]*::?\\\$[a-zA-Z0-9_\.\[\]\'\"\$\x7f-\xff]+)\}/e", "\$this->addquote('<?php echo \\1;?>')", $str);
// 合并相邻php标记
$str = preg_replace("/\?\>\s*\<\?php[\r\n\t ]*/", "", $str);
/**
* 删除空行
* Dos和windows采用回车+换行CR/LF表示下一行,
* 而UNIX/Linux采用换行符LF表示下一行
* 苹果机(MAC OS系统)则采用回车符CR表示下一行.
* CR用符号 '\r'表示, 十进制ASCII代码是13, 十六进制代码为0x0D;
* LF使用'\n'符号表示, ASCII代码是10, 十六制为0x0A.
* 所以Windows平台上换行在文本文件中是使用 0d 0a 两个字节表示,
* 而UNIX和苹果平台上换行则是使用0a或0d一个字节表示.
*
* 这里统一替换成windows平台回车换行, 第二参数考虑 \\1 保持原有
*/
$str = preg_replace("/([\r\n])+/", "\r\n", $str);
// 删除第一行
$str = preg_replace("/^[\r\n]+/", "", $str);
// write
$str = trim($str);
return $str;
}
/**
* 变量加上单引号
* 如果是数字就不加单引号, 如果已经加上单引号或者双引号保持不变
*/
protected function addquote($var)
{
preg_match_all("/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", $var, $vars);
foreach($vars[1] as $k => $v)
{
if (is_numeric($v))
{
$var = str_replace($vars[0][$k], "[$v]", $var);
}
else
{
$var = str_replace($vars[0][$k], "['$v']", $var);
}
}
return str_replace("\\\"", "\"", $var);
}
/**
* 模板中第一行可以写exit函数防止浏览
* 删除行首尾空白, html javascript css注释
*/
protected function removeComments($str, $clear = false)
{
$str = str_replace(array('<?php exit?>', '<?php exit;?>'), array('', ''), $str);
// 删除行首尾空白
$str = preg_replace("/([\r\n]+)[\t ]+/s", "\\1", $str);
$str = preg_replace("/[\t ]+([\r\n]+)/s", "\\1", $str);
// 删除 {} 前后的 html 注释 <!-- -->
$str = preg_replace("/\<\!\-\-\s*\{(.+?)\}\s*\-\-\>/s", "{\\1}", $str);
$str = preg_replace("/\<\!\-\-\s*\-\-\>/s", "", $str);
// 删除 html注释 存在 < { 就不删除
$str = preg_replace("/\<\!\-\-\s*[^\<\{]*\s*\-\-\>/s", "", $str);
if ($clear)
{
$str = $this->clear($str);
}
return $str;
}
/**
* 清除一部分 style script内的注释
* 多行注释内部存在 / 字符就不会清除
*/
protected function clear($str)
{
preg_match_all("|<script[^>]*>(.*)</script>|Usi", $str, $tvar);
foreach($tvar[0] as $k => $v)
{
// 删除单行注释
$v = preg_replace("/\/\/\s*[a-zA-Z0-9_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/", "", $v);
// 删除多行注释
$v = preg_replace("/\/\*[^\/]*\*\//s", "", $v);
$str = str_replace($tvar[0][$k], $v, $str);
}
preg_match_all("|<style[^>]*>(.*)</style>|Usi", $str, $tvar);
foreach($tvar[0] as $k => $v)
{
// 删除多行注释
$v = preg_replace("/\/\*[^\/]*\*\//s", "", $v);
$str = str_replace($tvar[0][$k], $v, $str);
}
return $str;
}
/**
*
* @todo 注意相互引用的模板嵌套会导致死循环
*/
protected function parseIncludeComponent($str)
{
$count_include_component = preg_match_all("/\{include\s+(.+)\}/", $str, $tvar);
$count_include_component += preg_match_all("/\{component\s+([a-zA-Z0-9\.\-_]+)\s+([a-zA-Z0-9\.\-_]+)\}/", $str, $tvar);
unset($tvar);
while ($count_include_component > 0)
{
$str = $this->parseInclude($str);
$str = $this->parseComponent($str);
$count_include_component = preg_match_all("/\{include\s+(.+)\}/", $str, $tvar);
$count_include_component += preg_match_all("/\{component\s+([a-zA-Z0-9\.\-_]+)\s+([a-zA-Z0-9\.\-_]+)\}/", $str, $tvar);
unset($tvar);
}
$str = $this->removeComments($str);
return $str;
}
/**
* 解析多个{include path/file}合并成一个文件
*
* @example {include 'debug_info'}
* {include 'debug_info.php'}
* {include "debug_info"}
* {include "debug_info.php"}
* {include $this->templateDir . $this->template}
*/
private function parseInclude($str)
{
$countSubTpl = preg_match_all("/\{include\s+(.+)\}/", $str, $tvar);
while ($countSubTpl > 0)
{
foreach($tvar[1] as $k => $subfile)
{
eval("\$subfile = $subfile;");
if (is_file($subfile))
{
$findfile = $subfile;
}
else if (is_file($subfile . '.php'))
{
$findfile = $subfile . '.php';
}
else if (is_file($this->templateDir . $subfile))
{
$findfile = $this->templateDir . $subfile;
}
else if (is_file($this->templateDir . $subfile . '.php'))
{
$findfile = $this->templateDir . $subfile . '.php';
}
else
{
$findfile = '';
}
if (!empty($findfile))
{
$subTpl = file_get_contents($findfile);
$this->tpl_include_files[] = $findfile;
}
else
{
// 找不到文件
$subTpl = 'SubTemplate not found:' . $subfile;
}
$str = str_replace($tvar[0][$k], $subTpl, $str);
}
$countSubTpl = preg_match_all("/\{include\s+(.+)\}/", $str, $tvar);
}
return $str;
}
/**
* 解析多个{component module action}合并成一个文件
*/
private function parseComponent($str)
{
$countCom = preg_match_all("/\{component\s+([a-zA-Z0-9\.\-_]+)\s+([a-zA-Z0-9\.\-_]+)\}/", $str, $tvar);
while ($countCom > 0)
{
$i = 0;
while ($i < $countCom)
{
$comfile = $this->templateDir . "component/" . $tvar[1][$i] . '-' . $tvar[2][$i] . '.php';
if (is_file($comfile))
{
$subTpl = file_get_contents($comfile);
$this->tpl_include_files[] = $comfile;
}
else
{
$subTpl = 'SubTemplate not found:' . $comfile;
}
////////////////////////////////////////////////////////////////////////////
$module = $tvar[1][$i];
$action = $tvar[2][$i];
$subTpl = "<?php
\$dispatcher = LtObjectUtil::singleton('LtDispatcher');
\$dispatcher->dispatchComponent('$module', '$action', \$this->context);
\$comdata = \$dispatcher->data;
unset(\$dispatcher);
?>
" . $subTpl;
////////////////////////////////////////////////////////////////////////////
$str = str_replace($tvar[0][$i], $subTpl, $str);
$i++;
}
$countCom = preg_match_all("/\{component\s+([a-zA-Z0-9\.\-_]+)\s+([a-zA-Z0-9\.\-_]+)\}/", $str, $tvar);
}
return $str;
}
}

View File

@ -0,0 +1,26 @@
<?php
/**
* The View class
*/
class LtView
{
public $layoutDir;
public $templateDir;
public $layout;
public $template;
public function render()
{
if (!empty($this->layout))
{
include($this->layoutDir . $this->layout . '.php');
}
else
{
include($this->templateDir . $this->template . '.php');
}
}
}

View File

@ -0,0 +1,33 @@
<?php
class LtObjectUtil
{
static $instances;
static public function singleton($className, $autoInited = true)
{
if (empty($className))
{
trigger_error('empty class name');
return false;
}
$key = strtolower($className);
if (isset(self::$instances[$key]))
{
return self::$instances[$key];
}
else if (class_exists($className))
{
$newInstance = new $className;
if ($autoInited && method_exists($newInstance, 'init'))
{
$newInstance->init();
}
self::$instances[$key] = $newInstance;
return $newInstance;
}
else
{
return false;
}
}
}

View File

@ -0,0 +1,226 @@
<?php
class LtPagination
{
public $configHandle;
public $conf;
public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}
public function init()
{
$this->conf = $this->configHandle->get("pagination.pager");
if (empty($this->conf))
{
$this->conf['per_page'] = 25; //每个页面中希望展示的项目数量
$this->conf['num_links_show'] = 9; //数字链接显示数量
$this->conf['num_point_start_end'] = 2; //“点”前边和后边的链接数量
$this->conf['show_first'] = true;
$this->conf['show_prev'] = true;
$this->conf['show_next'] = true;
$this->conf['show_last'] = true;
$this->conf['show_goto'] = false;
$this->conf['show_info'] = false;
$this->conf['show_point'] = true;
$this->conf['show_empty_button'] = false;
$this->conf['first_text'] = 'First';
$this->conf['prev_text'] = 'Prev';
$this->conf['next_text'] = 'Next';
$this->conf['last_text'] = 'Last';
$this->conf['point_text'] = '...';
$this->conf['full_tag_open'] = '<div class="pages">';
$this->conf['full_tag_close'] = '</div>';
$this->conf['num_tag_open'] = '';
$this->conf['num_tag_close'] = '';
$this->conf['link_tag_open'] = '<a href=":url">';
$this->conf['link_tag_close'] = '</a>';
$this->conf['link_tag_cur_open'] = '<strong>';
$this->conf['link_tag_cur_close'] = '</strong>';
$this->conf['button_tag_open'] = '<a href=":url" style="font-weight:bold">';
$this->conf['button_tag_close'] = '</a>';
$this->conf['button_tag_empty_open'] = '<span>';
$this->conf['button_tag_empty_close'] = '</span>';
$this->conf['point_tag_open'] = '<span>';
$this->conf['point_tag_close'] = '</span>';
}
}
/**
*
* @param $page int 当前页
* @param $count int 这个数值是你查询数据库得到的数据总量
* @param $url string 字串中使用 :page 表示页参数 不在意位置 如/a/:page/c/e
*/
public function pager($page, $count, $url)
{
$per_page = empty($this->conf['per_page']) ? 25 : $this->conf['per_page'];
$pagecount = ceil($count / $per_page);
$pager = $this->renderPager($page, $pagecount, $url);
if ($this->conf['show_goto'])
{
$pager .= $this->renderButton('goto', $page, $pagecount, $url);
}
if ($this->conf['show_info'])
{
$pager .= $this->renderButton('info', $page, $pagecount, $url);
}
return $this->conf['full_tag_open'] . $pager . $this->conf['full_tag_close'];
}
/**
*
* @param $pagenumber int 当前页
* @param $pagecount int 总页数
* @return string
*/
public function renderPager($pagenumber, $pagecount, $baseurl = '?page=:page')
{
$baseurl = urldecode($baseurl);
$pager = $this->conf['num_tag_open'];
$pager .= $this->renderButton('first', $pagenumber, $pagecount, $baseurl);
$pager .= $this->renderButton('prev', $pagenumber, $pagecount, $baseurl);
$startPoint = 1;
$endPoint = $this->conf['num_links_show'];
$num_links = ceil($this->conf['num_links_show'] / 2) - 1;
if ($pagenumber > $num_links)
{
$startPoint = $pagenumber - $num_links;
$endPoint = $pagenumber + $num_links;
}
if ($endPoint > $pagecount)
{
$startPoint = $pagecount + 1 - $this->conf['num_links_show'];
$endPoint = $pagecount;
}
if ($startPoint < 1)
{
$startPoint = 1;
}
$currentButton = '';
if ($this->conf['show_point'])
{
for($page = 1; $page < $startPoint; $page++)
{
$url = str_replace(':page', $page, $baseurl);
if ($page > $this->conf['num_point_start_end'])
{
$currentButton .= $this->conf['point_tag_open'] . $this->conf['point_text'] . $this->conf['point_tag_close'];
break;
}
$currentButton .= str_replace(':url', $url, $this->conf['link_tag_open']) . $page . $this->conf['link_tag_close'];
}
}
for ($page = $startPoint; $page <= $endPoint; $page++)
{
$url = str_replace(':page', $page, $baseurl);
if ($page == $pagenumber)
{
$currentButton .= $this->conf['link_tag_cur_open'] . $page . $this->conf['link_tag_cur_close'];
}
else
{
$currentButton .= str_replace(':url', $url, $this->conf['link_tag_open']) . $page . $this->conf['link_tag_close'];
}
}
if ($this->conf['show_point'])
{
$page = $pagecount - $this->conf['num_point_start_end'];
if ($page > $endPoint)
{
$currentButton .= $this->conf['point_tag_open'] . $this->conf['point_text'] . $this->conf['point_tag_close'];
}
for($page += 1; $page >= $endPoint && $page <= $pagecount; $page++)
{
if ($page == $endPoint) continue;
$url = str_replace(':page', $page, $baseurl);
$currentButton .= str_replace(':url', $url, $this->conf['link_tag_open']) . $page . $this->conf['link_tag_close'];
}
}
$pager .= $currentButton;
$pager .= $this->renderButton('next', $pagenumber, $pagecount, $baseurl);
$pager .= $this->renderButton('last', $pagenumber, $pagecount, $baseurl);
$pager .= $this->conf['num_tag_close'];
return $pager;
}
/**
*
* @param $buttonLabel string 显示文字
* @param $pagenumber int 当前页
* @param $pagecount int 总页数
* @return string
*/
public function renderButton($buttonLabel, $pagenumber, $pagecount, $baseurl = '?page=:page')
{
$baseurl = urldecode($baseurl);
$destPage = 1;
if ('goto' == $buttonLabel)
{
$button = "goto <input type=\"text\" size=\"3\" onkeydown=\"javascript: if(event.keyCode==13){ location='{$baseurl}'.replace(':page',this.value);return false;}\" />";
return $button;
}
if ('info' == $buttonLabel)
{
$button = " $pagenumber/$pagecount ";
return $button;
}
switch ($buttonLabel)
{
case "first":
$destPage = 1;
$bottenText = $this->conf['first_text'];
break;
case "prev":
$destPage = $pagenumber - 1;
$bottenText = $this->conf['prev_text'];
break;
case "next":
$destPage = $pagenumber + 1;
$bottenText = $this->conf['next_text'];
break;
case "last":
$destPage = $pagecount;
$bottenText = $this->conf['last_text'];
break;
}
$url = str_replace(':page', $destPage, $baseurl);
$button = str_replace(':url', $url, $this->conf['button_tag_open']) . $bottenText . $this->conf['button_tag_close'];
if ($buttonLabel == "first" || $buttonLabel == "prev")
{
if ($pagenumber <= 1)
{
$button = $this->conf['show_empty_button'] ? $this->conf['button_tag_empty_open'] . $bottenText . $this->conf['button_tag_empty_close'] : '';
}
}
else
{
if ($pagenumber >= $pagecount)
{
$button = $this->conf['show_empty_button'] ? $this->conf['button_tag_empty_open'] . $bottenText . $this->conf['button_tag_empty_close'] : '';
}
}
return $button;
}
}

View File

@ -0,0 +1,87 @@
<?php
class LtRbac {
public $configHandle;
protected $acl;
public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}
public function init()
{
$this->acl = $this->configHandle->get('rbac.acl');
}
public function checkAcl($roles, $resource)
{
$allow = false;
// deny priority
foreach (array("allow", "deny") as $operation)
{
foreach($roles as $role)
{
if (isset($this->acl[$operation][$role]))
{
// everyone *
if (in_array($resource, $this->acl[$operation]['*']))
{
$allow = "allow" == $operation ? true : false;
break;
}
if (in_array($resource, $this->acl[$operation][$role]))
{
$allow = "allow" == $operation ? true : false;
break;
}
else
{
$res = explode('/', trim($resource, '/'));
for ($i = count($res)-1; $i >= 0; $i--)
{
$res[$i] = '*';
$tmp = implode('/', $res);
if (in_array($tmp, $this->acl[$operation][$role]))
{
$allow = "allow" == $operation ? true : false;
break;
}
unset($res[$i]);
}
}
}
}
}
return $allow;
}
/*
private function __set($p,$v)
{
$this->$p = $v;
}
private function __get($p)
{
if(isset($this->$p))
{
return($this->$p);
}
else
{
return(NULL);
}
}
*/
}

View File

@ -0,0 +1,194 @@
<?php
/**
* The Router class
*/
class LtRouter
{
public $configHandle;
public $routingTable;
public $module;
public $action;
public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil"))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}
public function init()
{
$this->routingTable = $this->configHandle->get("router.routing_table");
if (empty($this->routingTable))
{
$this->routingTable = array('pattern' => ":module/:action/*",
'default' => array('module' => 'default', 'action' => 'index'),
'reqs' => array('module' => '[a-zA-Z0-9\.\-_]+',
'action' => '[a-zA-Z0-9\.\-_]+'
),
'varprefix' => ':',
'delimiter' => '/',
'postfix' => '',
'protocol' => 'PATH_INFO', // REWRITE STANDARD
);
}
$delimiter = $this->routingTable['delimiter'];
$postfix = $this->routingTable['postfix'];
$protocol = strtoupper($this->routingTable['protocol']);
$module = '';
$action = '';
$params = array();
// HTTP HTTPS
if (isset($_SERVER['SERVER_PROTOCOL']))
{
if (isset($_SERVER['PATH_INFO']) && !empty($_SERVER['PATH_INFO']))
{
// 忽略后缀
$url = rtrim($_SERVER['PATH_INFO'], "$postfix");
$url = explode($delimiter, trim($url, "/"));
}
else if (isset($_SERVER['REQUEST_URI']))
{
if ('REWRITE' == $protocol)
{
if (0 == strcmp($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']))
{
$url = array();
}
else
{
$url = substr($_SERVER['REQUEST_URI'], strlen(pathinfo($_SERVER['SCRIPT_NAME'], PATHINFO_DIRNAME)));
$url = rtrim($url, "$postfix");
$url = explode($delimiter, trim($url, "/"));
}
}
else if ('PATH_INFO' == $protocol)
{
$url = substr($_SERVER['REQUEST_URI'], strlen($_SERVER['SCRIPT_NAME']));
$url = rtrim($url, "$postfix");
$url = explode($delimiter, trim($url, "/"));
}
else //STANDARD
{
$url = array();
foreach($_GET as $v)
{
$url[] = $v;
}
}
}
else
{
$url = array();
foreach($_GET as $v)
{
$url[] = $v;
}
}
$params = $this->matchingRoutingTable($url);
$module = $params['module'];
$action = $params['action'];
}
else
{
// CLI
$i = 0;
while (isset($_SERVER['argv'][$i]) && isset($_SERVER['argv'][$i + 1]))
{
if (("-m" == $_SERVER['argv'][$i] || "--module" == $_SERVER['argv'][$i]))
{
$module = $_SERVER['argv'][$i + 1];
}
else if (("-a" == $_SERVER['argv'][$i] || "--action" == $_SERVER['argv'][$i]))
{
$action = $_SERVER['argv'][$i + 1];
}
else
{
$key = $_SERVER['argv'][$i];
$params[$key] = $_SERVER['argv'][$i + 1];
}
$i = $i + 2;
}
}
// 如果$_GET中不存在配置的变量则添加
foreach($params as $k => $v)
{
!isset($_GET[$k]) && $_GET[$k] = $v;
}
$this->module = $module;
$this->action = $action;
}
/**
* url 匹配路由表
*
* @param $ [string|array] $url
* @return
* @todo 修复导致$_GET多出属性的BUG
* @todo 如果是rewrite或者path_info模式可能需要unset module和action两个$_GET变量
*/
public function matchingRoutingTable($url)
{
$ret = $this->routingTable['default']; //初始化返回值为路由默认值
$reqs = $this->routingTable['reqs'];
$delimiter = $this->routingTable['delimiter'];
$varprefix = $this->routingTable['varprefix'];
$postfix = $this->routingTable['postfix'];
$pattern = explode($delimiter, trim($this->routingTable['pattern'], $delimiter));
/**
* 预处理url
*/
if (is_string($url))
{
$url = rtrim($url, $postfix); //忽略后缀
$url = explode($delimiter, trim($url, $delimiter));
}
foreach($pattern as $k => $v)
{
if ($v[0] == $varprefix)
{
// 变量
$varname = substr($v, 1);
// 匹配变量
if (isset($url[$k]))
{
if (isset($reqs[$varname]))
{
$regex = "/^{$reqs[$varname]}\$/i";
if (preg_match($regex, $url[$k]))
{
$ret[$varname] = $url[$k];
}
}
}
}
else if ($v[0] == '*')
{
// 通配符
$pos = $k;
while (isset($url[$pos]) && isset($url[$pos + 1]))
{
$ret[$url[$pos ++]] = urldecode($url[$pos]);
$pos++;
}
}
else
{
// 静态
}
}
return $ret;
}
}

View File

@ -0,0 +1,56 @@
<?php
class LtSession
{
public $storeHandle;
public $configHandle;
public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}
public function init()
{
if(!$sessionSavePath = $this->configHandle->get("session.save_path"))
{
$sessionSavePath = '/tmp/Lotus/session/';
}
if (!is_object($this->storeHandle))
{
ini_set('session.save_handler', 'files');
if (!is_dir($sessionSavePath))
{
if (!@mkdir($sessionSavePath, 0777, true))
{
trigger_error("Can not create $sessionSavePath");
}
}
session_save_path($sessionSavePath);
}
else
{
$this->storeHandle->conf = $this->configHandle->get("session.conf");
$this->storeHandle->init();
session_set_save_handler(
array(&$this->storeHandle, 'open'),
array(&$this->storeHandle, 'close'),
array(&$this->storeHandle, 'read'),
array(&$this->storeHandle, 'write'),
array(&$this->storeHandle, 'destroy'),
array(&$this->storeHandle, 'gc')
);
}
//session_start();
//header("Cache-control: private"); // to overcome/fix a bug in IE 6.x
}
}

View File

@ -0,0 +1,10 @@
<?php
Interface LtSessionStore
{
public function open($save_path, $name);
public function close();
public function read($id);
public function write($id, $data);
public function destroy($id);
public function gc($maxlifetime=0);
}

View File

@ -0,0 +1 @@
<?php

View File

@ -0,0 +1 @@
<?php

View File

@ -0,0 +1 @@
<?php

View File

@ -0,0 +1,142 @@
<?php
class LtSessionSqlite implements LtSessionStore
{
public $conf;
private $lifeTime; //session.gc_maxlifetime
private $dbHandle;
private $dbName;
private $tableName;
public function __construct()
{
// --
}
public function init()
{
if (isset($this->conf['gc_maxlifetime']))
{
$this->lifeTime = $this->conf['gc_maxlifetime'];
}
else
{
$this->lifeTime = get_cfg_var("session.gc_maxlifetime");
}
if (isset($this->conf['table_name']))
{
$this->tableName = $this->conf['table_name'];
}
else
{
$this->tableName = 'lotus_session';
}
if (isset($this->conf['db_name']))
{
$this->dbName = $this->conf['db_name'];
}
else
{
$this->dbName = '/tmp/Lotus/session/session_sqlite2.db';
}
if (!$this->dbHandle = sqlite_open($this->dbName, 0666))
{
trigger_error('session sqlite db error');
return false;
}
return true;
}
public function open($savePath, $sessName)
{
return true;
}
public function close()
{
$this->gc($this->lifeTime);
return @sqlite_close($this->dbHandle);
}
public function read($sessID)
{
$res = sqlite_query("SELECT session_data AS d FROM $this->tableName
WHERE session_id = '$sessID'
AND session_expires > " . time(), $this->dbHandle);
if ($row = sqlite_fetch_array($res, SQLITE_ASSOC))
{
return $row['d'];
}
else
{
return "";
}
}
public function write($sessID, $sessData)
{
$newExp = time() + $this->lifeTime;
$res = sqlite_query("SELECT * FROM $this->tableName
WHERE session_id = '$sessID'", $this->dbHandle);
if (sqlite_num_rows($res))
{
sqlite_exec("UPDATE $this->tableName
SET session_expires = '$newExp',
session_data = '$sessData'
WHERE session_id = '$sessID'", $this->dbHandle);
if (sqlite_changes($this->dbHandle))
{
return true;
}
}
else
{
sqlite_exec("INSERT INTO $this->tableName (
session_id,
session_expires,
session_data)
VALUES(
'$sessID',
'$newExp',
'$sessData')", $this->dbHandle);
if (sqlite_changes($this->dbHandle))
{
return true;
}
}
return false;
}
public function destroy($sessID)
{
sqlite_exec("DELETE FROM $this->tableName WHERE session_id = '$sessID'", $this->dbHandle);
if (sqlite_changes($this->dbHandle))
{
return true;
}
return false;
}
public function gc($sessMaxLifeTime)
{
sqlite_exec("DELETE FROM $this->tableName WHERE session_expires < " . time(), $this->dbHandle);
return sqlite_changes($this->dbHandle);
}
public function runOnce()
{
$sql = "SELECT name FROM sqlite_master WHERE type='table' UNION ALL SELECT name FROM sqlite_temp_master WHERE type='table' AND name='" . $this->tableName . "'";
$res = sqlite_query($sql, $this->dbHandle);
$row = sqlite_fetch_array($res, SQLITE_ASSOC);
if (empty($row))
{
$sql = "CREATE TABLE $this->tableName (
[session_id] VARCHAR(255) NOT NULL PRIMARY KEY,
[session_expires] INTEGER DEFAULT '0' NOT NULL,
[session_data] TEXT NULL
)";
return sqlite_exec($sql, $this->dbHandle);
}
return false;
}
}

View File

@ -0,0 +1,8 @@
<?php
Interface LtStore
{
public function add($key, $value);
public function del($key);
public function get($key);
public function update($key, $value);
}

View File

@ -0,0 +1,125 @@
<?php
class LtStoreFile implements LtStore
{
public $storeDir;
public $prefix = 'LtStore';
public $useSerialize = false;
static public $defaultStoreDir = "/tmp/LtStoreFile/";
public function init()
{
/**
* 目录不存在和是否可写在调用add是测试
* @todo detect dir is exists and writable
*/
if (null == $this->storeDir)
{
$this->storeDir = self::$defaultStoreDir;
}
$this->storeDir = str_replace('\\', '/', $this->storeDir);
$this->storeDir = rtrim($this->storeDir, '\\/') . '/';
}
/**
* 当key存在时:
* 如果没有过期, 不更新值, 返回 false
* 如果已经过期, 更新值, 返回 true
*
* @return bool
*/
public function add($key, $value)
{
$file = $this->getFilePath($key);
$cachePath = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($cachePath))
{
if (!@mkdir($cachePath, 0777, true))
{
trigger_error("Can not create $cachePath");
}
}
if (is_file($file))
{
return false;
}
if ($this->useSerialize)
{
$value = serialize($value);
}
$length = file_put_contents($file, '<?php exit;?>' . $value);
return $length > 0 ? true : false;
}
/**
* 删除不存在的key返回false
*
* @return bool
*/
public function del($key)
{
$file = $this->getFilePath($key);
if (!is_file($file))
{
return false;
}
else
{
return @unlink($file);
}
}
/**
* 取不存在的key返回false
* 已经过期返回false
*
* @return 成功返回数据,失败返回false
*/
public function get($key)
{
$file = $this->getFilePath($key);
if (!is_file($file))
{
return false;
}
$str = file_get_contents($file);
$value = substr($str, 13);
if ($this->useSerialize)
{
$value = unserialize($value);
}
return $value;
}
/**
* key不存在 返回false
* 不管有没有过期,都更新数据
*
* @return bool
*/
public function update($key, $value)
{
$file = $this->getFilePath($key);
if (!is_file($file))
{
return false;
}
else
{
if ($this->useSerialize)
{
$value = serialize($value);
}
$length = file_put_contents($file, '<?php exit;?>' . $value);
return $length > 0 ? true : false;
}
}
public function getFilePath($key)
{
$token = md5($key);
return $this->storeDir .
$this->prefix . '/' .
substr($token, 0, 2) .'/' .
substr($token, 2, 2) . '/' .
$token . '.php';
}
}

View File

@ -0,0 +1,54 @@
<?php
class LtStoreMemory implements LtStore
{
protected $stack;
public function add($key, $value)
{
if (isset($this->stack[$key]))
{
return false;
}
else
{
$this->stack[$key] = $value;
return true;
}
}
public function del($key)
{
if (isset($this->stack[$key]))
{
unset($this->stack[$key]);
return true;
}
else
{
return false;
}
}
public function get($key)
{
return isset($this->stack[$key]) ? $this->stack[$key] : false;
}
/**
* key不存在返回false
*
* @return bool
*/
public function update($key, $value)
{
if (!isset($this->stack[$key]))
{
return false;
}
else
{
$this->stack[$key] = $value;
return true;
}
}
}

View File

@ -0,0 +1,142 @@
<?php
class LtUrl
{
public $configHandle;
public $routingTable;
public $baseUrl;
public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}
public function init()
{
$this->routingTable = $this->configHandle->get("router.routing_table");
if (empty($this->routingTable))
{
$this->routingTable = array('pattern' => ":module/:action/*",
'default' => array('module' => 'default', 'action' => 'index'),
'reqs' => array('module' => '[a-zA-Z0-9\.\-_]+',
'action' => '[a-zA-Z0-9\.\-_]+'
),
'varprefix' => ':',
'delimiter' => '/',
'postfix' => '',
'protocol' => 'PATH_INFO', // REWRITE STANDARD
);
}
$protocol = strtoupper($this->routingTable['protocol']);
if ('REWRITE' == $protocol)
{
$this->baseUrl = pathinfo($_SERVER['SCRIPT_NAME'], PATHINFO_DIRNAME) . '/';
}
else if ('STANDARD' == $protocol)
{
$this->baseUrl = $_SERVER['PHP_SELF'];
}
else
{
$this->baseUrl = '';
}
}
public function generate($module, $action, $args = array())
{
$args = array_merge(array('module' => $module, 'action' => $action), $args);
$url = '';
// $url = $_SERVER['SERVER_PORT'] == '443' ? 'https://' : 'http://';
// $url .= $_SERVER['HTTP_HOST'];
// $url .= $_SERVER['SERVER_PORT'] == '80' ? '' : ':'.$_SERVER['SERVER_PORT'];
$url .= $this->baseUrl;
$url .= $this->reverseMatchingRoutingTable($args);
return $url;
}
/**
* 将变量反向匹配路由表, 返回匹配后的url
*
* @param array $params
* @return string
*/
public function reverseMatchingRoutingTable($args)
{
$ret = $this->routingTable['pattern'];
$default = $this->routingTable['default'];
$reqs = $this->routingTable['reqs'];
$delimiter = $this->routingTable['delimiter'];
$varprefix = $this->routingTable['varprefix'];
$postfix = $this->routingTable['postfix'];
$protocol = strtoupper($this->routingTable['protocol']);
if ('STANDARD' == $protocol)
{
return '?' . http_build_query($args, '', '&');
}
$pattern = explode($delimiter, trim($this->routingTable['pattern'], $delimiter));
foreach($pattern as $k => $v)
{
if ($v[0] == $varprefix)
{
// 变量
$varname = substr($v, 1);
// 匹配变量
if (isset($args[$varname]))
{
$regex = "/^{$reqs[$varname]}\$/i";
if (preg_match($regex, $args[$varname]))
{
$ret = str_replace($v, $args[$varname], $ret);
unset($args[$varname]);
}
}
else if (isset($default[$varname]))
{
$ret = str_replace($v, $default[$varname], $ret);
}
}
else if ($v[0] == '*')
{
// 通配符
$tmp = '';
foreach($args as $key => $value)
{
if (!isset($default[$key]))
{
$tmp .= $key . $delimiter . rawurlencode($value) . $delimiter;
}
}
$tmp = rtrim($tmp, $delimiter);
$ret = str_replace($v, $tmp, $ret);
$ret = rtrim($ret, $delimiter);
}
else
{
// 静态
}
}
if ('REWRITE' == $protocol)
{
$ret = $ret . $postfix;
}
else if ('PATH_INFO' == $protocol)
{
$ret = $_SERVER['SCRIPT_NAME'] . $delimiter . $ret . $postfix;
}
else
{
$ret = $ret . $postfix;
}
return $ret;
}
}

View File

@ -0,0 +1,174 @@
<?php
class LtValidator
{
public $configHandle;
protected $errorMessages;
public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}
public function init()
{
$this->errorMessages = $this->configHandle->get('validator.error_messages');
}
/**
* Validate an element
*
* @param mixed $value
* @param array $dtd
* @return array
*/
public function validate($value, $dtd)
{
$errorMessages = array();
$label = $dtd->label;
if (is_array($dtd->rules) && count($dtd->rules))
{
$messages = isset($dtd->messages) ? $dtd->messages : array();
foreach ($dtd->rules as $key => $val)
{
// callback_user_function
if ('callback_' == substr($key, 0, 9))
{
$method = substr($key, 9);
// 定义了过程函数
if (function_exists($method))
{
if (!$method($value, $dtd->rules[$key]))
{
if (isset($this->errorMessages[$key]))
{
$messages[$key] = $this->errorMessages[$key];
}
else
{
$messages[$key] = "validator.error_messages[$key] empty";
}
$errorMessages[$key] = sprintf($messages[$key], $label, $dtd->rules[$key]);
}
continue;
}
// 定义了类方法
$rc = new ReflectionClass($val);
if ($rc->hasMethod($method))
{
$rcMethod = $rc->getMethod($method);
if ($rcMethod->isStatic())
{
$ret = $rcMethod->invoke(null, $value, $dtd->rules[$key]);
}
else
{
// 非静态方法需要一个实例 有待考虑单例
$rcInstance = $rc->newInstance();
$ret = $rcMethod->invoke($rcInstance, $value, $dtd->rules[$key]);
}
if (!$ret)
{
if (isset($this->errorMessages[$key]))
{
$messages[$key] = $this->errorMessages[$key];
}
else
{
$messages[$key] = "validator.error_messages[$key] empty";
}
$errorMessages[$key] = sprintf($messages[$key], $label, $dtd->rules[$key]);
}
continue;
}
continue;
}
// end callback_user_function
$validateFunction = '_' . $key;
if ((is_bool($dtd->rules[$key]) || 0 < strlen($dtd->rules[$key])) && !$this->$validateFunction($value, $dtd->rules[$key]))
{
if (empty($messages[$key]))
{
if (isset($this->errorMessages[$key]))
{
$messages[$key] = $this->errorMessages[$key];
}
else
{
$messages[$key] = "validator.error_messages[$key] empty";
}
}
$errorMessages[$key] = sprintf($messages[$key], $label, $dtd->rules[$key]);
}
}
}
return $errorMessages;
}
protected function _ban($value, $ruleValue)
{
return !preg_match($ruleValue, $value);
}
protected function _mask($value, $ruleValue)
{
return preg_match($ruleValue, $value);
}
protected function _equal_to($value, $ruleValue)
{
return $value === $ruleValue;
}
protected function _max_length($value, $ruleValue)
{
return mb_strlen($value) <= $ruleValue;
}
protected function _min_length($value, $ruleValue)
{
return mb_strlen($value) >= $ruleValue;
}
protected function _max_value($value, $ruleValue)
{
return $value <= $ruleValue;
}
protected function _min_value($value, $ruleValue)
{
return $value >= $ruleValue;
}
protected function _min_selected($value, $ruleValue)
{
return count($value) >= $ruleValue;
}
protected function _max_selected($value, $ruleValue)
{
return count($value) <= $ruleValue;
}
protected function _required($value, $ruleValue)
{
if (false == $ruleValue)
{
return true;
}
else
{
return is_array($value) && count($value) || strlen($value);
}
}
}

View File

@ -0,0 +1,23 @@
<?php
class LtValidatorDtd
{
public $label;
public $rules;
public $messages;
public function __construct($label, $rules, $messages = null)
{
$this->label = $label;
foreach($rules as $key => $rule)
{
$this->rules[$key] = $rule;
}
if ($messages)
{
foreach($messages as $key => $message)
{
$this->messages[$key] = $message;
}
}
}
}

View File

@ -0,0 +1,304 @@
<?php
/**
*返回码定义
*/
/* 扩展内部错误 */
define("INTERNAL_ERR", -1);
/* 当前模式下不允许执行该函数 */
define("WRONG_MODE", 0);
/* 成功 */
define("SUCESS", 1);
/**
* 模式定义
*/
define("READMODE", 0);
define("WRITEMODE", 1);
/**
* @desc LtXml用于解析和生成XML文件
* 使用前调用 init() 方法对类进行初始化
*
* LtXml提供两个公共方法 getArray() 和 getString
*
* getArray() 方法要求传入一个规范的xml字符串
* 返回一个格式化的数组
*
* getString() 方法要求传入一个格式化的数组,反
* 回一个规范的xml字符串
* 在使用getString() 方法时,传入的格式化数组可
* 通过 createTag() 方法获得。
*
*/
class LtXml {
/**
* 只支持 ISO-8859-1, UTF-8 和 US-ASCII三种编码
*/
private $_supportedEncoding = array("ISO-8859-1", "UTF-8", "US-ASCII");
/**
* XMLParser 操作句柄
*/
private $_handler;
/**
* READMODE 0:读模式encoding参数不生效通过输入的string获取version和encodinggetString方法不可用
* WRITEMODE 1:写模式按照制定的encoding和array生成stringgetArray方法不可用
*/
public $mode;
/**
* 该 XML 对象的编码ISO-8859-1, UTF-8默认 或 US-ASCII
*/
public $encoding;
/**
* 该 XML 对象的版本1.0(默认)
*/
public $version;
public function init($mode = 0, $encoding = "UTF-8", $version = "1.0") {
$this->mode = $mode;
$this->encoding = $encoding;
$this->version = $version;
$this->_getParser($encoding);
}
public function getArray($xmlString) {
if (READMODE !== $this->mode) {
trigger_error("LtXml is on WRITEMODE, and cannot convert XML string to array.");
return WRONG_MODE;
}
if (0 === preg_match("/version=[\"|\']([1-9]\d*\.\d*)[\"|\']/", $xmlString, $res)) {
trigger_error("Cannot find the version in this XML document.");
return INTERNAL_ERR;
}
else {
$this->version = $res[1];
}
if (0 === preg_match("/encoding=[\"|\'](.*?)[\"|\']/", $xmlString, $res)) {
$this->encoding = "UTF-8";
}
else {
$this->encoding = strtoupper($res[1]);
}
$_array = $this->_stringToArray($xmlString);
if (NULL === $_array) {
trigger_error("Fail to get the tag template.");
return INTERNAL_ERR;
}
$currentArray = NULL;
$openingTags = array();
$array = $this->_getArrayTemplate();
foreach ($_array as $tag) {
$tag["tag"] = strtolower($tag["tag"]);
if (isset($tag["type"]) && "close" == $tag["type"]
&& isset($tag["tag"]) && ! empty($tag["tag"])) {
if ($openingTags[count($openingTags) - 1]["tag"] == $tag["tag"]) {
unset($openingTags[count($openingTags) - 1]);
}
else {
return -1;
}
}
else if ((isset($tag["type"]) && "complete" == $tag["type"])
|| (isset($tag["type"]) && "open" == $tag["type"])
&& isset($tag["tag"]) && ! empty($tag["tag"])){
$currentArray = $this->_getArrayTemplate();
$currentArray["tag"] = $tag["tag"];
$cdata = $tag["value"];
$cdata = preg_replace("/^\s*/", "", $cdata);
$cdata = preg_replace("/\s*$/", "", $cdata);
$currentArray["cdata"] = $cdata;
if (isset($tag["attributes"]) && is_array($tag["attributes"])) {
foreach($tag["attributes"] as $k => $v) {
$currentArray["attributes"][strtolower($k)] = $v;
}
}
if (0 == count($openingTags)) {
$openingTags[] = &$array;
$openingTags[0] = $currentArray;
}
else {
$subCount = count($openingTags[count($openingTags) - 1]["sub"]);
$openingTags[count($openingTags) - 1]["sub"][$subCount] = $currentArray;
$openingTags[count($openingTags)] = &$openingTags[count($openingTags) - 1]["sub"][$subCount];
}
if ("complete" == $tag["type"]) {
unset($openingTags[count($openingTags) - 1]);
}
}
else if (isset($tag["type"]) && "cdata" == $tag["type"]
&& isset($tag["tag"]) && ! empty($tag["tag"])) {
if ($tag["tag"] == $openingTags[count($openingTags) - 1]["tag"]) {
$cdata = $tag["value"];
$cdata = preg_replace("/^\s*/", "", $cdata);
$cdata = preg_replace("/\s*$/", "", $cdata);
$openingTags[count($openingTags) - 1]["cdata"] .= $cdata;
}
else {
return -2;
}
}
}
if (0 < count($openingTags)) {
return -3;
}
return $array;
}
public function getString($xmlArray) {
if (WRITEMODE !== $this->mode) {
trigger_error("LtXml is on READMODE, and cannot convert array to string.");
return WRONG_MODE;
}
$header = "<?xml version=\"{$this->version}\" encoding=\"{$this->encoding}\"". " ?" . ">\n";
$xmlString = $header;
$processingTags = array($xmlArray);
while (! empty($processingTags)) {
if (! isset($processingTags[count($processingTags) -1]["close"])) {
$tagArray = $processingTags[count($processingTags) - 1];
if (0 === $this->_isTag($tagArray)) {
trigger_error("The array do not match the format.");
return INTERNAL_ERR;
}
$processingTags[count($processingTags) -1]["close"] = "YES";
$tagName = $tagArray["tag"];
$tag = "<{$tagName}";
foreach ($tagArray["attributes"] as $key => $value) {
$tag .= " {$key}=\"{$value}\"";
}
if (! empty($tagArray["sub"]) || ! empty($tagArray["cdata"])) {
$cdata = $this->_convertEntity($tagArray["cdata"]);
$tag .= ">\n{$cdata}\n";
for ($i=count($tagArray["sub"]) - 1; $i>=0; $i--) {
$subArray = $tagArray["sub"][$i];
$processingTags[count($processingTags)] = $subArray;
}
}
else {
$processingTags[count($processingTags) - 1]["complete"] = "YES";
}
}
else {
$tag = (isset($processingTags[count($processingTags) - 1]["complete"]))
? "/>\n"
: "</{$processingTags[count($processingTags) - 1]["tag"]}>\n";
unset($processingTags[count($processingTags) - 1]);
}
$xmlString .= $tag;
}
$xmlString = preg_replace("/\n\s*/", "\n", $xmlString);
return $xmlString;
}
/**
* 生成一个xml节点
* @param string tag 标签名
* @param string cdata 数据
* @param array attr 属性列表
* @param array sub 子标签列表
*/
public function createTag($tag, $cdata = "", $attr = array(), $sub = array()) {
$newTag = $this->_getArrayTemplate();
if (! is_string($tag)) {
trigger_error("Cannot read the tag name.");
return INTERNAL_ERR;
}
$newTag["tag"] = $tag;
$newTag["cdata"] = $cdata;
$newTag["attributes"] = $attr;
$newTag["sub"] = $sub;
return $newTag;
}
/**
* 释放xml_parser
*/
public function free() {
xml_parser_free($this->_handler);
}
private function _getParser($encoding) {
if (in_array($encoding, $this->_supportedEncoding))
$this->_handler = xml_parser_create($encoding);
else
$this->_handler = NULL;
}
private function _stringToArray($xmlString) {
$res = xml_parse_into_struct($this->_handler, $xmlString, $array);
if (1 === $res)
return $array;
else
return NULL;
}
private function _convertEntity($string) {
$patterns = array("/</", "/</", "/&/", "/'/", "/\"/");
$replacement = array("&lt;", "&gt;", "&amp;", "&apos;", "&quot;");
return preg_replace($patterns, $replacement, $string);
}
private function _rConvertEntity($string) {
$patterns = array("/&lt;/", "/&gt;/", "/&amp;/", "/&apos;/", "/&quot;/");
$replacement = array("<", "<", "&", "'", "\"");
return preg_replace($patterns, $replacement, $string);
}
private function _getArrayTemplate() {
return array("tag" => "", "attributes" => array(), "sub" => array(), "cdata" => "");
}
/**
* 检测传入的参数是否是一个合法的tag数组
* @return 0 非法
* @return 1 合法
*/
private function _isTag($tag) {
if (! is_array($tag)) {
return 0;
}
if (! isset($tag["tag"]) || ! is_string($tag["tag"]) || empty($tag["tag"])) {
return 0;
}
if (! isset($tag["attributes"]) || ! is_array($tag["attributes"])) {
return 0;
}
if (! isset($tag["sub"]) || ! is_array($tag["sub"])) {
return 0;
}
if (! isset($tag["cdata"]) || ! is_string($tag["cdata"])) {
return 0;
}
return 1;
}
}

View File

@ -0,0 +1,5 @@
<?php
function C($className)
{
return LtObjectUtil::singleton($className);
}