Adding modifications from kritbit

This commit is contained in:
Nathan Adams
2016-04-14 22:01:11 -05:00
parent 5b104d624b
commit f08b2987e1
34 changed files with 3205 additions and 2404 deletions

View File

@@ -1,266 +1,266 @@
<?php
/**
* Context object
* encapsulate context, resolve name
*/
class H2o_Context implements ArrayAccess {
public $safeClass = array('stdClass', 'BlockContext');
public $scopes;
public $options;
public $autoescape = true;
private $arrayMethods = array('first'=> 0, 'last'=> 1, 'length'=> 2, 'size'=> 3);
static $lookupTable = array();
function __construct($context = array(), $options = array()){
if (is_object($context))
$context = get_object_vars($context);
$this->scopes = array($context);
if (isset($options['safeClass']))
$this->safeClass = array_merge($this->safeClass, $options['safeClass']);
if (isset($options['autoescape']))
$this->autoescape = $options['autoescape'];
$this->options = $options;
}
function push($layer = array()){
return array_unshift($this->scopes, $layer);
}
/**
* pop the most recent layer
*/
function pop() {
if (!isset($this->scopes[1]))
throw new Exception('cannnot pop from empty stack');
return array_shift($this->scopes);
}
function offsetExists($offset) {
foreach ($this->scopes as $layer) {
if (isset($layer[$offset])) return true;
}
return false;
}
function offsetGet($key) {
foreach ($this->scopes as $layer) {
if (isset($layer[$key]))
return $layer[$key];
}
return;
}
function offsetSet($key, $value) {
if (strpos($key, '.') > -1)
throw new Exception('cannot set non local variable');
return $this->scopes[0][$key] = $value;
}
function offsetUnset($key) {
foreach ($this->scopes as $layer) {
if (isset($layer[$key])) unset($layer[$key]);
}
}
function extend($context) {
$this->scopes[0] = array_merge($this->scopes[0], $context);
}
function set($key, $value) {
return $this->offsetSet($key, $value);
}
function get($key) {
return $this->offsetGet($key);
}
function isDefined($key) {
return $this->offsetExists($key);
}
/**
*
*
*
* Variable name
*
* @param $var variable name or array(0 => variable name, 'filters' => filters array)
* @return unknown_type
*/
function resolve($var) {
# if $var is array - it contains filters to apply
$filters = array();
if ( is_array($var) ) {
$name = array_shift($var);
$filters = isset($var['filters'])? $var['filters'] : array();
}
else $name = $var;
$result = null;
# Lookup basic types, null, boolean, numeric and string
# Variable starts with : (:users.name) to short-circuit lookup
if ($name[0] === ':') {
$object = $this->getVariable(substr($name, 1));
if (!is_null($object)) $result = $object;
} else {
if ($name === 'true') {
$result = true;
}
elseif ($name === 'false') {
$result = false;
}
elseif (preg_match('/^-?\d+(\.\d+)?$/', $name, $matches)) {
$result = isset($matches[1])? floatval($name) : intval($name);
}
elseif (preg_match('/^"([^"\\\\]*(?:\\.[^"\\\\]*)*)"|' .
'\'([^\'\\\\]*(?:\\.[^\'\\\\]*)*)\'$/', $name)) {
$result = stripcslashes(substr($name, 1, -1));
}
}
if (!empty(self::$lookupTable) && $result == Null) {
$result = $this->externalLookup($name);
}
$result = $this->applyFilters($result,$filters);
return $result;
}
function getVariable($name) {
# Local variables. this gives as a bit of performance improvement
if (!strpos($name, '.'))
return $this[$name];
# Prepare for Big lookup
$parts = explode('.', $name);
$object = $this[array_shift($parts)];
# Lookup context
foreach ($parts as $part) {
if (is_array($object) or $object instanceof ArrayAccess) {
if (isset($object[$part])) {
$object = $object[$part];
} elseif ($part === 'first') {
$object = isset($object[0])?$object[0]:null;
} elseif ($part === 'last') {
$last = count($object)-1;
$object = isset($object[$last])?$object[$last]:null;
} elseif ($part === 'size' or $part === 'length') {
return count($object);
} else {
return null;
}
}
elseif (is_object($object)) {
if (isset($object->$part))
$object = $object->$part;
elseif (is_callable(array($object, $part))) {
$methodAllowed = in_array(get_class($object), $this->safeClass) ||
(isset($object->h2o_safe) && (
$object->h2o_safe === true || in_array($part, $object->h2o_safe)
)
);
$object = $methodAllowed ? $object->$part() : null;
}
else return null;
}
else return null;
}
return $object;
}
function applyFilters($object, $filters) {
foreach ($filters as $filter) {
$name = substr(array_shift($filter), 1);
$args = $filter;
if (isset(h2o::$filters[$name])) {
foreach ($args as $i => $argument) {
# name args
if (is_array($argument)) {
foreach ($argument as $n => $arg) {
$args[$i][$n] = $this->resolve($arg);
}
} else {
# resolve argument values
$args[$i] = $this->resolve($argument);
}
}
array_unshift($args, $object);
$object = call_user_func_array(h2o::$filters[$name], $args);
}
}
return $object;
}
function escape($value, $var) {
$safe = false;
$filters = (is_array($var) && isset($var['filters']))? $var['filters'] : array();
foreach ( $filters as $filter ) {
$name = substr(array_shift($filter), 1);
$safe = !$safe && ($name === 'safe');
$escaped = $name === 'escape';
}
$should_escape = $this->autoescape || isset($escaped) && $escaped;
if ( ($should_escape && !$safe)) {
$value = htmlspecialchars($value);
}
return $value;
}
function externalLookup($name) {
if (!empty(self::$lookupTable)) {
foreach (self::$lookupTable as $lookup) {
$tmp = call_user_func_array($lookup, array($name, $this));
if ($tmp !== null)
return $tmp;
}
}
return null;
}
}
class BlockContext {
var $h2o_safe = array('name', 'depth', 'super');
var $block, $index;
private $context;
function __construct($block, $context, $index) {
$this->block =& $block;
$this->context = $context;
$this->index = $index;
}
function name() {
return $this->block->name;
}
function depth() {
return $this->index;
}
function super() {
$stream = new StreamWriter;
$this->block->parent->render($this->context, $stream, $this->index+1);
return $stream->close();
}
function __toString() {
return "[BlockContext : {$this->block->name}, {$this->block->filename}]";
}
}
?>
<?php
/**
* Context object
* encapsulate context, resolve name
*/
class H2o_Context implements ArrayAccess {
public $safeClass = array('stdClass', 'BlockContext');
public $scopes;
public $options;
public $autoescape = true;
private $arrayMethods = array('first'=> 0, 'last'=> 1, 'length'=> 2, 'size'=> 3);
static $lookupTable = array();
function __construct($context = array(), $options = array()){
if (is_object($context))
$context = get_object_vars($context);
$this->scopes = array($context);
if (isset($options['safeClass']))
$this->safeClass = array_merge($this->safeClass, $options['safeClass']);
if (isset($options['autoescape']))
$this->autoescape = $options['autoescape'];
$this->options = $options;
}
function push($layer = array()){
return array_unshift($this->scopes, $layer);
}
/**
* pop the most recent layer
*/
function pop() {
if (!isset($this->scopes[1]))
throw new Exception('cannnot pop from empty stack');
return array_shift($this->scopes);
}
function offsetExists($offset) {
foreach ($this->scopes as $layer) {
if (isset($layer[$offset])) return true;
}
return false;
}
function offsetGet($key) {
foreach ($this->scopes as $layer) {
if (isset($layer[$key]))
return $layer[$key];
}
return;
}
function offsetSet($key, $value) {
if (strpos($key, '.') > -1)
throw new Exception('cannot set non local variable');
return $this->scopes[0][$key] = $value;
}
function offsetUnset($key) {
foreach ($this->scopes as $layer) {
if (isset($layer[$key])) unset($layer[$key]);
}
}
function extend($context) {
$this->scopes[0] = array_merge($this->scopes[0], $context);
}
function set($key, $value) {
return $this->offsetSet($key, $value);
}
function get($key) {
return $this->offsetGet($key);
}
function isDefined($key) {
return $this->offsetExists($key);
}
/**
*
*
*
* Variable name
*
* @param $var variable name or array(0 => variable name, 'filters' => filters array)
* @return unknown_type
*/
function resolve($var) {
# if $var is array - it contains filters to apply
$filters = array();
if ( is_array($var) ) {
$name = array_shift($var);
$filters = isset($var['filters'])? $var['filters'] : array();
}
else $name = $var;
$result = null;
# Lookup basic types, null, boolean, numeric and string
# Variable starts with : (:users.name) to short-circuit lookup
if ($name[0] === ':') {
$object = $this->getVariable(substr($name, 1));
if (!is_null($object)) $result = $object;
} else {
if ($name === 'true') {
$result = true;
}
elseif ($name === 'false') {
$result = false;
}
elseif (preg_match('/^-?\d+(\.\d+)?$/', $name, $matches)) {
$result = isset($matches[1])? floatval($name) : intval($name);
}
elseif (preg_match('/^"([^"\\\\]*(?:\\.[^"\\\\]*)*)"|' .
'\'([^\'\\\\]*(?:\\.[^\'\\\\]*)*)\'$/', $name)) {
$result = stripcslashes(substr($name, 1, -1));
}
}
if (!empty(self::$lookupTable) && $result == Null) {
$result = $this->externalLookup($name);
}
$result = $this->applyFilters($result,$filters);
return $result;
}
function getVariable($name) {
# Local variables. this gives as a bit of performance improvement
if (!strpos($name, '.'))
return $this[$name];
# Prepare for Big lookup
$parts = explode('.', $name);
$object = $this[array_shift($parts)];
# Lookup context
foreach ($parts as $part) {
if (is_array($object) or $object instanceof ArrayAccess) {
if (isset($object[$part])) {
$object = $object[$part];
} elseif ($part === 'first') {
$object = isset($object[0])?$object[0]:null;
} elseif ($part === 'last') {
$last = count($object)-1;
$object = isset($object[$last])?$object[$last]:null;
} elseif ($part === 'size' or $part === 'length') {
return count($object);
} else {
return null;
}
}
elseif (is_object($object)) {
if (isset($object->$part))
$object = $object->$part;
elseif (is_callable(array($object, $part))) {
$methodAllowed = in_array(get_class($object), $this->safeClass) ||
(isset($object->h2o_safe) && (
$object->h2o_safe === true || in_array($part, $object->h2o_safe)
)
);
$object = $methodAllowed ? $object->$part() : null;
}
else return null;
}
else return null;
}
return $object;
}
function applyFilters($object, $filters) {
foreach ($filters as $filter) {
$name = substr(array_shift($filter), 1);
$args = $filter;
if (isset(h2o::$filters[$name])) {
foreach ($args as $i => $argument) {
# name args
if (is_array($argument)) {
foreach ($argument as $n => $arg) {
$args[$i][$n] = $this->resolve($arg);
}
} else {
# resolve argument values
$args[$i] = $this->resolve($argument);
}
}
array_unshift($args, $object);
$object = call_user_func_array(h2o::$filters[$name], $args);
}
}
return $object;
}
function escape($value, $var) {
$safe = false;
$filters = (is_array($var) && isset($var['filters']))? $var['filters'] : array();
foreach ( $filters as $filter ) {
$name = substr(array_shift($filter), 1);
$safe = !$safe && ($name === 'safe');
$escaped = $name === 'escape';
}
$should_escape = $this->autoescape || isset($escaped) && $escaped;
if ( ($should_escape && !$safe)) {
$value = htmlspecialchars($value);
}
return $value;
}
function externalLookup($name) {
if (!empty(self::$lookupTable)) {
foreach (self::$lookupTable as $lookup) {
$tmp = call_user_func_array($lookup, array($name, $this));
if ($tmp !== null)
return $tmp;
}
}
return null;
}
}
class BlockContext {
var $h2o_safe = array('name', 'depth', 'super');
var $block, $index;
private $context;
function __construct($block, $context, $index) {
$this->block =& $block;
$this->context = $context;
$this->index = $index;
}
function name() {
return $this->block->name;
}
function depth() {
return $this->index;
}
function super() {
$stream = new StreamWriter;
$this->block->parent->render($this->context, $stream, $this->index+1);
return $stream->close();
}
function __toString() {
return "[BlockContext : {$this->block->name}, {$this->block->filename}]";
}
}
?>

View File

@@ -1,173 +1,173 @@
<?php
class StreamWriter {
var $buffer = array();
var $close;
function __construct() {
$this->close = false;
}
function write($data) {
if ($this->close)
new Exception('tried to write to closed stream');
$this->buffer[] = $data;
}
function close() {
$this->close = true;
return implode('', $this->buffer);
}
}
class Evaluator {
static function gt($l, $r) { return $l > $r; }
static function ge($l, $r) { return $l >= $r; }
static function lt($l, $r) { return $l < $r; }
static function le($l, $r) { return $l <= $r; }
static function eq($l, $r) { return $l == $r; }
static function ne($l, $r) { return $l != $r; }
static function not_($bool) { return !$bool; }
static function and_($l, $r) { return ($l && $r); }
static function or_($l, $r) { return ($l && $r); }
# Currently only support single expression with no preceddence ,no boolean expression
# [expression] = [optional binary] ? operant [ optional compare operant]
# [operant] = variable|string|numeric|boolean
# [compare] = > | < | == | >= | <=
# [binary] = not | !
static function exec($args, $context) {
$argc = count($args);
$first = array_shift($args);
$first = $context->resolve($first);
switch ($argc) {
case 1 :
return $first;
case 2 :
if (is_array($first) && isset($first['operator']) && $first['operator'] == 'not') {
$operant = array_shift($args);
$operant = $context->resolve($operant);
return !($operant);
}
case 3 :
list($op, $right) = $args;
$right = $context->resolve($right);
return call_user_func(array("Evaluator", $op['operator']), $first, $right);
default:
return false;
}
}
}
/**
* $type of token, Block | Variable
*/
class H2o_Token {
function __construct ($type, $content, $position) {
$this->type = $type;
$this->content = $content;
$this->result='';
$this->position = $position;
}
function write($content){
$this->result= $content;
}
}
/**
* a token stream
*/
class TokenStream {
var $pushed;
var $stream;
var $closed;
var $c;
function __construct() {
$this->pushed = array();
$this->stream = array();
$this->closed = false;
}
function pop() {
if (count($this->pushed))
return array_pop($this->pushed);
return array_pop($this->stream);
}
function feed($type, $contents, $position) {
if ($this->closed)
throw new Exception('cannot feed closed stream');
$this->stream[] = new H2o_Token($type, $contents, $position);
}
function push($token) {
if (is_null($token))
throw new Exception('cannot push NULL');
if ($this->closed)
$this->pushed[] = $token;
else
$this->stream[] = $token;
}
function close() {
if ($this->closed)
new Exception('cannot close already closed stream');
$this->closed = true;
$this->stream = array_reverse($this->stream);
}
function isClosed() {
return $this->closed;
}
function current() {
return $this->c ;
}
function next() {
return $this->c = $this->pop();
}
}
class H2o_Info {
var $h2o_safe = array('filters', 'extensions', 'tags');
var $name = 'H2o Template engine';
var $description = "Django inspired template system";
var $version = H2O_VERSION;
function filters() {
return array_keys(h2o::$filters);
}
function tags() {
return array_keys(h2o::$tags);
}
function extensions() {
return array_keys(h2o::$extensions);
}
}
/**
* Functions
*/
function sym_to_str($string) {
return substr($string, 1);
}
function is_sym($string) {
return isset($string[0]) && $string[0] === ':';
}
function symbol($string) {
return ':'.$string;
}
function strip_regex($regex, $delimiter = '/') {
return substr($regex, 1, strrpos($regex, $delimiter)-1);
}
?>
<?php
class StreamWriter {
var $buffer = array();
var $close;
function __construct() {
$this->close = false;
}
function write($data) {
if ($this->close)
new Exception('tried to write to closed stream');
$this->buffer[] = $data;
}
function close() {
$this->close = true;
return implode('', $this->buffer);
}
}
class Evaluator {
static function gt($l, $r) { return $l > $r; }
static function ge($l, $r) { return $l >= $r; }
static function lt($l, $r) { return $l < $r; }
static function le($l, $r) { return $l <= $r; }
static function eq($l, $r) { return $l == $r; }
static function ne($l, $r) { return $l != $r; }
static function not_($bool) { return !$bool; }
static function and_($l, $r) { return ($l && $r); }
static function or_($l, $r) { return ($l && $r); }
# Currently only support single expression with no preceddence ,no boolean expression
# [expression] = [optional binary] ? operant [ optional compare operant]
# [operant] = variable|string|numeric|boolean
# [compare] = > | < | == | >= | <=
# [binary] = not | !
static function exec($args, $context) {
$argc = count($args);
$first = array_shift($args);
$first = $context->resolve($first);
switch ($argc) {
case 1 :
return $first;
case 2 :
if (is_array($first) && isset($first['operator']) && $first['operator'] == 'not') {
$operant = array_shift($args);
$operant = $context->resolve($operant);
return !($operant);
}
case 3 :
list($op, $right) = $args;
$right = $context->resolve($right);
return call_user_func(array("Evaluator", $op['operator']), $first, $right);
default:
return false;
}
}
}
/**
* $type of token, Block | Variable
*/
class H2o_Token {
function __construct ($type, $content, $position) {
$this->type = $type;
$this->content = $content;
$this->result='';
$this->position = $position;
}
function write($content){
$this->result= $content;
}
}
/**
* a token stream
*/
class TokenStream {
var $pushed;
var $stream;
var $closed;
var $c;
function __construct() {
$this->pushed = array();
$this->stream = array();
$this->closed = false;
}
function pop() {
if (count($this->pushed))
return array_pop($this->pushed);
return array_pop($this->stream);
}
function feed($type, $contents, $position) {
if ($this->closed)
throw new Exception('cannot feed closed stream');
$this->stream[] = new H2o_Token($type, $contents, $position);
}
function push($token) {
if (is_null($token))
throw new Exception('cannot push NULL');
if ($this->closed)
$this->pushed[] = $token;
else
$this->stream[] = $token;
}
function close() {
if ($this->closed)
new Exception('cannot close already closed stream');
$this->closed = true;
$this->stream = array_reverse($this->stream);
}
function isClosed() {
return $this->closed;
}
function current() {
return $this->c ;
}
function next() {
return $this->c = $this->pop();
}
}
class H2o_Info {
var $h2o_safe = array('filters', 'extensions', 'tags');
var $name = 'H2o Template engine';
var $description = "Django inspired template system";
var $version = H2O_VERSION;
function filters() {
return array_keys(h2o::$filters);
}
function tags() {
return array_keys(h2o::$tags);
}
function extensions() {
return array_keys(h2o::$extensions);
}
}
/**
* Functions
*/
function sym_to_str($string) {
return substr($string, 1);
}
function is_sym($string) {
return isset($string[0]) && $string[0] === ':';
}
function symbol($string) {
return ':'.$string;
}
function strip_regex($regex, $delimiter = '/') {
return substr($regex, 1, strrpos($regex, $delimiter)-1);
}
?>

View File

@@ -1,10 +1,10 @@
<?php
# Errors
class H2o_Error extends Exception {}
class ParseError extends H2o_Error {}
class TemplateNotFound extends H2o_Error {}
class TemplateSyntaxError extends H2o_Error {}
<?php
# Errors
class H2o_Error extends Exception {}
class ParseError extends H2o_Error {}
class TemplateNotFound extends H2o_Error {}
class TemplateSyntaxError extends H2o_Error {}
?>

View File

@@ -1,369 +1,369 @@
<?php
class FilterCollection {};
class CoreFilters extends FilterCollection {
static function first($value) {
return $value[0];
}
static function last($value) {
return $value[count($value) - 1];
}
static function join($value, $delimiter = ', ') {
return join($delimiter, $value);
}
static function length($value) {
return count($value);
}
static function urlencode($data) {
if (is_array($data)) {
$result;
foreach ($data as $name => $value) {
$result .= $name.'='.urlencode($value).'&'.$querystring;
}
$querystring = substr($result, 0, strlen($result)-1);
return htmlspecialchars($result);
} else {
return urlencode($data);
}
}
static function hyphenize ($string) {
$rules = array('/[^\w\s-]+/'=>'','/\s+/'=>'-', '/-{2,}/'=>'-');
$string = preg_replace(array_keys($rules), $rules, trim($string));
return $string = trim(strtolower($string));
}
static function urlize( $string, $truncate = false ) {
$reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
preg_match_all($reg_exUrl, $string, $matches);
$usedPatterns = array();
foreach($matches[0] as $pattern){
if(!array_key_exists($pattern, $usedPatterns)){
$usedPatterns[$pattern]=true;
$string = str_replace($pattern, "<a href=\"{$pattern}\" rel=\"nofollow\">{$pattern}</a>", $string);
}
}
$reg_exEmail = "/[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}/";
preg_match_all($reg_exEmail, $string, $matches);
$usedPatterns = array();
foreach($matches[0] as $pattern){
if(!array_key_exists($pattern, $usedPatterns)){
$usedPatterns[$pattern]=true;
$string = str_replace($pattern, "<a href=\"mailto:{$pattern}\">{$pattern}</a>", $string);
}
}
return $string;
}
static function set_default($object, $default) {
return !$object ? $default : $object;
}
}
class StringFilters extends FilterCollection {
static function humanize($string) {
$string = preg_replace('/\s+/', ' ', trim(preg_replace('/[^A-Za-z0-9()!,?$]+/', ' ', $string)));
return capfirst($string);
}
static function capitalize($string) {
return ucwords(strtolower($string)) ;
}
static function titlize($string) {
return self::capitalize($string);
}
static function capfirst($string) {
$string = strtolower($string);
return strtoupper($string{0}). substr($string, 1, strlen($string));
}
static function tighten_space($value) {
return preg_replace("/\s{2,}/", ' ', $value);
}
static function escape($value, $attribute = false) {
return htmlspecialchars($value, $attribute ? ENT_QUOTES : ENT_NOQUOTES);
}
static function escapejson($value) {
// The standard django escapejs converts all non-ascii characters into hex codes.
// This function encodes the entire data structure, and strings get quotes around them.
return json_encode($value);
}
static function force_escape($value, $attribute = false) {
return self::escape($value, $attribute);
}
static function e($value, $attribute = false) {
return self::escape($value, $attribute);
}
static function safe($value) {
return $value;
}
static function truncate ($string, $max = 50, $ends = '...') {
return (strlen($string) > $max ? substr($string, 0, $max).$ends : $string);
}
static function limitwords($text, $limit = 50, $ends = '...') {
if (strlen($text) > $limit) {
$words = str_word_count($text, 2);
$pos = array_keys($words);
if (isset($pos[$limit])) {
$text = substr($text, 0, $pos[$limit]) . $ends;
}
}
return $text;
}
}
class NumberFilters extends FilterCollection {
static function filesize ($bytes, $round = 1) {
if ($bytes === 0)
return '0 bytes';
elseif ($bytes === 1)
return '1 byte';
$units = array(
'bytes' => pow(2, 0), 'kB' => pow(2, 10),
'BM' => pow(2, 20), 'GB' => pow(2, 30),
'TB' => pow(2, 40), 'PB' => pow(2, 50),
'EB' => pow(2, 60), 'ZB' => pow(2, 70)
);
$lastUnit = 'bytes';
foreach ($units as $unitName => $unitFactor) {
if ($bytes >= $unitFactor) {
$lastUnit = $unitName;
} else {
$number = round( $bytes / $units[$lastUnit], $round );
return number_format($number) . ' ' . $lastUnit;
}
}
}
static function currency($amount, $currency = 'USD', $precision = 2, $negateWithParentheses = false) {
$definition = array(
'EUR' => array('<27>','.',','), 'GBP' => '<27>', 'JPY' => '<27>',
'USD'=>'$', 'AU' => '$', 'CAN' => '$'
);
$negative = false;
$separator = ',';
$decimals = '.';
$currency = strtoupper($currency);
// Is negative
if (strpos('-', $amount) !== false) {
$negative = true;
$amount = str_replace("-","",$amount);
}
$amount = (float) $amount;
if (!$negative) {
$negative = $amount < 0;
}
if ($negateWithParentheses) {
$amount = abs($amount);
}
// Get rid of negative zero
$zero = round(0, $precision);
if (round($amount, $precision) === $zero) {
$amount = $zero;
}
if (isset($definition[$currency])) {
$symbol = $definition[$currency];
if (is_array($symbol))
@list($symbol, $separator, $decimals) = $symbol;
} else {
$symbol = $currency;
}
$amount = number_format($amount, $precision, $decimals, $separator);
return $negateWithParentheses ? "({$symbol}{$amount})" : "{$symbol}{$amount}";
}
}
class HtmlFilters extends FilterCollection {
static function base_url($url, $options = array()) {
return $url;
}
static function asset_url($url, $options = array()) {
return self::base_url($url, $options);
}
static function image_tag($url, $options = array()) {
$attr = self::htmlAttribute(array('alt','width','height','border'), $options);
return sprintf('<img src="%s" %s/>', $url, $attr);
}
static function css_tag($url, $options = array()) {
$attr = self::htmlAttribute(array('media'), $options);
return sprintf('<link rel="stylesheet" href="%s" type="text/css" %s />', $url, $attr);
}
static function script_tag($url, $options = array()) {
return sprintf('<script src="%s" type="text/javascript"></script>', $url);
}
static function links_to($text, $url, $options = array()) {
$attrs = self::htmlAttribute(array('ref'), $options);
$url = self::base_url($url, $options);
return sprintf('<a href="%s" %s>%s</a>', $url, $attrs, $text);
}
static function links_with ($url, $text, $options = array()) {
return self::links_to($text, $url, $options);
}
static function strip_tags($text) {
$text = preg_replace(array('/</', '/>/'), array(' <', '> '),$text);
return strip_tags($text);
}
static function linebreaks($value, $format = 'p') {
if ($format === 'br')
return HtmlFilters::nl2br($value);
return HtmlFilters::nl2pbr($value);
}
static function nl2br($value) {
return str_replace("\n", "<br />\n", $value);
}
static function nl2pbr($value) {
$result = array();
$parts = preg_split('/(\r?\n){2,}/m', $value);
foreach ($parts as $part) {
array_push($result, '<p>' . HtmlFilters::nl2br($part) . '</p>');
}
return implode("\n", $result);
}
protected static function htmlAttribute($attrs = array(), $data = array()) {
$attrs = self::extract(array_merge(array('id', 'class', 'title', "style"), $attrs), $data);
$result = array();
foreach ($attrs as $name => $value) {
$result[] = "{$name}=\"{$value}\"";
}
return join(' ', $result);
}
protected static function extract($attrs = array(), $data=array()) {
$result = array();
if (empty($data)) return array();
foreach($data as $k => $e) {
if (in_array($k, $attrs)) $result[$k] = $e;
}
return $result;
}
}
class DatetimeFilters extends FilterCollection {
static function date($time, $format = 'jS F Y H:i') {
if ($time instanceof DateTime)
$time = (int) $time->format('U');
if (!is_numeric($time))
$time = strtotime($time);
return date($format, $time);
}
static function relative_time($timestamp, $format = 'g:iA') {
if ($timestamp instanceof DateTime)
$timestamp = (int) $timestamp->format('U');
$timestamp = is_numeric($timestamp) ? $timestamp: strtotime($timestamp);
$time = mktime(0, 0, 0);
$delta = time() - $timestamp;
$string = '';
if ($timestamp < $time - 86400) {
return date("F j, Y, g:i a", $timestamp);
}
if ($delta > 86400 && $timestamp < $time) {
return "Yesterday at " . date("g:i a", $timestamp);
}
if ($delta > 7200)
$string .= floor($delta / 3600) . " hours, ";
else if ($delta > 3660)
$string .= "1 hour, ";
else if ($delta >= 3600)
$string .= "1 hour ";
$delta %= 3600;
if ($delta > 60)
$string .= floor($delta / 60) . " minutes ";
else
$string .= $delta . " seconds ";
return "$string ago";
}
static function relative_date($time) {
if ($time instanceof DateTime)
$time = (int) $time->format('U');
$time = is_numeric($time) ? $time: strtotime($time);
$today = strtotime(date('M j, Y'));
$reldays = ($time - $today)/86400;
if ($reldays >= 0 && $reldays < 1)
return 'today';
else if ($reldays >= 1 && $reldays < 2)
return 'tomorrow';
else if ($reldays >= -1 && $reldays < 0)
return 'yesterday';
if (abs($reldays) < 7) {
if ($reldays > 0) {
$reldays = floor($reldays);
return 'in ' . $reldays . ' day' . ($reldays != 1 ? 's' : '');
} else {
$reldays = abs(floor($reldays));
return $reldays . ' day' . ($reldays != 1 ? 's' : '') . ' ago';
}
}
if (abs($reldays) < 182)
return date('l, F j',$time ? $time : time());
else
return date('l, F j, Y',$time ? $time : time());
}
static function relative_datetime($time) {
$date = self::relative_date($time);
if ($date === 'today')
return self::relative_time($time);
return $date;
}
}
/* Ultizie php funciton as Filters */
h2o::addFilter(array('md5', 'sha1', 'numberformat'=>'number_format', 'wordwrap', 'trim', 'upper' => 'strtoupper', 'lower' => 'strtolower'));
/* Add filter collections */
h2o::addFilter(array('CoreFilters', 'StringFilters', 'NumberFilters', 'DatetimeFilters', 'HtmlFilters'));
/* Alias default to set_default */
h2o::addFilter('default', array('CoreFilters', 'set_default'));
?>
<?php
class FilterCollection {};
class CoreFilters extends FilterCollection {
static function first($value) {
return $value[0];
}
static function last($value) {
return $value[count($value) - 1];
}
static function join($value, $delimiter = ', ') {
return join($delimiter, $value);
}
static function length($value) {
return count($value);
}
static function urlencode($data) {
if (is_array($data)) {
$result;
foreach ($data as $name => $value) {
$result .= $name.'='.urlencode($value).'&'.$querystring;
}
$querystring = substr($result, 0, strlen($result)-1);
return htmlspecialchars($result);
} else {
return urlencode($data);
}
}
static function hyphenize ($string) {
$rules = array('/[^\w\s-]+/'=>'','/\s+/'=>'-', '/-{2,}/'=>'-');
$string = preg_replace(array_keys($rules), $rules, trim($string));
return $string = trim(strtolower($string));
}
static function urlize( $string, $truncate = false ) {
$reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
preg_match_all($reg_exUrl, $string, $matches);
$usedPatterns = array();
foreach($matches[0] as $pattern){
if(!array_key_exists($pattern, $usedPatterns)){
$usedPatterns[$pattern]=true;
$string = str_replace($pattern, "<a href=\"{$pattern}\" rel=\"nofollow\">{$pattern}</a>", $string);
}
}
$reg_exEmail = "/[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}/";
preg_match_all($reg_exEmail, $string, $matches);
$usedPatterns = array();
foreach($matches[0] as $pattern){
if(!array_key_exists($pattern, $usedPatterns)){
$usedPatterns[$pattern]=true;
$string = str_replace($pattern, "<a href=\"mailto:{$pattern}\">{$pattern}</a>", $string);
}
}
return $string;
}
static function set_default($object, $default) {
return !$object ? $default : $object;
}
}
class StringFilters extends FilterCollection {
static function humanize($string) {
$string = preg_replace('/\s+/', ' ', trim(preg_replace('/[^A-Za-z0-9()!,?$]+/', ' ', $string)));
return capfirst($string);
}
static function capitalize($string) {
return ucwords(strtolower($string)) ;
}
static function titlize($string) {
return self::capitalize($string);
}
static function capfirst($string) {
$string = strtolower($string);
return strtoupper($string{0}). substr($string, 1, strlen($string));
}
static function tighten_space($value) {
return preg_replace("/\s{2,}/", ' ', $value);
}
static function escape($value, $attribute = false) {
return htmlspecialchars($value, $attribute ? ENT_QUOTES : ENT_NOQUOTES);
}
static function escapejson($value) {
// The standard django escapejs converts all non-ascii characters into hex codes.
// This function encodes the entire data structure, and strings get quotes around them.
return json_encode($value);
}
static function force_escape($value, $attribute = false) {
return self::escape($value, $attribute);
}
static function e($value, $attribute = false) {
return self::escape($value, $attribute);
}
static function safe($value) {
return $value;
}
static function truncate ($string, $max = 50, $ends = '...') {
return (strlen($string) > $max ? substr($string, 0, $max).$ends : $string);
}
static function limitwords($text, $limit = 50, $ends = '...') {
if (strlen($text) > $limit) {
$words = str_word_count($text, 2);
$pos = array_keys($words);
if (isset($pos[$limit])) {
$text = substr($text, 0, $pos[$limit]) . $ends;
}
}
return $text;
}
}
class NumberFilters extends FilterCollection {
static function filesize ($bytes, $round = 1) {
if ($bytes === 0)
return '0 bytes';
elseif ($bytes === 1)
return '1 byte';
$units = array(
'bytes' => pow(2, 0), 'kB' => pow(2, 10),
'BM' => pow(2, 20), 'GB' => pow(2, 30),
'TB' => pow(2, 40), 'PB' => pow(2, 50),
'EB' => pow(2, 60), 'ZB' => pow(2, 70)
);
$lastUnit = 'bytes';
foreach ($units as $unitName => $unitFactor) {
if ($bytes >= $unitFactor) {
$lastUnit = $unitName;
} else {
$number = round( $bytes / $units[$lastUnit], $round );
return number_format($number) . ' ' . $lastUnit;
}
}
}
static function currency($amount, $currency = 'USD', $precision = 2, $negateWithParentheses = false) {
$definition = array(
'EUR' => array('<27>','.',','), 'GBP' => '<27>', 'JPY' => '<27>',
'USD'=>'$', 'AU' => '$', 'CAN' => '$'
);
$negative = false;
$separator = ',';
$decimals = '.';
$currency = strtoupper($currency);
// Is negative
if (strpos('-', $amount) !== false) {
$negative = true;
$amount = str_replace("-","",$amount);
}
$amount = (float) $amount;
if (!$negative) {
$negative = $amount < 0;
}
if ($negateWithParentheses) {
$amount = abs($amount);
}
// Get rid of negative zero
$zero = round(0, $precision);
if (round($amount, $precision) === $zero) {
$amount = $zero;
}
if (isset($definition[$currency])) {
$symbol = $definition[$currency];
if (is_array($symbol))
@list($symbol, $separator, $decimals) = $symbol;
} else {
$symbol = $currency;
}
$amount = number_format($amount, $precision, $decimals, $separator);
return $negateWithParentheses ? "({$symbol}{$amount})" : "{$symbol}{$amount}";
}
}
class HtmlFilters extends FilterCollection {
static function base_url($url, $options = array()) {
return $url;
}
static function asset_url($url, $options = array()) {
return self::base_url($url, $options);
}
static function image_tag($url, $options = array()) {
$attr = self::htmlAttribute(array('alt','width','height','border'), $options);
return sprintf('<img src="%s" %s/>', $url, $attr);
}
static function css_tag($url, $options = array()) {
$attr = self::htmlAttribute(array('media'), $options);
return sprintf('<link rel="stylesheet" href="%s" type="text/css" %s />', $url, $attr);
}
static function script_tag($url, $options = array()) {
return sprintf('<script src="%s" type="text/javascript"></script>', $url);
}
static function links_to($text, $url, $options = array()) {
$attrs = self::htmlAttribute(array('ref'), $options);
$url = self::base_url($url, $options);
return sprintf('<a href="%s" %s>%s</a>', $url, $attrs, $text);
}
static function links_with ($url, $text, $options = array()) {
return self::links_to($text, $url, $options);
}
static function strip_tags($text) {
$text = preg_replace(array('/</', '/>/'), array(' <', '> '),$text);
return strip_tags($text);
}
static function linebreaks($value, $format = 'p') {
if ($format === 'br')
return HtmlFilters::nl2br($value);
return HtmlFilters::nl2pbr($value);
}
static function nl2br($value) {
return str_replace("\n", "<br />\n", $value);
}
static function nl2pbr($value) {
$result = array();
$parts = preg_split('/(\r?\n){2,}/m', $value);
foreach ($parts as $part) {
array_push($result, '<p>' . HtmlFilters::nl2br($part) . '</p>');
}
return implode("\n", $result);
}
protected static function htmlAttribute($attrs = array(), $data = array()) {
$attrs = self::extract(array_merge(array('id', 'class', 'title', "style"), $attrs), $data);
$result = array();
foreach ($attrs as $name => $value) {
$result[] = "{$name}=\"{$value}\"";
}
return join(' ', $result);
}
protected static function extract($attrs = array(), $data=array()) {
$result = array();
if (empty($data)) return array();
foreach($data as $k => $e) {
if (in_array($k, $attrs)) $result[$k] = $e;
}
return $result;
}
}
class DatetimeFilters extends FilterCollection {
static function date($time, $format = 'jS F Y H:i') {
if ($time instanceof DateTime)
$time = (int) $time->format('U');
if (!is_numeric($time))
$time = strtotime($time);
return date($format, $time);
}
static function relative_time($timestamp, $format = 'g:iA') {
if ($timestamp instanceof DateTime)
$timestamp = (int) $timestamp->format('U');
$timestamp = is_numeric($timestamp) ? $timestamp: strtotime($timestamp);
$time = mktime(0, 0, 0);
$delta = time() - $timestamp;
$string = '';
if ($timestamp < $time - 86400) {
return date("F j, Y, g:i a", $timestamp);
}
if ($delta > 86400 && $timestamp < $time) {
return "Yesterday at " . date("g:i a", $timestamp);
}
if ($delta > 7200)
$string .= floor($delta / 3600) . " hours, ";
else if ($delta > 3660)
$string .= "1 hour, ";
else if ($delta >= 3600)
$string .= "1 hour ";
$delta %= 3600;
if ($delta > 60)
$string .= floor($delta / 60) . " minutes ";
else
$string .= $delta . " seconds ";
return "$string ago";
}
static function relative_date($time) {
if ($time instanceof DateTime)
$time = (int) $time->format('U');
$time = is_numeric($time) ? $time: strtotime($time);
$today = strtotime(date('M j, Y'));
$reldays = ($time - $today)/86400;
if ($reldays >= 0 && $reldays < 1)
return 'today';
else if ($reldays >= 1 && $reldays < 2)
return 'tomorrow';
else if ($reldays >= -1 && $reldays < 0)
return 'yesterday';
if (abs($reldays) < 7) {
if ($reldays > 0) {
$reldays = floor($reldays);
return 'in ' . $reldays . ' day' . ($reldays != 1 ? 's' : '');
} else {
$reldays = abs(floor($reldays));
return $reldays . ' day' . ($reldays != 1 ? 's' : '') . ' ago';
}
}
if (abs($reldays) < 182)
return date('l, F j',$time ? $time : time());
else
return date('l, F j, Y',$time ? $time : time());
}
static function relative_datetime($time) {
$date = self::relative_date($time);
if ($date === 'today')
return self::relative_time($time);
return $date;
}
}
/* Ultizie php funciton as Filters */
h2o::addFilter(array('md5', 'sha1', 'numberformat'=>'number_format', 'wordwrap', 'trim', 'upper' => 'strtoupper', 'lower' => 'strtolower'));
/* Add filter collections */
h2o::addFilter(array('CoreFilters', 'StringFilters', 'NumberFilters', 'DatetimeFilters', 'HtmlFilters'));
/* Alias default to set_default */
h2o::addFilter('default', array('CoreFilters', 'set_default'));
?>

View File

@@ -1,290 +1,290 @@
<?php
/**
*
* @author taylor.luk
* @todo FileLoader need more test coverage
*/
class H2o_Loader {
public $parser;
public $runtime;
public $cached = false;
protected $cache = false;
public $searchpath = false;
function read($filename) {}
function cache_read($file, $object, $ttl = 3600) {}
}
class H2o_File_Loader extends H2o_Loader {
function __construct($searchpath, $options = array()) {
// if (is_file($searchpath)) {
// $searthpath = dirname($searchpath).DS;
// }
// if (!is_dir($searchpath))
// throw new TemplateNotFound($filename);
//
if (!is_array($searchpath))
throw new Exception("searchpath must be an array");
$this->searchpath = (array) $searchpath;
$this->setOptions($options);
}
function setOptions($options = array()) {
if (isset($options['cache']) && $options['cache']) {
$this->cache = h2o_cache($options);
}
}
function read($filename) {
if (!is_file($filename))
$filename = $this->get_template_path($this->searchpath,$filename);
if (is_file($filename)) {
$source = file_get_contents($filename);
return $this->runtime->parse($source);
} else {
throw new TemplateNotFound($filename);
}
}
function get_template_path($search_path, $filename){
for ($i=0 ; $i < count($search_path) ; $i++)
{
if(file_exists($search_path[$i] . $filename)) {
$filename = $search_path[$i] . $filename;
return $filename;
break;
} else {
continue;
}
}
throw new Exception('TemplateNotFound - Looked for template: ' . $filename);
}
function read_cache($filename) {
if (!$this->cache){
$filename = $this->get_template_path($this->searchpath,$filename);
return $this->read($filename);
}
if (!is_file($filename)){
$filename = $this->get_template_path($this->searchpath,$filename);
}
$filename = realpath($filename);
$cache = md5($filename);
$object = $this->cache->read($cache);
$this->cached = $object && !$this->expired($object);
if (!$this->cached) {
$nodelist = $this->read($filename);
$object = (object) array(
'filename' => $filename,
'content' => serialize($nodelist),
'created' => time(),
'templates' => $nodelist->parser->storage['templates'],
'included' => $nodelist->parser->storage['included'] + array_values(h2o::$extensions)
);
$this->cache->write($cache, $object);
} else {
foreach($object->included as $ext => $file) {
include_once (h2o::$extensions[$ext] = $file);
}
}
return unserialize($object->content);
}
function flush_cache() {
$this->cache->flush();
}
function expired($object) {
if (!$object) return false;
$files = array_merge(array($object->filename), $object->templates);
foreach ($files as $file) {
if (!is_file($file))
$file = $this->get_template_path($this->searchpath, $file);
if ($object->created < filemtime($file))
return true;
}
return false;
}
}
function file_loader($file) {
return new H2o_File_Loader($file);
}
class H2o_Hash_Loader {
function __construct($scope, $options = array()) {
$this->scope = $scope;
}
function setOptions() {}
function read($file) {
if (!isset($this->scope[$file]))
throw new TemplateNotFound;
return $this->runtime->parse($this->scope[$file], $file);
}
function read_cache($file) {
return $this->read($file);
}
}
function hash_loader($hash = array()) {
return new H2o_Hash_Loader($hash);
}
/**
* Cache subsystem
*
*/
function h2o_cache($options = array()) {
$type = $options['cache'];
$className = "H2o_".ucwords($type)."_Cache";
if (class_exists($className, false)) {
return new $className($options);
}
return false;
}
class H2o_File_Cache {
var $ttl = 3600;
var $prefix = 'h2o_';
function __construct($options = array()) {
if (isset($options['cache_dir']) && is_writable($options['cache_dir'])) {
$path = $options['cache_dir'];
} else {
$path = dirname($tmp = tempnam(uniqid(rand(), true), ''));
if (file_exists($tmp)) unlink($tmp);
}
if (isset($options['cache_ttl'])) {
$this->ttl = $options['cache_ttl'];
}
if(isset($options['cache_prefix'])) {
$this->prefix = $options['cache_prefix'];
}
$this->path = realpath($path). DS;
}
function read($filename) {
if (!file_exists($this->path . $this->prefix. $filename))
return false;
$content = file_get_contents($this->path . $this->prefix. $filename);
$expires = (int)substr($content, 0, 10);
if (time() >= $expires)
return false;
return unserialize(trim(substr($content, 10)));
}
function write($filename, &$object) {
$expires = time() + $this->ttl;
$content = $expires . serialize($object);
return file_put_contents($this->path . $this->prefix. $filename, $content);
}
function flush() {
foreach (glob($this->path. $this->prefix. '*') as $file) {
@unlink($file);
}
}
}
class H2o_Apc_Cache {
var $ttl = 3600;
var $prefix = 'h2o_';
function __construct($options = array()) {
if (!function_exists('apc_add'))
throw new Exception('APC extension needs to be loaded to use APC cache');
if (isset($options['cache_ttl'])) {
$this->ttl = $options['cache_ttl'];
}
if(isset($options['cache_prefix'])) {
$this->prefix = $options['cache_prefix'];
}
}
function read($filename) {
return apc_fetch($this->prefix.$filename);
}
function write($filename, $object) {
return apc_store($this->prefix.$filename, $object, $this->ttl);
}
function flush() {
return apc_clear_cache('user');
}
}
class H2o_Memcache_Cache {
var $ttl = 3600;
var $prefix = 'h2o_';
/**
* @var host default is file socket
*/
var $host = 'unix:///tmp/memcached.sock';
var $port = 0;
var $object;
function __construct( $scope, $options = array() ) {
if ( !function_exists( 'memcache_set' ) )
throw new Exception( 'Memcache extension needs to be loaded to use memcache' );
if ( isset( $options['cache_ttl'] ) ) {
$this->ttl = $options['cache_ttl'];
}
if( isset( $options['cache_prefix'] ) ) {
$this->prefix = $options['cache_prefix'];
}
if( isset( $options['host'] ) ) {
$this->host = $options['host'];
}
if( isset( $options['port'] ) ) {
$this->port = $options['port'];
}
$this->object = memcache_connect( $this->host, $this->port );
}
function read( $filename ){
return memcache_get( $this->object, $this->prefix.$filename );
}
function write( $filename, $content ) {
return memcache_set( $this->object,$this->prefix.$filename,$content , MEMCACHE_COMPRESSED,$this->ttl );
}
function flush(){
return memcache_flush( $this->object );
}
<?php
/**
*
* @author taylor.luk
* @todo FileLoader need more test coverage
*/
class H2o_Loader {
public $parser;
public $runtime;
public $cached = false;
protected $cache = false;
public $searchpath = false;
function read($filename) {}
function cache_read($file, $object, $ttl = 3600) {}
}
class H2o_File_Loader extends H2o_Loader {
function __construct($searchpath, $options = array()) {
// if (is_file($searchpath)) {
// $searthpath = dirname($searchpath).DS;
// }
// if (!is_dir($searchpath))
// throw new TemplateNotFound($filename);
//
if (!is_array($searchpath))
throw new Exception("searchpath must be an array");
$this->searchpath = (array) $searchpath;
$this->setOptions($options);
}
function setOptions($options = array()) {
if (isset($options['cache']) && $options['cache']) {
$this->cache = h2o_cache($options);
}
}
function read($filename) {
if (!is_file($filename))
$filename = $this->get_template_path($this->searchpath,$filename);
if (is_file($filename)) {
$source = file_get_contents($filename);
return $this->runtime->parse($source);
} else {
throw new TemplateNotFound($filename);
}
}
function get_template_path($search_path, $filename){
for ($i=0 ; $i < count($search_path) ; $i++)
{
if(file_exists($search_path[$i] . $filename)) {
$filename = $search_path[$i] . $filename;
return $filename;
break;
} else {
continue;
}
}
throw new Exception('TemplateNotFound - Looked for template: ' . $filename);
}
function read_cache($filename) {
if (!$this->cache){
$filename = $this->get_template_path($this->searchpath,$filename);
return $this->read($filename);
}
if (!is_file($filename)){
$filename = $this->get_template_path($this->searchpath,$filename);
}
$filename = realpath($filename);
$cache = md5($filename);
$object = $this->cache->read($cache);
$this->cached = $object && !$this->expired($object);
if (!$this->cached) {
$nodelist = $this->read($filename);
$object = (object) array(
'filename' => $filename,
'content' => serialize($nodelist),
'created' => time(),
'templates' => $nodelist->parser->storage['templates'],
'included' => $nodelist->parser->storage['included'] + array_values(h2o::$extensions)
);
$this->cache->write($cache, $object);
} else {
foreach($object->included as $ext => $file) {
include_once (h2o::$extensions[$ext] = $file);
}
}
return unserialize($object->content);
}
function flush_cache() {
$this->cache->flush();
}
function expired($object) {
if (!$object) return false;
$files = array_merge(array($object->filename), $object->templates);
foreach ($files as $file) {
if (!is_file($file))
$file = $this->get_template_path($this->searchpath, $file);
if ($object->created < filemtime($file))
return true;
}
return false;
}
}
function file_loader($file) {
return new H2o_File_Loader($file);
}
class H2o_Hash_Loader {
function __construct($scope, $options = array()) {
$this->scope = $scope;
}
function setOptions() {}
function read($file) {
if (!isset($this->scope[$file]))
throw new TemplateNotFound;
return $this->runtime->parse($this->scope[$file], $file);
}
function read_cache($file) {
return $this->read($file);
}
}
function hash_loader($hash = array()) {
return new H2o_Hash_Loader($hash);
}
/**
* Cache subsystem
*
*/
function h2o_cache($options = array()) {
$type = $options['cache'];
$className = "H2o_".ucwords($type)."_Cache";
if (class_exists($className, false)) {
return new $className($options);
}
return false;
}
class H2o_File_Cache {
var $ttl = 3600;
var $prefix = 'h2o_';
function __construct($options = array()) {
if (isset($options['cache_dir']) && is_writable($options['cache_dir'])) {
$path = $options['cache_dir'];
} else {
$path = dirname($tmp = tempnam(uniqid(rand(), true), ''));
if (file_exists($tmp)) unlink($tmp);
}
if (isset($options['cache_ttl'])) {
$this->ttl = $options['cache_ttl'];
}
if(isset($options['cache_prefix'])) {
$this->prefix = $options['cache_prefix'];
}
$this->path = realpath($path). DS;
}
function read($filename) {
if (!file_exists($this->path . $this->prefix. $filename))
return false;
$content = file_get_contents($this->path . $this->prefix. $filename);
$expires = (int)substr($content, 0, 10);
if (time() >= $expires)
return false;
return unserialize(trim(substr($content, 10)));
}
function write($filename, &$object) {
$expires = time() + $this->ttl;
$content = $expires . serialize($object);
return file_put_contents($this->path . $this->prefix. $filename, $content);
}
function flush() {
foreach (glob($this->path. $this->prefix. '*') as $file) {
@unlink($file);
}
}
}
class H2o_Apc_Cache {
var $ttl = 3600;
var $prefix = 'h2o_';
function __construct($options = array()) {
if (!function_exists('apc_add'))
throw new Exception('APC extension needs to be loaded to use APC cache');
if (isset($options['cache_ttl'])) {
$this->ttl = $options['cache_ttl'];
}
if(isset($options['cache_prefix'])) {
$this->prefix = $options['cache_prefix'];
}
}
function read($filename) {
return apc_fetch($this->prefix.$filename);
}
function write($filename, $object) {
return apc_store($this->prefix.$filename, $object, $this->ttl);
}
function flush() {
return apc_clear_cache('user');
}
}
class H2o_Memcache_Cache {
var $ttl = 3600;
var $prefix = 'h2o_';
/**
* @var host default is file socket
*/
var $host = 'unix:///tmp/memcached.sock';
var $port = 0;
var $object;
function __construct( $scope, $options = array() ) {
if ( !function_exists( 'memcache_set' ) )
throw new Exception( 'Memcache extension needs to be loaded to use memcache' );
if ( isset( $options['cache_ttl'] ) ) {
$this->ttl = $options['cache_ttl'];
}
if( isset( $options['cache_prefix'] ) ) {
$this->prefix = $options['cache_prefix'];
}
if( isset( $options['host'] ) ) {
$this->host = $options['host'];
}
if( isset( $options['port'] ) ) {
$this->port = $options['port'];
}
$this->object = memcache_connect( $this->host, $this->port );
}
function read( $filename ){
return memcache_get( $this->object, $this->prefix.$filename );
}
function write( $filename, $content ) {
return memcache_set( $this->object,$this->prefix.$filename,$content , MEMCACHE_COMPRESSED,$this->ttl );
}
function flush(){
return memcache_flush( $this->object );
}
}

View File

@@ -1,84 +1,84 @@
<?php
/*
Nodes
*/
class H2o_Node {
var $position;
function __construct($argstring) {}
function render($context, $stream) {}
}
class NodeList extends H2o_Node implements IteratorAggregate {
var $parser;
var $list;
function __construct(&$parser, $initial = null, $position = 0) {
$this->parser = $parser;
if (is_null($initial))
$initial = array();
$this->list = $initial;
$this->position = $position;
}
function render($context, $stream) {
foreach($this->list as $node) {
$node->render($context, $stream);
}
}
function append($node) {
array_push($this->list, $node);
}
function extend($nodes) {
array_merge($this->list, $nodes);
}
function getLength() {
return count($this->list);
}
function getIterator() {
return new ArrayIterator( $this->list );
}
}
class VariableNode extends H2o_Node {
private $filters = array();
var $variable;
function __construct($variable, $filters, $position = 0) {
if (!empty($filters))
$this->filters = $filters;
$this->variable = $variable;
}
function render($context, $stream) {
$value = $context->resolve($this->variable);
$value = $context->escape($value, $this->variable);
$stream->write($value);
}
}
class CommentNode extends H2o_Node {}
class TextNode extends H2o_Node {
var $content;
function __construct($content, $position = 0) {
$this->content = $content;
$this->position = $position;
}
function render($context, $stream) {
$stream->write($this->content);
}
function is_blank() {
return strlen(trim($this->content));
}
}
<?php
/*
Nodes
*/
class H2o_Node {
var $position;
function __construct($argstring) {}
function render($context, $stream) {}
}
class NodeList extends H2o_Node implements IteratorAggregate {
var $parser;
var $list;
function __construct(&$parser, $initial = null, $position = 0) {
$this->parser = $parser;
if (is_null($initial))
$initial = array();
$this->list = $initial;
$this->position = $position;
}
function render($context, $stream) {
foreach($this->list as $node) {
$node->render($context, $stream);
}
}
function append($node) {
array_push($this->list, $node);
}
function extend($nodes) {
array_merge($this->list, $nodes);
}
function getLength() {
return count($this->list);
}
function getIterator() {
return new ArrayIterator( $this->list );
}
}
class VariableNode extends H2o_Node {
private $filters = array();
var $variable;
function __construct($variable, $filters, $position = 0) {
if (!empty($filters))
$this->filters = $filters;
$this->variable = $variable;
}
function render($context, $stream) {
$value = $context->resolve($this->variable);
$value = $context->escape($value, $this->variable);
$stream->write($value);
}
}
class CommentNode extends H2o_Node {}
class TextNode extends H2o_Node {
var $content;
function __construct($content, $position = 0) {
$this->content = $content;
$this->position = $position;
}
function render($context, $stream) {
$stream->write($this->content);
}
function is_blank() {
return strlen(trim($this->content));
}
}
?>

View File

@@ -1,290 +1,290 @@
<?php
class H2o_Lexer {
function __construct($options = array()) {
$this->options = $options;
$trim = '';
if ($this->options['TRIM_TAGS'])
$trim = '(?:\r?\n)?';
$this->pattern = ('/\G(.*?)(?:' .
preg_quote($this->options['BLOCK_START']). '(.*?)' .preg_quote($this->options['BLOCK_END']) . $trim . '|' .
preg_quote($this->options['VARIABLE_START']). '(.*?)' .preg_quote($this->options['VARIABLE_END']) . '|' .
preg_quote($this->options['COMMENT_START']). '(.*?)' .preg_quote($this->options['COMMENT_END']) . $trim . ')/sm'
);
}
function tokenize($source) {
$result = new TokenStream;
$pos = 0;
$matches = array();
preg_match_all($this->pattern, $source, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
if ($match[1])
$result->feed('text', $match[1], $pos);
$tagpos = $pos + strlen($match[1]);
if ($match[2])
$result->feed('block', trim($match[2]), $tagpos);
elseif ($match[3])
$result->feed('variable', trim($match[3]), $tagpos);
elseif ($match[4])
$result->feed('comment', trim($match[4]), $tagpos);
$pos += strlen($match[0]);
}
if ($pos < strlen($source)){
$result->feed('text', substr($source, $pos), $pos);
}
$result->close();
return $result;
}
}
class H2o_Parser {
var $first;
var $storage = array();
var $filename;
var $runtime;
function __construct($source, $filename, $runtime, $options) {
$this->options = $options;
//$this->source = $source;
$this->runtime = $runtime;
$this->filename = $filename;
$this->first = true;
$this->lexer = new H2o_Lexer($options);
$this->tokenstream = $this->lexer->tokenize($source);
$this->storage = array(
'blocks' => array(),
'templates' => array(),
'included' => array()
);
}
function &parse() {
$until = func_get_args();
$nodelist = new NodeList($this);
while($token = $this->tokenstream->next()) {
//$token = $this->tokenstream->current();
switch($token->type) {
case 'text' :
$node = new TextNode($token->content, $token->position);
break;
case 'variable' :
$args = H2o_Parser::parseArguments($token->content, $token->position);
$variable = array_shift($args);
$filters = $args;
$node = new VariableNode($variable, $filters, $token->position);
break;
case 'comment' :
$node = new CommentNode($token->content);
break;
case 'block' :
if (in_array($token->content, $until)) {
$this->token = $token;
return $nodelist;
}
$temp = preg_split('/\s+/',$token->content, 2);
$name = $temp[0];
$args = (count($temp) > 1 ? $temp[1] : null);
$node = H2o::createTag($name, $args, $this, $token->position);
$this->token = $token;
}
$this->searching = join(',',$until);
$this->first = false;
$nodelist->append($node);
}
if ($until) {
throw new TemplateSyntaxError('Unclose tag, expecting '. $until[0]);
}
return $nodelist;
}
function skipTo($until) {
$this->parse($until);
return null;
}
# Parse arguments
static function parseArguments($source = null, $fpos = 0){
$parser = new ArgumentLexer($source, $fpos);
$result = array();
$current_buffer = &$result;
$filter_buffer = array();
$tokens = $parser->parse();
foreach ($tokens as $token) {
list($token, $data) = $token;
if ($token == 'filter_start') {
$filter_buffer = array();
$current_buffer = &$filter_buffer;
}
elseif ($token == 'filter_end') {
if (count($filter_buffer)) {
$i = count($result)-1;
if ( is_array($result[$i]) ) $result[$i]['filters'][] = $filter_buffer;
else $result[$i] = array(0 => $result[$i], 'filters' => array($filter_buffer));
}
$current_buffer = &$result;
}
elseif ($token == 'boolean') {
$current_buffer[] = ($data === 'true'? true : false);
}
elseif ($token == 'name') {
$current_buffer[] = symbol($data);
}
elseif ($token == 'number' || $token == 'string') {
$current_buffer[] = $data;
}
elseif ($token == 'named_argument') {
$last = $current_buffer[count($current_buffer) - 1];
if (!is_array($last))
$current_buffer[] = array();
$namedArgs =& $current_buffer[count($current_buffer) - 1];
list($name,$value) = array_map('trim', explode(':', $data, 2));
# if argument value is variable mark it
$value = self::parseArguments($value);
$namedArgs[$name] = $value[0];
}
elseif( $token == 'operator') {
$current_buffer[] = array('operator'=>$data);
}
}
return $result;
}
}
class H2O_RE {
static $whitespace, $seperator, $parentheses, $pipe, $filter_end, $operator, $boolean, $number, $string, $i18n_string, $name, $named_args;
static function init() {
$r = 'strip_regex';
self::$whitespace = '/\s+/m';
self::$parentheses = '/\(|\)/m';
self::$filter_end = '/;/';
self::$boolean = '/true|false/';
self::$seperator = '/,/';
self::$pipe = '/\|/';
self::$operator = '/\s?(>|<|>=|<=|!=|==|!|and |not |or )\s?/i';
self::$number = '/\d+(\.\d*)?/';
self::$name = '/[a-zA-Z][a-zA-Z0-9-_]*(?:\.[a-zA-Z_0-9][a-zA-Z0-9_-]*)*/';
self::$string = '/(?:
"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)" | # Double Quote string
\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\' # Single Quote String
)/xsm';
self::$i18n_string = "/_\({$r(self::$string)}\) | {$r(self::$string)}/xsm";
self::$named_args = "{
({$r(self::$name)})(?:{$r(self::$whitespace)})?
:
(?:{$r(self::$whitespace)})?({$r(self::$i18n_string)}|{$r(self::$number)}|{$r(self::$name)})
}x";
}
}
H2O_RE::init();
class ArgumentLexer {
private $source;
private $match;
private $pos = 0, $fpos, $eos;
private $operator_map = array(
'!' => 'not', '!='=> 'ne', '==' => 'eq', '>' => 'gt', '<' => 'lt', '<=' => 'le', '>=' => 'ge'
);
function __construct($source, $fpos = 0){
if (!is_null($source))
$this->source = $source;
$this->fpos=$fpos;
}
function parse(){
$result = array();
$filtering = false;
while (!$this->eos()) {
$this->scan(H2O_RE::$whitespace);
if (!$filtering) {
if ($this->scan(H2O_RE::$operator)){
$operator = trim($this->match);
if(isset($this->operator_map[$operator]))
$operator = $this->operator_map[$operator];
$result[] = array('operator', $operator);
}
elseif ($this->scan(H2O_RE::$boolean))
$result[] = array('boolean', $this->match);
elseif ($this->scan(H2O_RE::$named_args))
$result[] = array('named_argument', $this->match);
elseif ($this->scan(H2O_RE::$name))
$result[] = array('name', $this->match);
elseif ($this->scan(H2O_RE::$pipe)) {
$filtering = true;
$result[] = array('filter_start', $this->match);
}
elseif ($this->scan(H2O_RE::$seperator))
$result[] = array('separator', null);
elseif ($this->scan(H2O_RE::$i18n_string))
$result[] = array('string', $this->match);
elseif ($this->scan(H2O_RE::$number))
$result[] = array('number', $this->match);
else
throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
}
else {
// parse filters, with chaining and ";" as filter end character
if ($this->scan(H2O_RE::$pipe)) {
$result[] = array('filter_end', null);
$result[] = array('filter_start', null);
}
elseif ($this->scan(H2O_RE::$seperator))
$result[] = array('separator', null);
elseif ($this->scan(H2O_RE::$filter_end)) {
$result[] = array('filter_end', null);
$filtering = false;
}
elseif ($this->scan(H2O_RE::$boolean))
$result[] = array('boolean', $this->match);
elseif ($this->scan(H2O_RE::$named_args))
$result[] = array('named_argument', $this->match);
elseif ($this->scan(H2O_RE::$name))
$result[] = array('name', $this->match);
elseif ($this->scan(H2O_RE::$i18n_string))
$result[] = array('string', $this->match);
elseif ($this->scan(H2O_RE::$number))
$result[] = array('number', $this->match);
else
throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
}
}
// if we are still in the filter state, we add a filter_end token.
if ($filtering)
$result[] = array('filter_end', null);
return $result;
}
# String scanner
function scan($regexp) {
if (preg_match($regexp . 'A', $this->source, $match, null, $this->pos)) {
$this->match = $match[0];
$this->pos += strlen($this->match);
return true;
}
return false;
}
function eos() {
return $this->pos >= strlen($this->source);
}
/**
* return the position in the template
*/
function getPosition() {
return $this->fpos + $this->pos;
}
}
?>
<?php
class H2o_Lexer {
function __construct($options = array()) {
$this->options = $options;
$trim = '';
if ($this->options['TRIM_TAGS'])
$trim = '(?:\r?\n)?';
$this->pattern = ('/\G(.*?)(?:' .
preg_quote($this->options['BLOCK_START']). '(.*?)' .preg_quote($this->options['BLOCK_END']) . $trim . '|' .
preg_quote($this->options['VARIABLE_START']). '(.*?)' .preg_quote($this->options['VARIABLE_END']) . '|' .
preg_quote($this->options['COMMENT_START']). '(.*?)' .preg_quote($this->options['COMMENT_END']) . $trim . ')/sm'
);
}
function tokenize($source) {
$result = new TokenStream;
$pos = 0;
$matches = array();
preg_match_all($this->pattern, $source, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
if ($match[1])
$result->feed('text', $match[1], $pos);
$tagpos = $pos + strlen($match[1]);
if ($match[2])
$result->feed('block', trim($match[2]), $tagpos);
elseif ($match[3])
$result->feed('variable', trim($match[3]), $tagpos);
elseif ($match[4])
$result->feed('comment', trim($match[4]), $tagpos);
$pos += strlen($match[0]);
}
if ($pos < strlen($source)){
$result->feed('text', substr($source, $pos), $pos);
}
$result->close();
return $result;
}
}
class H2o_Parser {
var $first;
var $storage = array();
var $filename;
var $runtime;
function __construct($source, $filename, $runtime, $options) {
$this->options = $options;
//$this->source = $source;
$this->runtime = $runtime;
$this->filename = $filename;
$this->first = true;
$this->lexer = new H2o_Lexer($options);
$this->tokenstream = $this->lexer->tokenize($source);
$this->storage = array(
'blocks' => array(),
'templates' => array(),
'included' => array()
);
}
function &parse() {
$until = func_get_args();
$nodelist = new NodeList($this);
while($token = $this->tokenstream->next()) {
//$token = $this->tokenstream->current();
switch($token->type) {
case 'text' :
$node = new TextNode($token->content, $token->position);
break;
case 'variable' :
$args = H2o_Parser::parseArguments($token->content, $token->position);
$variable = array_shift($args);
$filters = $args;
$node = new VariableNode($variable, $filters, $token->position);
break;
case 'comment' :
$node = new CommentNode($token->content);
break;
case 'block' :
if (in_array($token->content, $until)) {
$this->token = $token;
return $nodelist;
}
$temp = preg_split('/\s+/',$token->content, 2);
$name = $temp[0];
$args = (count($temp) > 1 ? $temp[1] : null);
$node = H2o::createTag($name, $args, $this, $token->position);
$this->token = $token;
}
$this->searching = join(',',$until);
$this->first = false;
$nodelist->append($node);
}
if ($until) {
throw new TemplateSyntaxError('Unclose tag, expecting '. $until[0]);
}
return $nodelist;
}
function skipTo($until) {
$this->parse($until);
return null;
}
# Parse arguments
static function parseArguments($source = null, $fpos = 0){
$parser = new ArgumentLexer($source, $fpos);
$result = array();
$current_buffer = &$result;
$filter_buffer = array();
$tokens = $parser->parse();
foreach ($tokens as $token) {
list($token, $data) = $token;
if ($token == 'filter_start') {
$filter_buffer = array();
$current_buffer = &$filter_buffer;
}
elseif ($token == 'filter_end') {
if (count($filter_buffer)) {
$i = count($result)-1;
if ( is_array($result[$i]) ) $result[$i]['filters'][] = $filter_buffer;
else $result[$i] = array(0 => $result[$i], 'filters' => array($filter_buffer));
}
$current_buffer = &$result;
}
elseif ($token == 'boolean') {
$current_buffer[] = ($data === 'true'? true : false);
}
elseif ($token == 'name') {
$current_buffer[] = symbol($data);
}
elseif ($token == 'number' || $token == 'string') {
$current_buffer[] = $data;
}
elseif ($token == 'named_argument') {
$last = $current_buffer[count($current_buffer) - 1];
if (!is_array($last))
$current_buffer[] = array();
$namedArgs =& $current_buffer[count($current_buffer) - 1];
list($name,$value) = array_map('trim', explode(':', $data, 2));
# if argument value is variable mark it
$value = self::parseArguments($value);
$namedArgs[$name] = $value[0];
}
elseif( $token == 'operator') {
$current_buffer[] = array('operator'=>$data);
}
}
return $result;
}
}
class H2O_RE {
static $whitespace, $seperator, $parentheses, $pipe, $filter_end, $operator, $boolean, $number, $string, $i18n_string, $name, $named_args;
static function init() {
$r = 'strip_regex';
self::$whitespace = '/\s+/m';
self::$parentheses = '/\(|\)/m';
self::$filter_end = '/;/';
self::$boolean = '/true|false/';
self::$seperator = '/,/';
self::$pipe = '/\|/';
self::$operator = '/\s?(>|<|>=|<=|!=|==|!|and |not |or )\s?/i';
self::$number = '/\d+(\.\d*)?/';
self::$name = '/[a-zA-Z][a-zA-Z0-9-_]*(?:\.[a-zA-Z_0-9][a-zA-Z0-9_-]*)*/';
self::$string = '/(?:
"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)" | # Double Quote string
\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\' # Single Quote String
)/xsm';
self::$i18n_string = "/_\({$r(self::$string)}\) | {$r(self::$string)}/xsm";
self::$named_args = "{
({$r(self::$name)})(?:{$r(self::$whitespace)})?
:
(?:{$r(self::$whitespace)})?({$r(self::$i18n_string)}|{$r(self::$number)}|{$r(self::$name)})
}x";
}
}
H2O_RE::init();
class ArgumentLexer {
private $source;
private $match;
private $pos = 0, $fpos, $eos;
private $operator_map = array(
'!' => 'not', '!='=> 'ne', '==' => 'eq', '>' => 'gt', '<' => 'lt', '<=' => 'le', '>=' => 'ge'
);
function __construct($source, $fpos = 0){
if (!is_null($source))
$this->source = $source;
$this->fpos=$fpos;
}
function parse(){
$result = array();
$filtering = false;
while (!$this->eos()) {
$this->scan(H2O_RE::$whitespace);
if (!$filtering) {
if ($this->scan(H2O_RE::$operator)){
$operator = trim($this->match);
if(isset($this->operator_map[$operator]))
$operator = $this->operator_map[$operator];
$result[] = array('operator', $operator);
}
elseif ($this->scan(H2O_RE::$boolean))
$result[] = array('boolean', $this->match);
elseif ($this->scan(H2O_RE::$named_args))
$result[] = array('named_argument', $this->match);
elseif ($this->scan(H2O_RE::$name))
$result[] = array('name', $this->match);
elseif ($this->scan(H2O_RE::$pipe)) {
$filtering = true;
$result[] = array('filter_start', $this->match);
}
elseif ($this->scan(H2O_RE::$seperator))
$result[] = array('separator', null);
elseif ($this->scan(H2O_RE::$i18n_string))
$result[] = array('string', $this->match);
elseif ($this->scan(H2O_RE::$number))
$result[] = array('number', $this->match);
else
throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
}
else {
// parse filters, with chaining and ";" as filter end character
if ($this->scan(H2O_RE::$pipe)) {
$result[] = array('filter_end', null);
$result[] = array('filter_start', null);
}
elseif ($this->scan(H2O_RE::$seperator))
$result[] = array('separator', null);
elseif ($this->scan(H2O_RE::$filter_end)) {
$result[] = array('filter_end', null);
$filtering = false;
}
elseif ($this->scan(H2O_RE::$boolean))
$result[] = array('boolean', $this->match);
elseif ($this->scan(H2O_RE::$named_args))
$result[] = array('named_argument', $this->match);
elseif ($this->scan(H2O_RE::$name))
$result[] = array('name', $this->match);
elseif ($this->scan(H2O_RE::$i18n_string))
$result[] = array('string', $this->match);
elseif ($this->scan(H2O_RE::$number))
$result[] = array('number', $this->match);
else
throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
}
}
// if we are still in the filter state, we add a filter_end token.
if ($filtering)
$result[] = array('filter_end', null);
return $result;
}
# String scanner
function scan($regexp) {
if (preg_match($regexp . 'A', $this->source, $match, null, $this->pos)) {
$this->match = $match[0];
$this->pos += strlen($this->match);
return true;
}
return false;
}
function eos() {
return $this->pos >= strlen($this->source);
}
/**
* return the position in the template
*/
function getPosition() {
return $this->fpos + $this->pos;
}
}
?>