- PHP Framework upgrade 3.5.0 -> 3.5.1 (fixes some issues with CREST cURL caching, and SESSION management)
- #138 added "cookie logout" to "logout" menu entry
This commit is contained in:
@@ -1,5 +1,52 @@
|
||||
CHANGELOG
|
||||
|
||||
3.5.1 (31 December 2015)
|
||||
* NEW: ttl attribute in <include> template tag
|
||||
* NEW: allow anonymous function for template filter
|
||||
* NEW: format modifier for international and custom currency symbol
|
||||
* NEW: Image->data() returns image resource
|
||||
* NEW: extract() get prefixed array keys from an assoc array
|
||||
* NEW: Optimized and faster Template parser with full support for HTML5 empty tags
|
||||
* NEW: Added support for {@token} encapsulation syntax in routes definition
|
||||
* NEW: DB\SQL->exec(), automatically shift to 1-based query arguments
|
||||
* NEW: abort() flush output
|
||||
* Added referenced value to devoid()
|
||||
* Template token filters are now resolved within Preview->token()
|
||||
* Web->_curl: restrict redirections to HTTP
|
||||
* Web->minify(), skip importing of external files
|
||||
* Improved session and error handling in until()
|
||||
* Get the error trace array with the new $format parameter
|
||||
* Better support for unicode URLs
|
||||
* Optimized TZ detection with date_default_timezone_get()
|
||||
* format() Provide default decimal places
|
||||
* Optimize code: remove redundant TTL checks
|
||||
* Optimized timeout handling in Web->request()
|
||||
* Improved PHPDoc hints
|
||||
* Added missing russian DIACRITICS letters
|
||||
* DB\Cursor: allow child implementation of reset()
|
||||
* DB\Cursor: Copyfrom now does an internal call to set()
|
||||
* DB\SQL: Provide the ability to disable SQL logging
|
||||
* DB\SQL: improved query analysis to trigger fetchAll
|
||||
* DB\SQL\Mapper: added support for binary table columns
|
||||
* SQL,JIG,MONGO,CACHE Session handlers refactored and optimized
|
||||
* SMTP Refactoring and optimization
|
||||
* Bug fix: SMTP, Align quoted_printable_encode() with SMTP specs (dot-stuffing)
|
||||
* Bug fix: SMTP, Send buffered optional headers to output
|
||||
* Bug fix: SMTP, Content-Transfer-Encoding for non-TLS connections
|
||||
* Bug fix: SMTP, Single attachment error
|
||||
* Bug fix: Cursor->load not always mapping to first record
|
||||
* Bug fix: dry SQL mapper should not trigger 'load'
|
||||
* Bug fix: Code highlighting on empty text
|
||||
* Bug fix: Image->resize, round dimensions instead of cast
|
||||
* Bug fix: whitespace handling in $f3->compile()
|
||||
* Bug fix: TTL of `View` and `Preview` (`Template`)
|
||||
* Bug fix: token filter regex
|
||||
* Bug fix: Template, empty attributes
|
||||
* Bug fix: Preview->build() greedy regex
|
||||
* Bug fix: Web->minify() single-line comment on last line
|
||||
* Bug fix: Web->request(), follow_location with cURL and open_basedir
|
||||
* Bug fix: Web->send() Single quotes around filename not interpreted correctly by some browsers
|
||||
|
||||
3.5.0 (2 June 2015)
|
||||
* NEW: until() method for long polling
|
||||
* NEW: abort() to disconnect HTTP client (and continue execution)
|
||||
|
||||
162
app/lib/base.php
162
app/lib/base.php
@@ -45,7 +45,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
//@{ Framework details
|
||||
const
|
||||
PACKAGE='Fat-Free Framework',
|
||||
VERSION='3.5.0-Release';
|
||||
VERSION='3.5.1-Release';
|
||||
//@}
|
||||
|
||||
//@{ HTTP status codes (RFC 2616)
|
||||
@@ -179,8 +179,8 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
}
|
||||
|
||||
/**
|
||||
* assemble url from alias name
|
||||
* @return NULL
|
||||
* Assemble url from alias name
|
||||
* @return string
|
||||
* @param $name string
|
||||
* @param $params array|string
|
||||
**/
|
||||
@@ -215,7 +215,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
function compile($str) {
|
||||
$fw=$this;
|
||||
return preg_replace_callback(
|
||||
'/(?<!\w)@(\w(?:[\w\.\[\]\(]|\->|::)*)/',
|
||||
'/(?<!\w)@(\w(?:[\h\w\.\[\]\(]|\->|::)*)/',
|
||||
function($var) use($fw) {
|
||||
return '$'.preg_replace_callback(
|
||||
'/\.(\w+)\(|\.(\w+)|\[((?:[^\[\]]*|(?R))*)\]/',
|
||||
@@ -226,7 +226,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
('['.var_export($expr[1],TRUE).']')).'('):
|
||||
('['.var_export(
|
||||
isset($expr[3])?
|
||||
$fw->compile($expr[3]):
|
||||
trim($fw->compile($expr[3])):
|
||||
(ctype_digit($expr[2])?
|
||||
(int)$expr[2]:
|
||||
$expr[2]),TRUE).']');
|
||||
@@ -305,10 +305,11 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
|
||||
/**
|
||||
* Return TRUE if hive key is empty and not cached
|
||||
* @return bool
|
||||
* @param $key string
|
||||
* @param $val mixed
|
||||
* @return bool
|
||||
**/
|
||||
function devoid($key) {
|
||||
function devoid($key,&$val=NULL) {
|
||||
$val=$this->ref($key,FALSE);
|
||||
return empty($val) &&
|
||||
(!Cache::instance()->exists($this->hash($key).'.var',$val) ||
|
||||
@@ -422,8 +423,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
// End session
|
||||
session_unset();
|
||||
session_destroy();
|
||||
unset($_COOKIE[session_name()]);
|
||||
header_remove('Set-Cookie');
|
||||
$this->clear('COOKIE.'.session_name());
|
||||
}
|
||||
$this->sync('SESSION');
|
||||
}
|
||||
@@ -679,6 +679,19 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
return $num?($num/abs($num)):0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract values of an associative array whose keys start with the given prefix
|
||||
* @return array
|
||||
* @param $arr array
|
||||
* @param $prefix string
|
||||
**/
|
||||
function extract($arr,$prefix) {
|
||||
$out=array();
|
||||
foreach (preg_grep('/^'.preg_quote($prefix,'/').'/',array_keys($arr)) as $key)
|
||||
$out[substr($key,strlen($prefix))]=$arr[$key];
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert class constants to array
|
||||
* @return array
|
||||
@@ -687,14 +700,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
**/
|
||||
function constants($class,$prefix='') {
|
||||
$ref=new ReflectionClass($class);
|
||||
$out=array();
|
||||
foreach (preg_grep('/^'.$prefix.'/',array_keys($ref->getconstants()))
|
||||
as $val) {
|
||||
$out[$key=substr($val,strlen($prefix))]=
|
||||
constant((is_object($class)?get_class($class):$class).'::'.$prefix.$key);
|
||||
}
|
||||
unset($ref);
|
||||
return $out;
|
||||
return $this->extract($ref->getconstants(),$prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -843,9 +849,12 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
return number_format(
|
||||
$args[$pos],0,'',$thousands_sep);
|
||||
case 'currency':
|
||||
if (function_exists('money_format'))
|
||||
$int=$cstm=false;
|
||||
if (isset($prop) && $cstm=!$int=($prop=='int'))
|
||||
$currency_symbol=$prop;
|
||||
if (!$cstm && function_exists('money_format'))
|
||||
return money_format(
|
||||
'%n',$args[$pos]);
|
||||
'%'.($int?'i':'n'),$args[$pos]);
|
||||
$fmt=array(
|
||||
0=>'(nc)',1=>'(n c)',
|
||||
2=>'(nc)',10=>'+nc',
|
||||
@@ -878,7 +887,8 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
$frac_digits,
|
||||
$decimal_point,
|
||||
$thousands_sep),
|
||||
$currency_symbol),
|
||||
$int?$int_curr_symbol
|
||||
:$currency_symbol),
|
||||
$fmt[(int)(
|
||||
(${$pre.'_cs_precedes'}%2).
|
||||
(${$pre.'_sign_posn'}%5).
|
||||
@@ -891,8 +901,8 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
$thousands_sep).'%';
|
||||
case 'decimal':
|
||||
return number_format(
|
||||
$args[$pos],$prop,$decimal_point,
|
||||
$thousands_sep);
|
||||
$args[$pos],isset($prop)?$prop:2,
|
||||
$decimal_point,$thousands_sep);
|
||||
}
|
||||
break;
|
||||
case 'date':
|
||||
@@ -1022,7 +1032,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
**/
|
||||
function status($code) {
|
||||
$reason=@constant('self::HTTP_'.$code);
|
||||
if (PHP_SAPI!='cli')
|
||||
if (PHP_SAPI!='cli' && !headers_sent())
|
||||
header($_SERVER['SERVER_PROTOCOL'].' '.$code.' '.$reason);
|
||||
return $reason;
|
||||
}
|
||||
@@ -1089,11 +1099,12 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return formatted stack trace
|
||||
* @return string
|
||||
* Return filtered, formatted stack trace
|
||||
* @return string|array
|
||||
* @param $trace array|NULL
|
||||
* @param $format bool
|
||||
**/
|
||||
function trace(array $trace=NULL) {
|
||||
function trace(array $trace=NULL, $format=TRUE) {
|
||||
if (!$trace) {
|
||||
$trace=debug_backtrace(FALSE);
|
||||
$frame=$trace[0];
|
||||
@@ -1111,6 +1122,8 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
'__call|call_user_func)/',$frame['function']));
|
||||
}
|
||||
);
|
||||
if (!$format)
|
||||
return $trace;
|
||||
$out='';
|
||||
$eol="\n";
|
||||
// Analyze stack trace
|
||||
@@ -1369,7 +1382,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
$url=$this->rel($this->hive['URI']);
|
||||
$case=$this->hive['CASELESS']?'i':'';
|
||||
preg_match('/^'.
|
||||
preg_replace('/@(\w+\b)/','(?P<\1>[^\/\?]+)',
|
||||
preg_replace('/((\\\{)?@(\w+\b)(?(2)\\\}))/','(?P<\3>[^\/\?]+)',
|
||||
str_replace('\*','([^\?]+)',preg_quote($pattern,'/'))).
|
||||
'\/?(?:\?.*)?$/'.$case.'um',$url,$args);
|
||||
return $args;
|
||||
@@ -1394,7 +1407,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
array_multisort($paths,SORT_DESC,$keys,$vals);
|
||||
$this->hive['ROUTES']=array_combine($keys,$vals);
|
||||
// Convert to BASE-relative URL
|
||||
$req=$this->rel($this->hive['URI']);
|
||||
$req=$this->rel(urldecode($this->hive['URI']));
|
||||
if ($cors=(isset($this->hive['HEADERS']['Origin']) &&
|
||||
$this->hive['CORS']['origin'])) {
|
||||
$cors=$this->hive['CORS'];
|
||||
@@ -1428,7 +1441,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
if (is_numeric($key) && $key)
|
||||
unset($args[$key]);
|
||||
// Capture values of route pattern tokens
|
||||
$this->hive['PARAMS']=$args=array_map('urldecode',$args);
|
||||
$this->hive['PARAMS']=$args;
|
||||
// Save matching route
|
||||
$this->hive['ALIAS']=$alias;
|
||||
$this->hive['PATTERN']=$pattern;
|
||||
@@ -1437,9 +1450,10 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
implode(',',$cors['expose']):$cors['expose']));
|
||||
if (is_string($handler)) {
|
||||
// Replace route pattern tokens in handler if any
|
||||
$handler=preg_replace_callback('/@(\w+\b)/',
|
||||
$handler=preg_replace_callback('/({)?@(\w+\b)(?(1)})/',
|
||||
function($id) use($args) {
|
||||
return isset($args[$id[1]])?$args[$id[1]]:$id[0];
|
||||
$pid=count($id)>2?2:1;
|
||||
return isset($args[$id[$pid]])?$args[$id[$pid]]:$id[0];
|
||||
},
|
||||
$handler
|
||||
);
|
||||
@@ -1458,7 +1472,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
$cached=$cache->exists(
|
||||
$hash=$this->hash($this->hive['VERB'].' '.
|
||||
$this->hive['URI']).'.url',$data);
|
||||
if ($cached && $cached[0]+$ttl>$now) {
|
||||
if ($cached) {
|
||||
if (isset($headers['If-Modified-Since']) &&
|
||||
strtotime($headers['If-Modified-Since'])+
|
||||
$ttl>$now) {
|
||||
@@ -1520,10 +1534,13 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
// Unhandled HTTP method
|
||||
header('Allow: '.implode(',',array_unique($allowed)));
|
||||
if ($cors) {
|
||||
header('Access-Control-Allow-Methods: OPTIONS,'.implode(',',$allowed));
|
||||
header('Access-Control-Allow-Methods: OPTIONS,'.
|
||||
implode(',',$allowed));
|
||||
if ($cors['headers'])
|
||||
header('Access-Control-Allow-Headers: '.(is_array($cors['headers'])?
|
||||
implode(',',$cors['headers']):$cors['headers']));
|
||||
header('Access-Control-Allow-Headers: '.
|
||||
(is_array($cors['headers'])?
|
||||
implode(',',$cors['headers']):
|
||||
$cors['headers']));
|
||||
if ($cors['ttl']>0)
|
||||
header('Access-Control-Max-Age: '.$cors['ttl']);
|
||||
}
|
||||
@@ -1546,28 +1563,26 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
$time=time();
|
||||
$limit=max(0,min($timeout,$max=ini_get('max_execution_time')-1));
|
||||
$out='';
|
||||
$flag=FALSE;
|
||||
// Turn output buffering on
|
||||
ob_start();
|
||||
// Not for the weak of heart
|
||||
while (
|
||||
// No error occurred
|
||||
!$this->hive['ERROR'] &&
|
||||
// Still alive?
|
||||
!connection_aborted() &&
|
||||
// Got time left?
|
||||
(time()-$time+1<$limit) &&
|
||||
// Restart session
|
||||
$flag=@session_start() &&
|
||||
@session_start() &&
|
||||
// CAUTION: Callback will kill host if it never becomes truthy!
|
||||
!($out=$this->call($func,$args))) {
|
||||
session_commit();
|
||||
ob_flush();
|
||||
flush();
|
||||
// Hush down
|
||||
sleep(1);
|
||||
}
|
||||
if ($flag) {
|
||||
session_commit();
|
||||
ob_flush();
|
||||
flush();
|
||||
}
|
||||
ob_flush();
|
||||
flush();
|
||||
return $out;
|
||||
}
|
||||
|
||||
@@ -1577,9 +1592,11 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
function abort() {
|
||||
@session_start();
|
||||
session_commit();
|
||||
header('Content-Length: 0');
|
||||
$out='';
|
||||
while (ob_get_level())
|
||||
ob_end_clean();
|
||||
$out=ob_get_clean().$out;
|
||||
header('Content-Length: '.strlen($out));
|
||||
echo $out;
|
||||
flush();
|
||||
if (function_exists('fastcgi_finish_request'))
|
||||
fastcgi_finish_request();
|
||||
@@ -1826,7 +1843,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
$out='';
|
||||
$pre=FALSE;
|
||||
$text=trim($text);
|
||||
if (!preg_match('/^<\?php/',$text)) {
|
||||
if ($text && !preg_match('/^<\?php/',$text)) {
|
||||
$text='<?php '.$text;
|
||||
$pre=TRUE;
|
||||
}
|
||||
@@ -2083,9 +2100,9 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
'CONFIG'=>NULL,
|
||||
'CORS'=>array(
|
||||
'headers'=>'',
|
||||
'origin'=>false,
|
||||
'credentials'=>false,
|
||||
'expose'=>false,
|
||||
'origin'=>FALSE,
|
||||
'credentials'=>FALSE,
|
||||
'expose'=>FALSE,
|
||||
'ttl'=>0),
|
||||
'DEBUG'=>0,
|
||||
'DIACRITICS'=>array(),
|
||||
@@ -2131,7 +2148,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
'SERIALIZER'=>extension_loaded($ext='igbinary')?$ext:'php',
|
||||
'TEMP'=>'tmp/',
|
||||
'TIME'=>microtime(TRUE),
|
||||
'TZ'=>(@ini_get('date.timezone'))?:'UTC',
|
||||
'TZ'=>@date_default_timezone_get(),
|
||||
'UI'=>'./',
|
||||
'UNLOAD'=>NULL,
|
||||
'UPLOADS'=>'./',
|
||||
@@ -2500,8 +2517,7 @@ class View extends Prefab {
|
||||
function render($file,$mime='text/html',array $hive=NULL,$ttl=0) {
|
||||
$fw=Base::instance();
|
||||
$cache=Cache::instance();
|
||||
$cached=$cache->exists($hash=$fw->hash($file),$data);
|
||||
if ($cached && $cached[0]+$ttl>microtime(TRUE))
|
||||
if ($cache->exists($hash=$fw->hash($file),$data))
|
||||
return $data;
|
||||
foreach ($fw->split($fw->get('UI').';./') as $dir)
|
||||
if (is_file($this->view=$fw->fixslashes($dir.$file))) {
|
||||
@@ -2516,7 +2532,7 @@ class View extends Prefab {
|
||||
foreach($this->trigger['afterrender'] as $func)
|
||||
$data=$fw->call($func,$data);
|
||||
if ($ttl)
|
||||
$cache->set($hash,$data);
|
||||
$cache->set($hash,$data,$ttl);
|
||||
return $data;
|
||||
}
|
||||
user_error(sprintf(Base::E_Open,$file),E_USER_ERROR);
|
||||
@@ -2539,7 +2555,7 @@ class Preview extends View {
|
||||
//! MIME type
|
||||
$mime,
|
||||
//! token filter
|
||||
$filter = array(
|
||||
$filter=array(
|
||||
'esc'=>'$this->esc',
|
||||
'raw'=>'$this->raw',
|
||||
'alias'=>'\Base::instance()->alias',
|
||||
@@ -2552,15 +2568,24 @@ class Preview extends View {
|
||||
* @param $str string
|
||||
**/
|
||||
function token($str) {
|
||||
return trim(preg_replace('/\{\{(.+?)\}\}/s',trim('\1'),
|
||||
$str=trim(preg_replace('/\{\{(.+?)\}\}/s',trim('\1'),
|
||||
Base::instance()->compile($str)));
|
||||
if (preg_match('/^(.+)(?<!\|)\|((?:\h*\w+(?:\h*[,;]?))+)$/s',
|
||||
$str,$parts)) {
|
||||
$str=trim($parts[1]);
|
||||
foreach (Base::instance()->split($parts[2]) as $func)
|
||||
$str=is_string($cmd=$this->filter($func))?$cmd.'('.$str.')':
|
||||
'\Base::instance()->call('.
|
||||
'$this->filter(\''.$func.'\'),array('.$str.'))';
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* register token filter
|
||||
* Register or get (a specific one or all) token filters
|
||||
* @param string $key
|
||||
* @param string $func
|
||||
* @return array
|
||||
* @param string|closure $func
|
||||
* @return array|closure|string
|
||||
*/
|
||||
function filter($key=NULL,$func=NULL) {
|
||||
if (!$key)
|
||||
@@ -2578,19 +2603,15 @@ class Preview extends View {
|
||||
protected function build($node) {
|
||||
$self=$this;
|
||||
return preg_replace_callback(
|
||||
'/\{\-(.+?)\-\}|\{\{(.+?)\}\}(\n+)?/s',
|
||||
'/\{\-(.+?)\-\}|\{\{(.+?)\}\}(\n+)?|(\{\*.*?\*\})/s',
|
||||
function($expr) use($self) {
|
||||
if ($expr[1])
|
||||
return $expr[1];
|
||||
$str=trim($self->token($expr[2]));
|
||||
if (preg_match('/^([^|]+?)\h*\|(\h*\w+(?:\h*[,;]\h*\w+)*)/',
|
||||
$str,$parts)) {
|
||||
$str=$parts[1];
|
||||
foreach (Base::instance()->split($parts[2]) as $func)
|
||||
$str=$self->filter($func).'('.$str.')';
|
||||
}
|
||||
return '<?php echo '.$str.'; ?>'.
|
||||
(isset($expr[3])?$expr[3]."\n":'');
|
||||
return empty($expr[4])?
|
||||
('<?php echo '.$str.'; ?>'.
|
||||
(isset($expr[3])?$expr[3]."\n":'')):
|
||||
'';
|
||||
},
|
||||
preg_replace_callback(
|
||||
'/\{~(.+?)~\}/s',
|
||||
@@ -2631,8 +2652,7 @@ class Preview extends View {
|
||||
if (!is_dir($tmp=$fw->get('TEMP')))
|
||||
mkdir($tmp,Base::MODE,TRUE);
|
||||
foreach ($fw->split($fw->get('UI')) as $dir) {
|
||||
$cached=$cache->exists($hash=$fw->hash($dir.$file),$data);
|
||||
if ($cached && $cached[0]+$ttl>microtime(TRUE))
|
||||
if ($cache->exists($hash=$fw->hash($dir.$file),$data))
|
||||
return $data;
|
||||
if (is_file($view=$fw->fixslashes($dir.$file))) {
|
||||
if (!is_file($this->view=($tmp.
|
||||
@@ -2659,7 +2679,7 @@ class Preview extends View {
|
||||
foreach ($this->trigger['afterrender'] as $func)
|
||||
$data = $fw->call($func, $data);
|
||||
if ($ttl)
|
||||
$cache->set($hash,$data);
|
||||
$cache->set($hash,$data,$ttl);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ class Basket extends Magic {
|
||||
if (is_string($var))
|
||||
$var=\Base::instance()->get($var);
|
||||
foreach ($var as $key=>$val)
|
||||
$this->item[$key]=$val;
|
||||
$this->set($key,$val);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -103,7 +103,7 @@ abstract class Cursor extends \Magic implements \IteratorAggregate {
|
||||
|
||||
/**
|
||||
* Get cursor's equivalent external iterator
|
||||
* Causes a fatal error in PHP 5.3.5if uncommented
|
||||
* Causes a fatal error in PHP 5.3.5 if uncommented
|
||||
* return ArrayIterator
|
||||
**/
|
||||
abstract function getiterator();
|
||||
@@ -119,7 +119,7 @@ abstract class Cursor extends \Magic implements \IteratorAggregate {
|
||||
|
||||
/**
|
||||
* Return first record (mapper object) that matches criteria
|
||||
* @return \DB\Cursor|FALSE
|
||||
* @return static|FALSE
|
||||
* @param $filter string|array
|
||||
* @param $options array
|
||||
* @param $ttl int
|
||||
@@ -171,8 +171,9 @@ abstract class Cursor extends \Magic implements \IteratorAggregate {
|
||||
* @param $ttl int
|
||||
**/
|
||||
function load($filter=NULL,array $options=NULL,$ttl=0) {
|
||||
$this->reset();
|
||||
return ($this->query=$this->find($filter,$options,$ttl)) &&
|
||||
$this->skip(0)?$this->query[$this->ptr=0]:FALSE;
|
||||
$this->skip(0)?$this->query[$this->ptr]:FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -149,7 +149,7 @@ class Mapper extends \DB\Cursor {
|
||||
|
||||
/**
|
||||
* Return records that match criteria
|
||||
* @return \DB\JIG\Mapper[]|FALSE
|
||||
* @return static[]|FALSE
|
||||
* @param $filter array
|
||||
* @param $options array
|
||||
* @param $ttl int
|
||||
@@ -431,7 +431,7 @@ class Mapper extends \DB\Cursor {
|
||||
if ($func)
|
||||
$var=call_user_func($func,$var);
|
||||
foreach ($var as $key=>$val)
|
||||
$this->document[$key]=$val;
|
||||
$this->set($key,$val);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,15 @@ class Session extends Mapper {
|
||||
|
||||
protected
|
||||
//! Session ID
|
||||
$sid;
|
||||
$sid,
|
||||
//! Anti-CSRF token
|
||||
$_csrf,
|
||||
//! User agent
|
||||
$_agent,
|
||||
//! IP,
|
||||
$_ip,
|
||||
//! Suspect callback
|
||||
$onsuspect;
|
||||
|
||||
/**
|
||||
* Open session
|
||||
@@ -44,6 +52,8 @@ class Session extends Mapper {
|
||||
* @return TRUE
|
||||
**/
|
||||
function close() {
|
||||
$this->reset();
|
||||
$this->sid=NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -53,9 +63,20 @@ class Session extends Mapper {
|
||||
* @param $id string
|
||||
**/
|
||||
function read($id) {
|
||||
if ($id!=$this->sid)
|
||||
$this->load(array('@session_id=?',$this->sid=$id));
|
||||
return $this->dry()?FALSE:$this->get('data');
|
||||
$this->load(array('@session_id=?',$this->sid=$id));
|
||||
if ($this->dry())
|
||||
return FALSE;
|
||||
if ($this->get('ip')!=$this->_ip || $this->get('agent')!=$this->_agent) {
|
||||
$fw=\Base::instance();
|
||||
if (!isset($this->onsuspect) || FALSE===$fw->call($this->onsuspect,array($this,$id))) {
|
||||
//NB: `session_destroy` can't be called at that stage (`session_start` not completed)
|
||||
$this->destroy($id);
|
||||
$this->close();
|
||||
$fw->clear('COOKIE.'.session_name());
|
||||
$fw->error(403);
|
||||
}
|
||||
}
|
||||
return $this->get('data');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,19 +86,10 @@ class Session extends Mapper {
|
||||
* @param $data string
|
||||
**/
|
||||
function write($id,$data) {
|
||||
$fw=\Base::instance();
|
||||
$sent=headers_sent();
|
||||
$headers=$fw->get('HEADERS');
|
||||
if ($id!=$this->sid)
|
||||
$this->load(array('@session_id=?',$this->sid=$id));
|
||||
$csrf=$fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
|
||||
$fw->hash(mt_rand());
|
||||
$this->set('session_id',$id);
|
||||
$this->set('data',$data);
|
||||
$this->set('csrf',$sent?$this->csrf():$csrf);
|
||||
$this->set('ip',$fw->get('IP'));
|
||||
$this->set('agent',
|
||||
isset($headers['User-Agent'])?$headers['User-Agent']:'');
|
||||
$this->set('ip',$this->_ip);
|
||||
$this->set('agent',$this->_agent);
|
||||
$this->set('stamp',time());
|
||||
$this->save();
|
||||
return TRUE;
|
||||
@@ -90,9 +102,6 @@ class Session extends Mapper {
|
||||
**/
|
||||
function destroy($id) {
|
||||
$this->erase(array('@session_id=?',$id));
|
||||
setcookie(session_name(),'',strtotime('-1 year'));
|
||||
unset($_COOKIE[session_name()]);
|
||||
header_remove('Set-Cookie');
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -107,19 +116,27 @@ class Session extends Mapper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return anti-CSRF token
|
||||
* @return string|FALSE
|
||||
**/
|
||||
function csrf() {
|
||||
return $this->dry()?FALSE:$this->get('csrf');
|
||||
* Return session id (if session has started)
|
||||
* @return string|NULL
|
||||
**/
|
||||
function sid() {
|
||||
return $this->sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return IP address
|
||||
* @return string|FALSE
|
||||
**/
|
||||
* Return anti-CSRF token
|
||||
* @return string
|
||||
**/
|
||||
function csrf() {
|
||||
return $this->_csrf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return IP address
|
||||
* @return string
|
||||
**/
|
||||
function ip() {
|
||||
return $this->dry()?FALSE:$this->get('ip');
|
||||
return $this->_ip;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,6 +144,8 @@ class Session extends Mapper {
|
||||
* @return string|FALSE
|
||||
**/
|
||||
function stamp() {
|
||||
if (!$this->sid)
|
||||
session_start();
|
||||
return $this->dry()?FALSE:$this->get('stamp');
|
||||
}
|
||||
|
||||
@@ -135,17 +154,19 @@ class Session extends Mapper {
|
||||
* @return string|FALSE
|
||||
**/
|
||||
function agent() {
|
||||
return $this->dry()?FALSE:$this->get('agent');
|
||||
return $this->_agent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate class
|
||||
* @param $db object
|
||||
* @param $db \DB\Jig
|
||||
* @param $file string
|
||||
* @param $onsuspect callback
|
||||
* @param $key string
|
||||
**/
|
||||
function __construct(\DB\Jig $db,$file='sessions',$onsuspect=NULL) {
|
||||
function __construct(\DB\Jig $db,$file='sessions',$onsuspect=NULL,$key=NULL) {
|
||||
parent::__construct($db,$file);
|
||||
$this->onsuspect=$onsuspect;
|
||||
session_set_save_handler(
|
||||
array($this,'open'),
|
||||
array($this,'close'),
|
||||
@@ -155,26 +176,14 @@ class Session extends Mapper {
|
||||
array($this,'cleanup')
|
||||
);
|
||||
register_shutdown_function('session_commit');
|
||||
@session_start();
|
||||
$fw=\Base::instance();
|
||||
$headers=$fw->get('HEADERS');
|
||||
if (($ip=$this->ip()) && $ip!=$fw->get('IP') ||
|
||||
($agent=$this->agent()) &&
|
||||
(!isset($headers['User-Agent']) ||
|
||||
$agent!=$headers['User-Agent'])) {
|
||||
if (isset($onsuspect))
|
||||
$fw->call($onsuspect,array($this));
|
||||
else {
|
||||
session_destroy();
|
||||
$fw->error(403);
|
||||
}
|
||||
}
|
||||
$csrf=$fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
|
||||
$this->_csrf=$fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
|
||||
$fw->hash(mt_rand());
|
||||
if ($this->load(array('@session_id=?',$this->sid=session_id()))) {
|
||||
$this->set('csrf',$csrf);
|
||||
$this->save();
|
||||
}
|
||||
if ($key)
|
||||
$fw->set($key,$this->_csrf);
|
||||
$this->_agent=isset($headers['User-Agent'])?$headers['User-Agent']:'';
|
||||
$this->_ip=$fw->get('IP');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ class Mapper extends \DB\Cursor {
|
||||
|
||||
/**
|
||||
* Convert array to mapper object
|
||||
* @return \DB\Mongo\Mapper
|
||||
* @return static
|
||||
* @param $row array
|
||||
**/
|
||||
protected function factory($row) {
|
||||
@@ -111,7 +111,7 @@ class Mapper extends \DB\Cursor {
|
||||
|
||||
/**
|
||||
* Build query and execute
|
||||
* @return \DB\Mongo\Mapper[]
|
||||
* @return static[]
|
||||
* @param $fields string
|
||||
* @param $filter array
|
||||
* @param $options array
|
||||
@@ -177,7 +177,7 @@ class Mapper extends \DB\Cursor {
|
||||
|
||||
/**
|
||||
* Return records that match criteria
|
||||
* @return \DB\Mongo\Mapper[]
|
||||
* @return static[]
|
||||
* @param $filter array
|
||||
* @param $options array
|
||||
* @param $ttl int
|
||||
@@ -308,7 +308,7 @@ class Mapper extends \DB\Cursor {
|
||||
if ($func)
|
||||
$var=call_user_func($func,$var);
|
||||
foreach ($var as $key=>$val)
|
||||
$this->document[$key]=$val;
|
||||
$this->set($key,$val);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,15 @@ class Session extends Mapper {
|
||||
|
||||
protected
|
||||
//! Session ID
|
||||
$sid;
|
||||
$sid,
|
||||
//! Anti-CSRF token
|
||||
$_csrf,
|
||||
//! User agent
|
||||
$_agent,
|
||||
//! IP,
|
||||
$_ip,
|
||||
//! Suspect callback
|
||||
$onsuspect;
|
||||
|
||||
/**
|
||||
* Open session
|
||||
@@ -44,6 +52,8 @@ class Session extends Mapper {
|
||||
* @return TRUE
|
||||
**/
|
||||
function close() {
|
||||
$this->reset();
|
||||
$this->sid=NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -53,9 +63,20 @@ class Session extends Mapper {
|
||||
* @param $id string
|
||||
**/
|
||||
function read($id) {
|
||||
if ($id!=$this->sid)
|
||||
$this->load(array('session_id'=>$this->sid=$id));
|
||||
return $this->dry()?FALSE:$this->get('data');
|
||||
$this->load(array('session_id'=>$this->sid=$id));
|
||||
if ($this->dry())
|
||||
return FALSE;
|
||||
if ($this->get('ip')!=$this->_ip || $this->get('agent')!=$this->_agent) {
|
||||
$fw=\Base::instance();
|
||||
if (!isset($this->onsuspect) || FALSE===$fw->call($this->onsuspect,array($this,$id))) {
|
||||
//NB: `session_destroy` can't be called at that stage (`session_start` not completed)
|
||||
$this->destroy($id);
|
||||
$this->close();
|
||||
$fw->clear('COOKIE.'.session_name());
|
||||
$fw->error(403);
|
||||
}
|
||||
}
|
||||
return $this->get('data');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,19 +86,10 @@ class Session extends Mapper {
|
||||
* @param $data string
|
||||
**/
|
||||
function write($id,$data) {
|
||||
$fw=\Base::instance();
|
||||
$sent=headers_sent();
|
||||
$headers=$fw->get('HEADERS');
|
||||
if ($id!=$this->sid)
|
||||
$this->load(array('session_id'=>$this->sid=$id));
|
||||
$csrf=$fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
|
||||
$fw->hash(mt_rand());
|
||||
$this->set('session_id',$id);
|
||||
$this->set('data',$data);
|
||||
$this->set('csrf',$sent?$this->csrf():$csrf);
|
||||
$this->set('ip',$fw->get('IP'));
|
||||
$this->set('agent',
|
||||
isset($headers['User-Agent'])?$headers['User-Agent']:'');
|
||||
$this->set('ip',$this->_ip);
|
||||
$this->set('agent',$this->_agent);
|
||||
$this->set('stamp',time());
|
||||
$this->save();
|
||||
return TRUE;
|
||||
@@ -90,9 +102,6 @@ class Session extends Mapper {
|
||||
**/
|
||||
function destroy($id) {
|
||||
$this->erase(array('session_id'=>$id));
|
||||
setcookie(session_name(),'',strtotime('-1 year'));
|
||||
unset($_COOKIE[session_name()]);
|
||||
header_remove('Set-Cookie');
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -107,45 +116,57 @@ class Session extends Mapper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return anti-CSRF token
|
||||
* @return string|FALSE
|
||||
**/
|
||||
* Return session id (if session has started)
|
||||
* @return string|NULL
|
||||
**/
|
||||
function sid() {
|
||||
return $this->sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return anti-CSRF token
|
||||
* @return string
|
||||
**/
|
||||
function csrf() {
|
||||
return $this->dry()?FALSE:$this->get('csrf');
|
||||
return $this->_csrf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return IP address
|
||||
* @return string|FALSE
|
||||
**/
|
||||
* Return IP address
|
||||
* @return string
|
||||
**/
|
||||
function ip() {
|
||||
return $this->dry()?FALSE:$this->get('ip');
|
||||
return $this->_ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Unix timestamp
|
||||
* @return string|FALSE
|
||||
**/
|
||||
* Return Unix timestamp
|
||||
* @return string|FALSE
|
||||
**/
|
||||
function stamp() {
|
||||
if (!$this->sid)
|
||||
session_start();
|
||||
return $this->dry()?FALSE:$this->get('stamp');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTTP user agent
|
||||
* @return string|FALSE
|
||||
**/
|
||||
* Return HTTP user agent
|
||||
* @return string
|
||||
**/
|
||||
function agent() {
|
||||
return $this->dry()?FALSE:$this->get('agent');
|
||||
return $this->_agent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate class
|
||||
* @param $db object
|
||||
* @param $db \DB\Mongo
|
||||
* @param $table string
|
||||
* @param $onsuspect callback
|
||||
* @param $key string
|
||||
**/
|
||||
function __construct(\DB\Mongo $db,$table='sessions',$onsuspect=NULL) {
|
||||
function __construct(\DB\Mongo $db,$table='sessions',$onsuspect=NULL,$key=NULL) {
|
||||
parent::__construct($db,$table);
|
||||
$this->onsuspect=$onsuspect;
|
||||
session_set_save_handler(
|
||||
array($this,'open'),
|
||||
array($this,'close'),
|
||||
@@ -155,26 +176,14 @@ class Session extends Mapper {
|
||||
array($this,'cleanup')
|
||||
);
|
||||
register_shutdown_function('session_commit');
|
||||
@session_start();
|
||||
$fw=\Base::instance();
|
||||
$headers=$fw->get('HEADERS');
|
||||
if (($ip=$this->ip()) && $ip!=$fw->get('IP') ||
|
||||
($agent=$this->agent()) &&
|
||||
(!isset($headers['User-Agent']) ||
|
||||
$agent!=$headers['User-Agent'])) {
|
||||
if (isset($onsuspect))
|
||||
$fw->call($onsuspect,array($this));
|
||||
else {
|
||||
session_destroy();
|
||||
$fw->error(403);
|
||||
}
|
||||
}
|
||||
$csrf=$fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
|
||||
$this->_csrf=$fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
|
||||
$fw->hash(mt_rand());
|
||||
if ($this->load(array('session_id'=>$this->sid=session_id()))) {
|
||||
$this->set('csrf',$csrf);
|
||||
$this->save();
|
||||
}
|
||||
if ($key)
|
||||
$fw->set($key,$this->_csrf);
|
||||
$this->_agent=isset($headers['User-Agent'])?$headers['User-Agent']:'';
|
||||
$this->_ip=$fw->get('IP');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -91,6 +91,8 @@ class SQL {
|
||||
return \PDO::PARAM_BOOL;
|
||||
case 'integer':
|
||||
return \PDO::PARAM_INT;
|
||||
case 'resource':
|
||||
return \PDO::PARAM_LOB;
|
||||
default:
|
||||
return \PDO::PARAM_STR;
|
||||
}
|
||||
@@ -112,6 +114,8 @@ class SQL {
|
||||
return (bool)$val;
|
||||
case \PDO::PARAM_STR:
|
||||
return (string)$val;
|
||||
case \PDO::PARAM_LOB:
|
||||
return (binary)$val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +153,11 @@ class SQL {
|
||||
for ($i=0;$i<$count;$i++) {
|
||||
$cmd=$cmds[$i];
|
||||
$arg=$args[$i];
|
||||
// ensure 1-based arguments
|
||||
if (array_key_exists(0,$arg)) {
|
||||
array_unshift($arg,'');
|
||||
unset($arg[0]);
|
||||
}
|
||||
if (!preg_replace('/(^\s+|[\s;]+$)/','',$cmd))
|
||||
continue;
|
||||
$now=microtime(TRUE);
|
||||
@@ -198,8 +207,8 @@ class SQL {
|
||||
$this->rollback();
|
||||
user_error('PDOStatement: '.$error[2],E_USER_ERROR);
|
||||
}
|
||||
if (preg_match('/^\s*'.
|
||||
'(?:EXPLAIN|SELECT|PRAGMA|SHOW|RETURNING)\b/is',$cmd) ||
|
||||
if (preg_match('/(?:^[\s\(]*'.
|
||||
'(?:EXPLAIN|SELECT|PRAGMA|SHOW)|RETURNING)\b/is',$cmd) ||
|
||||
(preg_match('/^\s*(?:CALL|EXEC)\b/is',$cmd) &&
|
||||
$query->columnCount())) {
|
||||
$result=$query->fetchall(\PDO::FETCH_ASSOC);
|
||||
@@ -245,11 +254,14 @@ class SQL {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return SQL profiler results
|
||||
* Return SQL profiler results (or disable logging)
|
||||
* @param $flag bool
|
||||
* @return string
|
||||
**/
|
||||
function log() {
|
||||
return $this->log;
|
||||
function log($flag=TRUE) {
|
||||
if ($flag)
|
||||
return $this->log;
|
||||
$this->log=FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -333,7 +345,10 @@ class SQL {
|
||||
\PDO::PARAM_INT:
|
||||
(preg_match('/bool/i',$row[$val[2]])?
|
||||
\PDO::PARAM_BOOL:
|
||||
\PDO::PARAM_STR),
|
||||
(preg_match('/blob|bytea|image|binary/i',
|
||||
$row[$val[2]])?
|
||||
\PDO::PARAM_LOB:
|
||||
\PDO::PARAM_STR)),
|
||||
'default'=>is_string($row[$val[3]])?
|
||||
preg_replace('/^\s*([\'"])(.*)\1\s*/','\2',
|
||||
$row[$val[3]]):$row[$val[3]],
|
||||
@@ -422,7 +437,7 @@ class SQL {
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect call to MongoDB object
|
||||
* Redirect call to PDO object
|
||||
* @return mixed
|
||||
* @param $func string
|
||||
* @param $args array
|
||||
|
||||
@@ -190,7 +190,7 @@ class Mapper extends \DB\Cursor {
|
||||
|
||||
/**
|
||||
* Build query string and execute
|
||||
* @return \DB\SQL\Mapper[]
|
||||
* @return static[]
|
||||
* @param $fields string
|
||||
* @param $filter string|array
|
||||
* @param $options array
|
||||
@@ -294,7 +294,7 @@ class Mapper extends \DB\Cursor {
|
||||
|
||||
/**
|
||||
* Return records that match criteria
|
||||
* @return \DB\SQL\Mapper[]
|
||||
* @return static[]
|
||||
* @param $filter string|array
|
||||
* @param $options array
|
||||
* @param $ttl int
|
||||
@@ -362,7 +362,7 @@ class Mapper extends \DB\Cursor {
|
||||
$field['value']=$dry?NULL:$out->adhoc[$key]['value'];
|
||||
unset($field);
|
||||
}
|
||||
if (isset($this->trigger['load']))
|
||||
if (!$dry && isset($this->trigger['load']))
|
||||
\Base::instance()->call($this->trigger['load'],$this);
|
||||
return $out;
|
||||
}
|
||||
@@ -559,14 +559,8 @@ class Mapper extends \DB\Cursor {
|
||||
if ($func)
|
||||
$var=call_user_func($func,$var);
|
||||
foreach ($var as $key=>$val)
|
||||
if (in_array($key,array_keys($this->fields))) {
|
||||
$field=&$this->fields[$key];
|
||||
if ($field['value']!==$val) {
|
||||
$field['value']=$val;
|
||||
$field['changed']=TRUE;
|
||||
}
|
||||
unset($field);
|
||||
}
|
||||
if (in_array($key,array_keys($this->fields)))
|
||||
$this->set($key,$val);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,15 @@ class Session extends Mapper {
|
||||
|
||||
protected
|
||||
//! Session ID
|
||||
$sid;
|
||||
$sid,
|
||||
//! Anti-CSRF token
|
||||
$_csrf,
|
||||
//! User agent
|
||||
$_agent,
|
||||
//! IP,
|
||||
$_ip,
|
||||
//! Suspect callback
|
||||
$onsuspect;
|
||||
|
||||
/**
|
||||
* Open session
|
||||
@@ -44,6 +52,8 @@ class Session extends Mapper {
|
||||
* @return TRUE
|
||||
**/
|
||||
function close() {
|
||||
$this->reset();
|
||||
$this->sid=NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -53,9 +63,20 @@ class Session extends Mapper {
|
||||
* @param $id string
|
||||
**/
|
||||
function read($id) {
|
||||
if ($id!=$this->sid)
|
||||
$this->load(array('session_id=?',$this->sid=$id));
|
||||
return $this->dry()?FALSE:$this->get('data');
|
||||
$this->load(array('session_id=?',$this->sid=$id));
|
||||
if ($this->dry())
|
||||
return FALSE;
|
||||
if ($this->get('ip')!=$this->_ip || $this->get('agent')!=$this->_agent) {
|
||||
$fw=\Base::instance();
|
||||
if (!isset($this->onsuspect) || FALSE===$fw->call($this->onsuspect,array($this,$id))) {
|
||||
//NB: `session_destroy` can't be called at that stage (`session_start` not completed)
|
||||
$this->destroy($id);
|
||||
$this->close();
|
||||
$fw->clear('COOKIE.'.session_name());
|
||||
$fw->error(403);
|
||||
}
|
||||
}
|
||||
return $this->get('data');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,19 +86,10 @@ class Session extends Mapper {
|
||||
* @param $data string
|
||||
**/
|
||||
function write($id,$data) {
|
||||
$fw=\Base::instance();
|
||||
$sent=headers_sent();
|
||||
$headers=$fw->get('HEADERS');
|
||||
if ($id!=$this->sid)
|
||||
$this->load(array('session_id=?',$this->sid=$id));
|
||||
$csrf=$fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
|
||||
$fw->hash(mt_rand());
|
||||
$this->set('session_id',$id);
|
||||
$this->set('data',$data);
|
||||
$this->set('csrf',$sent?$this->csrf():$csrf);
|
||||
$this->set('ip',$fw->get('IP'));
|
||||
$this->set('agent',
|
||||
isset($headers['User-Agent'])?$headers['User-Agent']:'');
|
||||
$this->set('ip',$this->_ip);
|
||||
$this->set('agent',$this->_agent);
|
||||
$this->set('stamp',time());
|
||||
$this->save();
|
||||
return TRUE;
|
||||
@@ -90,9 +102,6 @@ class Session extends Mapper {
|
||||
**/
|
||||
function destroy($id) {
|
||||
$this->erase(array('session_id=?',$id));
|
||||
setcookie(session_name(),'',strtotime('-1 year'));
|
||||
unset($_COOKIE[session_name()]);
|
||||
header_remove('Set-Cookie');
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -106,20 +115,28 @@ class Session extends Mapper {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return session id (if session has started)
|
||||
* @return string|NULL
|
||||
**/
|
||||
function sid() {
|
||||
return $this->sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return anti-CSRF token
|
||||
* @return string|FALSE
|
||||
* @return string
|
||||
**/
|
||||
function csrf() {
|
||||
return $this->dry()?FALSE:$this->get('csrf');
|
||||
return $this->_csrf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return IP address
|
||||
* @return string|FALSE
|
||||
* @return string
|
||||
**/
|
||||
function ip() {
|
||||
return $this->dry()?FALSE:$this->get('ip');
|
||||
return $this->_ip;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,25 +144,28 @@ class Session extends Mapper {
|
||||
* @return string|FALSE
|
||||
**/
|
||||
function stamp() {
|
||||
if (!$this->sid)
|
||||
session_start();
|
||||
return $this->dry()?FALSE:$this->get('stamp');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTTP user agent
|
||||
* @return string|FALSE
|
||||
* @return string
|
||||
**/
|
||||
function agent() {
|
||||
return $this->dry()?FALSE:$this->get('agent');
|
||||
return $this->_agent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate class
|
||||
* @param $db object
|
||||
* @param $db \DB\SQL
|
||||
* @param $table string
|
||||
* @param $force bool
|
||||
* @param $onsuspect callback
|
||||
* @param $key string
|
||||
**/
|
||||
function __construct(\DB\SQL $db,$table='sessions',$force=TRUE,$onsuspect=NULL) {
|
||||
function __construct(\DB\SQL $db,$table='sessions',$force=TRUE,$onsuspect=NULL,$key=NULL) {
|
||||
if ($force) {
|
||||
$eol="\n";
|
||||
$tab="\t";
|
||||
@@ -160,7 +180,6 @@ class Session extends Mapper {
|
||||
$table.' ('.$eol.
|
||||
$tab.$db->quotekey('session_id').' VARCHAR(40),'.$eol.
|
||||
$tab.$db->quotekey('data').' TEXT,'.$eol.
|
||||
$tab.$db->quotekey('csrf').' TEXT,'.$eol.
|
||||
$tab.$db->quotekey('ip').' VARCHAR(40),'.$eol.
|
||||
$tab.$db->quotekey('agent').' VARCHAR(255),'.$eol.
|
||||
$tab.$db->quotekey('stamp').' INTEGER,'.$eol.
|
||||
@@ -169,6 +188,7 @@ class Session extends Mapper {
|
||||
);
|
||||
}
|
||||
parent::__construct($db,$table);
|
||||
$this->onsuspect=$onsuspect;
|
||||
session_set_save_handler(
|
||||
array($this,'open'),
|
||||
array($this,'close'),
|
||||
@@ -178,26 +198,14 @@ class Session extends Mapper {
|
||||
array($this,'cleanup')
|
||||
);
|
||||
register_shutdown_function('session_commit');
|
||||
@session_start();
|
||||
$fw=\Base::instance();
|
||||
$headers=$fw->get('HEADERS');
|
||||
if (($ip=$this->ip()) && $ip!=$fw->get('IP') ||
|
||||
($agent=$this->agent()) &&
|
||||
(!isset($headers['User-Agent']) ||
|
||||
$agent!=$headers['User-Agent'])) {
|
||||
if (isset($onsuspect))
|
||||
$fw->call($onsuspect,array($this));
|
||||
else {
|
||||
session_destroy();
|
||||
$fw->error(403);
|
||||
}
|
||||
}
|
||||
$csrf=$fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
|
||||
$this->_csrf=$fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
|
||||
$fw->hash(mt_rand());
|
||||
if ($this->load(array('session_id=?',$this->sid=session_id()))) {
|
||||
$this->set('csrf',$csrf);
|
||||
$this->save();
|
||||
}
|
||||
if ($key)
|
||||
$fw->set($key,$this->_csrf);
|
||||
$this->_agent=isset($headers['User-Agent'])?$headers['User-Agent']:'';
|
||||
$this->_ip=$fw->get('IP');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -230,9 +230,9 @@ class Image {
|
||||
$ratio=($origw=imagesx($this->data))/($origh=imagesy($this->data));
|
||||
if (!$crop) {
|
||||
if ($width/$ratio<=$height)
|
||||
$height=$width/$ratio;
|
||||
$height=round($width/$ratio);
|
||||
else
|
||||
$width=$height*$ratio;
|
||||
$width=round($height*$ratio);
|
||||
}
|
||||
if (!$enlarge) {
|
||||
$width=min($origw,$width);
|
||||
@@ -245,12 +245,12 @@ class Image {
|
||||
// Resize
|
||||
if ($crop) {
|
||||
if ($width/$ratio<=$height) {
|
||||
$cropw=$origh*$width/$height;
|
||||
$cropw=round($origh*$width/$height);
|
||||
imagecopyresampled($tmp,$this->data,
|
||||
0,0,($origw-$cropw)/2,0,$width,$height,$cropw,$origh);
|
||||
}
|
||||
else {
|
||||
$croph=$origw*$height/$width;
|
||||
$croph=round($origw*$height/$width);
|
||||
imagecopyresampled($tmp,$this->data,
|
||||
0,0,0,($origh-$croph)/2,$width,$height,$origw,$croph);
|
||||
}
|
||||
@@ -489,6 +489,14 @@ class Image {
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return image resource
|
||||
* @return resource
|
||||
**/
|
||||
function data() {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save current state
|
||||
* @return object
|
||||
|
||||
@@ -25,7 +25,15 @@ class Session {
|
||||
|
||||
protected
|
||||
//! Session ID
|
||||
$sid;
|
||||
$sid,
|
||||
//! Anti-CSRF token
|
||||
$_csrf,
|
||||
//! User agent
|
||||
$_agent,
|
||||
//! IP,
|
||||
$_ip,
|
||||
//! Suspect callback
|
||||
$onsuspect;
|
||||
|
||||
/**
|
||||
* Open session
|
||||
@@ -42,6 +50,7 @@ class Session {
|
||||
* @return TRUE
|
||||
**/
|
||||
function close() {
|
||||
$this->sid=NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -51,9 +60,20 @@ class Session {
|
||||
* @param $id string
|
||||
**/
|
||||
function read($id) {
|
||||
if ($id!=$this->sid)
|
||||
$this->sid=$id;
|
||||
return Cache::instance()->exists($id.'.@',$data)?$data['data']:FALSE;
|
||||
$this->sid=$id;
|
||||
if (!$data=Cache::instance()->get($id.'.@'))
|
||||
return FALSE;
|
||||
if ($data['ip']!=$this->_ip || $data['agent']!=$this->_agent) {
|
||||
$fw=Base::instance();
|
||||
if (!isset($this->onsuspect) || FALSE===$fw->call($this->onsuspect,array($this,$id))) {
|
||||
//NB: `session_destroy` can't be called at that stage (`session_start` not completed)
|
||||
$this->destroy($id);
|
||||
$this->close();
|
||||
$fw->clear('COOKIE.'.session_name());
|
||||
$fw->error(403);
|
||||
}
|
||||
}
|
||||
return $data['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,20 +84,12 @@ class Session {
|
||||
**/
|
||||
function write($id,$data) {
|
||||
$fw=Base::instance();
|
||||
$sent=headers_sent();
|
||||
$headers=$fw->get('HEADERS');
|
||||
$csrf=$fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
|
||||
$fw->hash(mt_rand());
|
||||
$jar=$fw->get('JAR');
|
||||
if ($id!=$this->sid)
|
||||
$this->sid=$id;
|
||||
Cache::instance()->set($id.'.@',
|
||||
array(
|
||||
'data'=>$data,
|
||||
'csrf'=>$sent?$this->csrf():$csrf,
|
||||
'ip'=>$fw->get('IP'),
|
||||
'agent'=>isset($headers['User-Agent'])?
|
||||
$headers['User-Agent']:'',
|
||||
'ip'=>$this->_ip,
|
||||
'agent'=>$this->_agent,
|
||||
'stamp'=>time()
|
||||
),
|
||||
$jar['expire']?($jar['expire']-time()):0
|
||||
@@ -92,9 +104,6 @@ class Session {
|
||||
**/
|
||||
function destroy($id) {
|
||||
Cache::instance()->clear($id.'.@');
|
||||
setcookie(session_name(),'',strtotime('-1 year'));
|
||||
unset($_COOKIE[session_name()]);
|
||||
header_remove('Set-Cookie');
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -109,50 +118,55 @@ class Session {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return anti-CSRF token
|
||||
* @return string|FALSE
|
||||
**/
|
||||
* Return session id (if session has started)
|
||||
* @return string|NULL
|
||||
**/
|
||||
function sid() {
|
||||
return $this->sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return anti-CSRF token
|
||||
* @return string
|
||||
**/
|
||||
function csrf() {
|
||||
return Cache::instance()->
|
||||
exists(($this->sid?:session_id()).'.@',$data)?
|
||||
$data['csrf']:FALSE;
|
||||
return $this->_csrf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return IP address
|
||||
* @return string|FALSE
|
||||
**/
|
||||
* Return IP address
|
||||
* @return string
|
||||
**/
|
||||
function ip() {
|
||||
return Cache::instance()->
|
||||
exists(($this->sid?:session_id()).'.@',$data)?
|
||||
$data['ip']:FALSE;
|
||||
return $this->_ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Unix timestamp
|
||||
* @return string|FALSE
|
||||
**/
|
||||
* Return Unix timestamp
|
||||
* @return string|FALSE
|
||||
**/
|
||||
function stamp() {
|
||||
return Cache::instance()->
|
||||
exists(($this->sid?:session_id()).'.@',$data)?
|
||||
$data['stamp']:FALSE;
|
||||
if (!$this->sid)
|
||||
session_start();
|
||||
return Cache::instance()->exists($this->sid.'.@',$data)?
|
||||
$data['stamp']:FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTTP user agent
|
||||
* @return string|FALSE
|
||||
**/
|
||||
* Return HTTP user agent
|
||||
* @return string
|
||||
**/
|
||||
function agent() {
|
||||
return Cache::instance()->
|
||||
exists(($this->sid?:session_id()).'.@',$data)?
|
||||
$data['agent']:FALSE;
|
||||
return $this->_agent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate class
|
||||
* @param $onsuspect callback
|
||||
* @param $key string
|
||||
**/
|
||||
function __construct($onsuspect=NULL) {
|
||||
function __construct($onsuspect=NULL,$key=NULL) {
|
||||
$this->onsuspect=$onsuspect;
|
||||
session_set_save_handler(
|
||||
array($this,'open'),
|
||||
array($this,'close'),
|
||||
@@ -162,30 +176,14 @@ class Session {
|
||||
array($this,'cleanup')
|
||||
);
|
||||
register_shutdown_function('session_commit');
|
||||
@session_start();
|
||||
$fw=\Base::instance();
|
||||
$headers=$fw->get('HEADERS');
|
||||
if (($ip=$this->ip()) && $ip!=$fw->get('IP') ||
|
||||
($agent=$this->agent()) &&
|
||||
(!isset($headers['User-Agent']) ||
|
||||
$agent!=$headers['User-Agent'])) {
|
||||
if (isset($onsuspect))
|
||||
$fw->call($onsuspect,array($this));
|
||||
else {
|
||||
session_destroy();
|
||||
$fw->error(403);
|
||||
}
|
||||
}
|
||||
$csrf=$fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
|
||||
$this->_csrf=$fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
|
||||
$fw->hash(mt_rand());
|
||||
$jar=$fw->get('JAR');
|
||||
if (Cache::instance()->exists(($this->sid=session_id()).'.@',$data)) {
|
||||
$data['csrf']=$csrf;
|
||||
Cache::instance()->set($this->sid.'.@',
|
||||
$data,
|
||||
$jar['expire']?($jar['expire']-time()):0
|
||||
);
|
||||
}
|
||||
if ($key)
|
||||
$fw->set($key,$this->_csrf);
|
||||
$this->_agent=isset($headers['User-Agent'])?$headers['User-Agent']:'';
|
||||
$this->_ip=$fw->get('IP');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -182,12 +182,13 @@ class SMTP extends Magic {
|
||||
stream_socket_enable_crypto(
|
||||
$socket,TRUE,STREAM_CRYPTO_METHOD_TLS_CLIENT);
|
||||
$reply=$this->dialog('EHLO '.$fw->get('HOST'),$log);
|
||||
if (preg_match('/8BITMIME/',$reply))
|
||||
$headers['Content-Transfer-Encoding']='8bit';
|
||||
else {
|
||||
$headers['Content-Transfer-Encoding']='quoted-printable';
|
||||
$message=quoted_printable_encode($message);
|
||||
}
|
||||
}
|
||||
if (preg_match('/8BITMIME/',$reply))
|
||||
$headers['Content-Transfer-Encoding']='8bit';
|
||||
else {
|
||||
$headers['Content-Transfer-Encoding']='quoted-printable';
|
||||
$message=preg_replace('/^\.(.+)/m',
|
||||
'..$1',quoted_printable_encode($message));
|
||||
}
|
||||
if ($this->user && $this->pw && preg_match('/AUTH/',$reply)) {
|
||||
// Authenticate
|
||||
@@ -204,9 +205,9 @@ class SMTP extends Magic {
|
||||
$str='';
|
||||
// Stringify headers
|
||||
foreach ($headers as $key=>&$val) {
|
||||
if (!in_array($key,$reqd)) {
|
||||
if (!in_array($key,$reqd) && (!$this->attachments ||
|
||||
$key!='Content-Type' && $key!='Content-Transfer-Encoding'))
|
||||
$str.=$key.': '.$val.$eol;
|
||||
}
|
||||
if (in_array($key,array('From','To','Cc','Bcc')) &&
|
||||
!preg_match('/[<>]/',$val))
|
||||
$val='<'.$val.'>';
|
||||
@@ -221,12 +222,13 @@ class SMTP extends Magic {
|
||||
$this->dialog('DATA',$log);
|
||||
if ($this->attachments) {
|
||||
// Replace Content-Type
|
||||
$hash=uniqid(NULL,TRUE);
|
||||
$type=$headers['Content-Type'];
|
||||
$headers['Content-Type']='multipart/mixed; '.
|
||||
'boundary="'.$hash.'"';
|
||||
unset($headers['Content-Type']);
|
||||
$enc=$headers['Content-Transfer-Encoding'];
|
||||
unset($headers['Content-Transfer-Encoding']);
|
||||
$hash=uniqid(NULL,TRUE);
|
||||
// Send mail headers
|
||||
$out='';
|
||||
$out='Content-Type: multipart/mixed; boundary="'.$hash.'"'.$eol;
|
||||
foreach ($headers as $key=>$val)
|
||||
if ($key!='Bcc')
|
||||
$out.=$key.': '.$val.$eol;
|
||||
@@ -235,16 +237,17 @@ class SMTP extends Magic {
|
||||
$out.=$eol;
|
||||
$out.='--'.$hash.$eol;
|
||||
$out.='Content-Type: '.$type.$eol;
|
||||
$out.=$eol;
|
||||
$out.='Content-Transfer-Encoding: '.$enc.$eol;
|
||||
$out.=$str.$eol;
|
||||
$out.=$message.$eol;
|
||||
foreach ($this->attachments as $attachment) {
|
||||
if (is_array($attachment['filename'])) {
|
||||
list($alias,$file)=each($attachment);
|
||||
list($alias,$file)=each($attachment['filename']);
|
||||
$filename=$alias;
|
||||
$attachment['filename']=$file;
|
||||
}
|
||||
else
|
||||
$filename=basename($attachment);
|
||||
$filename=basename($attachment['filename']);
|
||||
$out.='--'.$hash.$eol;
|
||||
$out.='Content-Type: application/octet-stream'.$eol;
|
||||
$out.='Content-Transfer-Encoding: base64'.$eol;
|
||||
@@ -253,8 +256,8 @@ class SMTP extends Magic {
|
||||
$out.='Content-Disposition: attachment; '.
|
||||
'filename="'.$filename.'"'.$eol;
|
||||
$out.=$eol;
|
||||
$out.=chunk_split(
|
||||
base64_encode(file_get_contents($attachment))).$eol;
|
||||
$out.=chunk_split(base64_encode(
|
||||
file_get_contents($attachment['filename']))).$eol;
|
||||
}
|
||||
$out.=$eol;
|
||||
$out.='--'.$hash.'--'.$eol;
|
||||
@@ -287,7 +290,7 @@ class SMTP extends Magic {
|
||||
* @param $user string
|
||||
* @param $pw string
|
||||
**/
|
||||
function __construct($host,$port,$scheme,$user,$pw) {
|
||||
function __construct($host='localhost',$port=25,$scheme=null,$user=null,$pw=null) {
|
||||
$this->headers=array(
|
||||
'MIME-Version'=>'1.0',
|
||||
'Content-Type'=>'text/plain; '.
|
||||
|
||||
@@ -69,6 +69,7 @@ class Template extends Preview {
|
||||
\Base::instance()->stringify($pair[2]));
|
||||
},$pairs)).')+get_defined_vars()':
|
||||
'get_defined_vars()';
|
||||
$ttl=isset($attrib['ttl'])?(int)$attrib['ttl']:0;
|
||||
return
|
||||
'<?php '.(isset($attrib['if'])?
|
||||
('if ('.$this->token($attrib['if']).') '):'').
|
||||
@@ -76,7 +77,7 @@ class Template extends Preview {
|
||||
(preg_match('/^\{\{(.+?)\}\}$/',$attrib['href'])?
|
||||
$this->token($attrib['href']):
|
||||
Base::instance()->stringify($attrib['href'])).','.
|
||||
'$this->mime,'.$hive.'); ?>');
|
||||
'$this->mime,'.$hive.','.$ttl.'); ?>');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,45 +270,40 @@ class Template extends Preview {
|
||||
**/
|
||||
function parse($text) {
|
||||
// Build tree structure
|
||||
for ($ptr=0,$len=strlen($text),$tree=array(),$node=&$tree,
|
||||
$stack=array(),$depth=0,$tmp='';$ptr<$len;)
|
||||
if (preg_match('/^<(\/?)(?:F3:)?'.
|
||||
for ($ptr=0,$w=5,$len=strlen($text),$tree=array(),$tmp='';$ptr<$len;)
|
||||
if (preg_match('/^(.{0,'.$w.'}?)<(\/?)(?:F3:)?'.
|
||||
'('.$this->tags.')\b((?:\h+[\w-]+'.
|
||||
'(?:\h*=\h*(?:"(?:.+?)"|\'(?:.+?)\'))?|'.
|
||||
'(?:\h*=\h*(?:"(?:.*?)"|\'(?:.*?)\'))?|'.
|
||||
'\h*\{\{.+?\}\})*)\h*(\/?)>/is',
|
||||
substr($text,$ptr),$match)) {
|
||||
if (strlen($tmp))
|
||||
$node[]=$tmp;
|
||||
if (strlen($tmp)||$match[1])
|
||||
$tree[]=$tmp.$match[1];
|
||||
// Element node
|
||||
if ($match[1]) {
|
||||
if ($match[2]) {
|
||||
// Find matching start tag
|
||||
$save=$depth;
|
||||
$found=FALSE;
|
||||
while ($depth>0) {
|
||||
$depth--;
|
||||
foreach ($stack[$depth] as $item)
|
||||
if (is_array($item) && isset($item[$match[2]])) {
|
||||
// Start tag found
|
||||
$found=TRUE;
|
||||
break 2;
|
||||
}
|
||||
$stack=array();
|
||||
for($i=count($tree)-1;$i>=0;$i--) {
|
||||
$item = $tree[$i];
|
||||
if (is_array($item) && array_key_exists($match[3],$item)
|
||||
&& !isset($item[$match[3]][0])) {
|
||||
// Start tag found
|
||||
$tree[$i][$match[3]]+=array_reverse($stack);
|
||||
$tree=array_slice($tree,0,$i+1);
|
||||
break;
|
||||
} else $stack[]=$item;
|
||||
}
|
||||
if (!$found)
|
||||
// Unbalanced tag
|
||||
$depth=$save;
|
||||
$node=&$stack[$depth];
|
||||
}
|
||||
else {
|
||||
// Start tag
|
||||
$stack[$depth]=&$node;
|
||||
$node=&$node[][$match[2]];
|
||||
if ($match[3]) {
|
||||
$node=&$tree[][$match[3]];
|
||||
$node=array();
|
||||
if ($match[4]) {
|
||||
// Process attributes
|
||||
preg_match_all(
|
||||
'/(?:\b([\w-]+)\h*'.
|
||||
'(?:=\h*(?:"(.*?)"|\'(.*?)\'))?|'.
|
||||
'(\{\{.+?\}\}))/s',
|
||||
$match[3],$attr,PREG_SET_ORDER);
|
||||
$match[4],$attr,PREG_SET_ORDER);
|
||||
foreach ($attr as $kv)
|
||||
if (isset($kv[4]))
|
||||
$node['@attrib'][]=$kv[4];
|
||||
@@ -318,26 +314,23 @@ class Template extends Preview {
|
||||
(isset($kv[3]) && $kv[3]!==''?
|
||||
$kv[3]:NULL));
|
||||
}
|
||||
if ($match[4])
|
||||
// Empty tag
|
||||
$node=&$stack[$depth];
|
||||
else
|
||||
$depth++;
|
||||
}
|
||||
$tmp='';
|
||||
$ptr+=strlen($match[0]);
|
||||
$w=5;
|
||||
}
|
||||
else {
|
||||
// Text node
|
||||
$tmp.=substr($text,$ptr,1);
|
||||
$ptr++;
|
||||
$tmp.=substr($text,$ptr,$w);
|
||||
$ptr+=$w;
|
||||
if ($w<50)
|
||||
$w++;
|
||||
}
|
||||
if (strlen($tmp))
|
||||
// Append trailing text
|
||||
$node[]=$tmp;
|
||||
$tree[]=$tmp;
|
||||
// Break references
|
||||
unset($node);
|
||||
unset($stack);
|
||||
return $tree;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ class Web extends Prefab {
|
||||
header('Content-Type: '.($mime?:$this->mime($file)));
|
||||
if ($force)
|
||||
header('Content-Disposition: attachment; '.
|
||||
'filename='.var_export(basename($file),TRUE));
|
||||
'filename="'.basename($file).'"');
|
||||
header('Accept-Ranges: bytes');
|
||||
header('Content-Length: '.$size);
|
||||
header('X-Powered-By: '.Base::instance()->get('PACKAGE'));
|
||||
@@ -259,10 +259,13 @@ class Web extends Prefab {
|
||||
**/
|
||||
protected function _curl($url,$options) {
|
||||
$curl=curl_init($url);
|
||||
curl_setopt($curl,CURLOPT_FOLLOWLOCATION,
|
||||
$options['follow_location']);
|
||||
if (!ini_get('open_basedir'))
|
||||
curl_setopt($curl,CURLOPT_FOLLOWLOCATION,
|
||||
$options['follow_location']);
|
||||
curl_setopt($curl,CURLOPT_MAXREDIRS,
|
||||
$options['max_redirects']);
|
||||
curl_setopt($curl,CURLOPT_PROTOCOLS,CURLPROTO_HTTP|CURLPROTO_HTTPS);
|
||||
curl_setopt($curl,CURLOPT_REDIR_PROTOCOLS,CURLPROTO_HTTP|CURLPROTO_HTTPS);
|
||||
curl_setopt($curl,CURLOPT_CUSTOMREQUEST,$options['method']);
|
||||
if (isset($options['header']))
|
||||
curl_setopt($curl,CURLOPT_HTTPHEADER,$options['header']);
|
||||
@@ -288,6 +291,11 @@ class Web extends Prefab {
|
||||
curl_exec($curl);
|
||||
curl_close($curl);
|
||||
$body=ob_get_clean();
|
||||
if ($options['follow_location'] &&
|
||||
preg_match('/^Location: (.+)$/m',implode(PHP_EOL,$headers),$loc)) {
|
||||
$options['max_redirects']--;
|
||||
return $this->request($loc[1],$options);
|
||||
}
|
||||
return array(
|
||||
'body'=>$body,
|
||||
'headers'=>$headers,
|
||||
@@ -357,7 +365,8 @@ class Web extends Prefab {
|
||||
if (!$socket)
|
||||
return FALSE;
|
||||
stream_set_blocking($socket,TRUE);
|
||||
stream_set_timeout($socket,$options['timeout']);
|
||||
stream_set_timeout($socket,isset($options['timeout'])?
|
||||
$options['timeout']:ini_get('default_socket_timeout'));
|
||||
fputs($socket,$options['method'].' '.$parts['path'].
|
||||
($parts['query']?('?'.$parts['query']):'').' HTTP/1.0'.$eol
|
||||
);
|
||||
@@ -565,7 +574,7 @@ class Web extends Prefab {
|
||||
$src=$fw->read($save);
|
||||
for ($ptr=0,$len=strlen($src);$ptr<$len;) {
|
||||
if (preg_match('/^@import\h+url'.
|
||||
'\(\h*([\'"])(.+?)\1\h*\)[^;]*;/',
|
||||
'\(\h*([\'"])((?!(?:https?:)?\/\/).+?)\1\h*\)[^;]*;/',
|
||||
substr($src,$ptr),$parts)) {
|
||||
$path=dirname($file);
|
||||
$data.=$this->minify(
|
||||
@@ -586,7 +595,8 @@ class Web extends Prefab {
|
||||
// Single-line comment
|
||||
$str=strstr(
|
||||
substr($src,$ptr+2),"\n",TRUE);
|
||||
$ptr+=strlen($str)+2;
|
||||
$ptr+=(empty($str))?
|
||||
strlen(substr($src,$ptr)):strlen($str)+2;
|
||||
}
|
||||
else {
|
||||
// Presume it's a regex pattern
|
||||
@@ -785,7 +795,7 @@ class Web extends Prefab {
|
||||
'ù'=>'u','ű'=>'u','ů'=>'u','ư'=>'u','ū'=>'u','ǚ'=>'u',
|
||||
'ǜ'=>'u','ǔ'=>'u','ǖ'=>'u','ũ'=>'u','ü'=>'ue','в'=>'v',
|
||||
'ŵ'=>'w','ы'=>'y','ÿ'=>'y','ý'=>'y','ŷ'=>'y','ź'=>'z',
|
||||
'ž'=>'z','з'=>'z','ż'=>'z','ж'=>'zh'
|
||||
'ž'=>'z','з'=>'z','ż'=>'z','ж'=>'zh','ь'=>'','ъ'=>''
|
||||
)+Base::instance()->get('DIACRITICS'))))),'-');
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class AccessController extends Controller {
|
||||
|
||||
if( !$loginCheck ){
|
||||
// no user found or LogIn timer expired
|
||||
$this->logOut($f3);
|
||||
$this->logout($f3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -173,9 +173,9 @@ class User extends Controller\Controller{
|
||||
* log the current user out + clear character system log data
|
||||
* @param \Base $f3
|
||||
*/
|
||||
public function logOut(\Base $f3){
|
||||
public function logout(\Base $f3){
|
||||
$this->deleteLog($f3);
|
||||
parent::logOut($f3);
|
||||
parent::logout($f3);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -344,7 +344,7 @@ class User extends Controller\Controller{
|
||||
// remove user
|
||||
$user->erase();
|
||||
|
||||
$this->logOut($f3);
|
||||
$this->logout($f3);
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ class Controller {
|
||||
'expires' => $expireTime->format('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
$authenticationModel = $character->rel('characterTokens');
|
||||
$authenticationModel = $character->rel('characterAuthentications');
|
||||
$authenticationModel->copyfrom($authData);
|
||||
$authenticationModel->save();
|
||||
|
||||
@@ -349,15 +349,26 @@ class Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* log out current user
|
||||
* log out current character
|
||||
* @param \Base $f3
|
||||
*/
|
||||
public function logOut(\Base $f3){
|
||||
// destroy session
|
||||
public function logout(\Base $f3){
|
||||
$params = (array)$f3->get('POST');
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// delete server side cookie validation data
|
||||
// for the current character as well
|
||||
if(
|
||||
$params['clearCookies'] === '1' &&
|
||||
( $activeCharacter = $this->getCharacter())
|
||||
){
|
||||
$activeCharacter->logout();
|
||||
}
|
||||
|
||||
// destroy session login data -------------------------------
|
||||
$f3->clear('SESSION');
|
||||
|
||||
if( $f3->get('AJAX') ){
|
||||
$params = $f3->get('POST');
|
||||
$return = (object) [];
|
||||
if(
|
||||
isset($params['reroute']) &&
|
||||
@@ -370,7 +381,6 @@ class Controller {
|
||||
}
|
||||
|
||||
echo json_encode($return);
|
||||
die();
|
||||
}else{
|
||||
// redirect to landing page
|
||||
$f3->reroute('@login');
|
||||
|
||||
@@ -89,6 +89,10 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
$self->beforeInsertEvent($self);
|
||||
});
|
||||
|
||||
$this->beforeerase( function($self){
|
||||
$self->beforeeraseEvent($self);
|
||||
});
|
||||
|
||||
$this->aftererase( function($self){
|
||||
$self->aftereraseEvent($self);
|
||||
});
|
||||
@@ -409,6 +413,15 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* can be overwritten
|
||||
* @return bool
|
||||
*/
|
||||
public function beforeeraseEvent($self){
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* can be overwritten
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
namespace Model;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
use Controller;
|
||||
|
||||
class CharacterAuthenticationModel extends BasicModel{
|
||||
|
||||
@@ -51,4 +52,23 @@ class CharacterAuthenticationModel extends BasicModel{
|
||||
'index' => true
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* can be overwritten
|
||||
* @param $self CharacterAuthenticationModel
|
||||
* @return bool
|
||||
*/
|
||||
public function beforeeraseEvent($self){
|
||||
// clear existing client Cookies as well
|
||||
$cookieName = Controller\Controller::COOKIE_PREFIX_CHARACTER;
|
||||
$cookieName .= '_' . $this->characterId->getCookieName();
|
||||
$self::getF3()->clear('COOKIE.' . $cookieName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -94,7 +94,7 @@ class CharacterModel extends BasicModel {
|
||||
'characterMaps' => [
|
||||
'has-many' => ['Model\CharacterMapModel', 'characterId']
|
||||
],
|
||||
'characterTokens' => [
|
||||
'characterAuthentications' => [
|
||||
'has-many' => ['Model\CharacterAuthenticationModel', 'characterId']
|
||||
]
|
||||
];
|
||||
@@ -538,4 +538,15 @@ class CharacterModel extends BasicModel {
|
||||
return $maps;
|
||||
}
|
||||
|
||||
public function logout(){
|
||||
if($this->characterAuthentications){
|
||||
foreach($this->characterAuthentications as $characterAuthentication){
|
||||
/**
|
||||
* @var $characterAuthentication CharacterAuthenticationModel
|
||||
*/
|
||||
$characterAuthentication->erase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,7 +15,7 @@ define(['jquery'], function($) {
|
||||
sendInviteKey: 'api/user/sendInvite', // ajax URL - send registration key
|
||||
getCookieCharacterData: 'api/user/getCookieCharacter', // ajax URL - get character data from cookie
|
||||
logIn: 'api/user/logIn', // ajax URL - login
|
||||
logOut: 'api/user/logOut', // ajax URL - logout
|
||||
logout: 'api/user/logout', // ajax URL - logout
|
||||
deleteLog: 'api/user/deleteLog', // ajax URL - delete character log
|
||||
saveUserConfig: 'api/user/saveAccount', // ajax URL - saves/update user account
|
||||
deleteAccount: 'api/user/deleteAccount', // ajax URL - delete Account data
|
||||
|
||||
@@ -230,7 +230,7 @@ define([
|
||||
class: 'fa fa-sign-in fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('Logout');
|
||||
$(document).triggerMenuEvent('Logout', {clearCookies: 1});
|
||||
})
|
||||
)
|
||||
);
|
||||
@@ -590,10 +590,19 @@ define([
|
||||
});
|
||||
|
||||
$(document).on('pf:menuLogout', function(e, data){
|
||||
|
||||
var clearCookies = false;
|
||||
if( typeof data === 'object' ){
|
||||
if( data.hasOwnProperty('clearCookies') ){
|
||||
clearCookies = data.clearCookies;
|
||||
}
|
||||
}
|
||||
|
||||
// logout
|
||||
Util.logout({
|
||||
ajaxData: {
|
||||
reroute: 1
|
||||
reroute: 1,
|
||||
clearCookies: clearCookies
|
||||
}
|
||||
});
|
||||
return false;
|
||||
|
||||
@@ -1778,7 +1778,7 @@ define([
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.logOut,
|
||||
url: Init.path.logout,
|
||||
data: data,
|
||||
dataType: 'json'
|
||||
}).done(function(data){
|
||||
|
||||
@@ -15,7 +15,7 @@ define(['jquery'], function($) {
|
||||
sendInviteKey: 'api/user/sendInvite', // ajax URL - send registration key
|
||||
getCookieCharacterData: 'api/user/getCookieCharacter', // ajax URL - get character data from cookie
|
||||
logIn: 'api/user/logIn', // ajax URL - login
|
||||
logOut: 'api/user/logOut', // ajax URL - logout
|
||||
logout: 'api/user/logout', // ajax URL - logout
|
||||
deleteLog: 'api/user/deleteLog', // ajax URL - delete character log
|
||||
saveUserConfig: 'api/user/saveAccount', // ajax URL - saves/update user account
|
||||
deleteAccount: 'api/user/deleteAccount', // ajax URL - delete Account data
|
||||
|
||||
@@ -230,7 +230,7 @@ define([
|
||||
class: 'fa fa-sign-in fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('Logout');
|
||||
$(document).triggerMenuEvent('Logout', {clearCookies: 1});
|
||||
})
|
||||
)
|
||||
);
|
||||
@@ -590,10 +590,19 @@ define([
|
||||
});
|
||||
|
||||
$(document).on('pf:menuLogout', function(e, data){
|
||||
|
||||
var clearCookies = false;
|
||||
if( typeof data === 'object' ){
|
||||
if( data.hasOwnProperty('clearCookies') ){
|
||||
clearCookies = data.clearCookies;
|
||||
}
|
||||
}
|
||||
|
||||
// logout
|
||||
Util.logout({
|
||||
ajaxData: {
|
||||
reroute: 1
|
||||
reroute: 1,
|
||||
clearCookies: clearCookies
|
||||
}
|
||||
});
|
||||
return false;
|
||||
|
||||
@@ -1778,7 +1778,7 @@ define([
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.logOut,
|
||||
url: Init.path.logout,
|
||||
data: data,
|
||||
dataType: 'json'
|
||||
}).done(function(data){
|
||||
|
||||
Reference in New Issue
Block a user