|
@@ -2,7 +2,7 @@
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
|
|
|
|
|
|
- Copyright (c) 2009-2017 F3::Factory/Bong Cosca, All rights reserved.
|
|
|
|
|
|
|
+ Copyright (c) 2009-2019 F3::Factory/Bong Cosca, All rights reserved.
|
|
|
|
|
|
|
|
This file is part of the Fat-Free Framework (http://fatfreeframework.com).
|
|
This file is part of the Fat-Free Framework (http://fatfreeframework.com).
|
|
|
|
|
|
|
@@ -29,7 +29,7 @@ abstract class Prefab {
|
|
|
**/
|
|
**/
|
|
|
static function instance() {
|
|
static function instance() {
|
|
|
if (!Registry::exists($class=get_called_class())) {
|
|
if (!Registry::exists($class=get_called_class())) {
|
|
|
- $ref=new Reflectionclass($class);
|
|
|
|
|
|
|
+ $ref=new ReflectionClass($class);
|
|
|
$args=func_get_args();
|
|
$args=func_get_args();
|
|
|
Registry::set($class,
|
|
Registry::set($class,
|
|
|
$args?$ref->newinstanceargs($args):new $class);
|
|
$args?$ref->newinstanceargs($args):new $class);
|
|
@@ -45,7 +45,7 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
//@{ Framework details
|
|
//@{ Framework details
|
|
|
const
|
|
const
|
|
|
PACKAGE='Fat-Free Framework',
|
|
PACKAGE='Fat-Free Framework',
|
|
|
- VERSION='3.6.5-Release';
|
|
|
|
|
|
|
+ VERSION='3.7.2-Release';
|
|
|
//@}
|
|
//@}
|
|
|
|
|
|
|
|
//@{ HTTP status codes (RFC 2616)
|
|
//@{ HTTP status codes (RFC 2616)
|
|
@@ -67,6 +67,7 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
HTTP_304='Not Modified',
|
|
HTTP_304='Not Modified',
|
|
|
HTTP_305='Use Proxy',
|
|
HTTP_305='Use Proxy',
|
|
|
HTTP_307='Temporary Redirect',
|
|
HTTP_307='Temporary Redirect',
|
|
|
|
|
+ HTTP_308='Permanent Redirect',
|
|
|
HTTP_400='Bad Request',
|
|
HTTP_400='Bad Request',
|
|
|
HTTP_401='Unauthorized',
|
|
HTTP_401='Unauthorized',
|
|
|
HTTP_402='Payment Required',
|
|
HTTP_402='Payment Required',
|
|
@@ -85,12 +86,19 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
HTTP_415='Unsupported Media Type',
|
|
HTTP_415='Unsupported Media Type',
|
|
|
HTTP_416='Requested Range Not Satisfiable',
|
|
HTTP_416='Requested Range Not Satisfiable',
|
|
|
HTTP_417='Expectation Failed',
|
|
HTTP_417='Expectation Failed',
|
|
|
|
|
+ HTTP_421='Misdirected Request',
|
|
|
|
|
+ HTTP_422='Unprocessable Entity',
|
|
|
|
|
+ HTTP_423='Locked',
|
|
|
|
|
+ HTTP_429='Too Many Requests',
|
|
|
|
|
+ HTTP_451='Unavailable For Legal Reasons',
|
|
|
HTTP_500='Internal Server Error',
|
|
HTTP_500='Internal Server Error',
|
|
|
HTTP_501='Not Implemented',
|
|
HTTP_501='Not Implemented',
|
|
|
HTTP_502='Bad Gateway',
|
|
HTTP_502='Bad Gateway',
|
|
|
HTTP_503='Service Unavailable',
|
|
HTTP_503='Service Unavailable',
|
|
|
HTTP_504='Gateway Timeout',
|
|
HTTP_504='Gateway Timeout',
|
|
|
- HTTP_505='HTTP Version Not Supported';
|
|
|
|
|
|
|
+ HTTP_505='HTTP Version Not Supported',
|
|
|
|
|
+ HTTP_507='Insufficient Storage',
|
|
|
|
|
+ HTTP_511='Network Authentication Required';
|
|
|
//@}
|
|
//@}
|
|
|
|
|
|
|
|
const
|
|
const
|
|
@@ -114,6 +122,7 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
const
|
|
const
|
|
|
E_Pattern='Invalid routing pattern: %s',
|
|
E_Pattern='Invalid routing pattern: %s',
|
|
|
E_Named='Named route does not exist: %s',
|
|
E_Named='Named route does not exist: %s',
|
|
|
|
|
+ E_Alias='Invalid named route alias: %s',
|
|
|
E_Fatal='Fatal error: %s',
|
|
E_Fatal='Fatal error: %s',
|
|
|
E_Open='Unable to open %s',
|
|
E_Open='Unable to open %s',
|
|
|
E_Routes='No routes specified',
|
|
E_Routes='No routes specified',
|
|
@@ -168,17 +177,17 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
}
|
|
}
|
|
|
else {
|
|
else {
|
|
|
$i=0;
|
|
$i=0;
|
|
|
- $url=preg_replace_callback('/@(\w+)|(\*)/',
|
|
|
|
|
|
|
+ $url=preg_replace_callback('/(\{)?@(\w+)(?(1)\})|(\*)/',
|
|
|
function($match) use(&$i,$args) {
|
|
function($match) use(&$i,$args) {
|
|
|
- if (isset($match[1]) &&
|
|
|
|
|
- array_key_exists($match[1],$args))
|
|
|
|
|
- return $args[$match[1]];
|
|
|
|
|
if (isset($match[2]) &&
|
|
if (isset($match[2]) &&
|
|
|
- array_key_exists($match[2],$args)) {
|
|
|
|
|
- if (!is_array($args[$match[2]]))
|
|
|
|
|
- return $args[$match[2]];
|
|
|
|
|
|
|
+ array_key_exists($match[2],$args))
|
|
|
|
|
+ return $args[$match[2]];
|
|
|
|
|
+ if (isset($match[3]) &&
|
|
|
|
|
+ array_key_exists($match[3],$args)) {
|
|
|
|
|
+ if (!is_array($args[$match[3]]))
|
|
|
|
|
+ return $args[$match[3]];
|
|
|
$i++;
|
|
$i++;
|
|
|
- return $args[$match[2]][$i-1];
|
|
|
|
|
|
|
+ return $args[$match[3]][$i-1];
|
|
|
}
|
|
}
|
|
|
return $match[0];
|
|
return $match[0];
|
|
|
},$url);
|
|
},$url);
|
|
@@ -226,9 +235,31 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
* Convert JS-style token to PHP expression
|
|
* Convert JS-style token to PHP expression
|
|
|
* @return string
|
|
* @return string
|
|
|
* @param $str string
|
|
* @param $str string
|
|
|
- **/
|
|
|
|
|
- function compile($str) {
|
|
|
|
|
- return preg_replace_callback(
|
|
|
|
|
|
|
+ * @param $evaluate bool compile expressions as well or only convert variable access
|
|
|
|
|
+ **/
|
|
|
|
|
+ function compile($str, $evaluate=TRUE) {
|
|
|
|
|
+ return (!$evaluate)
|
|
|
|
|
+ ? preg_replace_callback(
|
|
|
|
|
+ '/^@(\w+)((?:\..+|\[(?:(?:[^\[\]]*|(?R))*)\])*)/',
|
|
|
|
|
+ function($expr) {
|
|
|
|
|
+ $str='$'.$expr[1];
|
|
|
|
|
+ if (isset($expr[2]))
|
|
|
|
|
+ $str.=preg_replace_callback(
|
|
|
|
|
+ '/\.([^.\[\]]+)|\[((?:[^\[\]\'"]*|(?R))*)\]/',
|
|
|
|
|
+ function($sub) {
|
|
|
|
|
+ $val=isset($sub[2]) ? $sub[2] : $sub[1];
|
|
|
|
|
+ if (ctype_digit($val))
|
|
|
|
|
+ $val=(int)$val;
|
|
|
|
|
+ $out='['.$this->export($val).']';
|
|
|
|
|
+ return $out;
|
|
|
|
|
+ },
|
|
|
|
|
+ $expr[2]
|
|
|
|
|
+ );
|
|
|
|
|
+ return $str;
|
|
|
|
|
+ },
|
|
|
|
|
+ $str
|
|
|
|
|
+ )
|
|
|
|
|
+ : preg_replace_callback(
|
|
|
'/(?<!\w)@(\w+(?:(?:\->|::)\w+)?)'.
|
|
'/(?<!\w)@(\w+(?:(?:\->|::)\w+)?)'.
|
|
|
'((?:\.\w+|\[(?:(?:[^\[\]]*|(?R))*)\]|(?:\->|::)\w+|\()*)/',
|
|
'((?:\.\w+|\[(?:(?:[^\[\]]*|(?R))*)\]|(?:\->|::)\w+|\()*)/',
|
|
|
function($expr) {
|
|
function($expr) {
|
|
@@ -292,7 +323,7 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
elseif ($obj) {
|
|
elseif ($obj) {
|
|
|
$obj=FALSE;
|
|
$obj=FALSE;
|
|
|
if (!is_object($var))
|
|
if (!is_object($var))
|
|
|
- $var=new stdclass;
|
|
|
|
|
|
|
+ $var=new stdClass;
|
|
|
if ($add || property_exists($var,$part))
|
|
if ($add || property_exists($var,$part))
|
|
|
$var=&$var->$part;
|
|
$var=&$var->$part;
|
|
|
else {
|
|
else {
|
|
@@ -355,12 +386,22 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
$parts=$this->cut($key);
|
|
$parts=$this->cut($key);
|
|
|
$jar=$this->unserialize($this->serialize($this->hive['JAR']));
|
|
$jar=$this->unserialize($this->serialize($this->hive['JAR']));
|
|
|
unset($jar['lifetime']);
|
|
unset($jar['lifetime']);
|
|
|
- if (isset($_COOKIE[$parts[1]]))
|
|
|
|
|
- call_user_func_array('setcookie',
|
|
|
|
|
- array_merge([$parts[1],NULL],['expire'=>0]+$jar));
|
|
|
|
|
- if ($ttl)
|
|
|
|
|
- $jar['expire']=$time+$ttl;
|
|
|
|
|
- call_user_func_array('setcookie',[$parts[1],$val]+$jar);
|
|
|
|
|
|
|
+ if (version_compare(PHP_VERSION, '7.3.0') >= 0) {
|
|
|
|
|
+ unset($jar['expire']);
|
|
|
|
|
+ if (isset($_COOKIE[$parts[1]]))
|
|
|
|
|
+ setcookie($parts[1],NULL,['expires'=>0]+$jar);
|
|
|
|
|
+ if ($ttl)
|
|
|
|
|
+ $jar['expires']=$time+$ttl;
|
|
|
|
|
+ setcookie($parts[1],$val,$jar);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ unset($jar['samesite']);
|
|
|
|
|
+ if (isset($_COOKIE[$parts[1]]))
|
|
|
|
|
+ call_user_func_array('setcookie',
|
|
|
|
|
+ array_merge([$parts[1],NULL],['expire'=>0]+$jar));
|
|
|
|
|
+ if ($ttl)
|
|
|
|
|
+ $jar['expire']=$time+$ttl;
|
|
|
|
|
+ call_user_func_array('setcookie',[$parts[1],$val]+$jar);
|
|
|
|
|
+ }
|
|
|
$_COOKIE[$parts[1]]=$val;
|
|
$_COOKIE[$parts[1]]=$val;
|
|
|
return $val;
|
|
return $val;
|
|
|
}
|
|
}
|
|
@@ -405,7 +446,12 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
$jar=$this->unserialize($this->serialize($this->hive['JAR']));
|
|
$jar=$this->unserialize($this->serialize($this->hive['JAR']));
|
|
|
unset($jar['expire']);
|
|
unset($jar['expire']);
|
|
|
if (!headers_sent() && session_status()!=PHP_SESSION_ACTIVE)
|
|
if (!headers_sent() && session_status()!=PHP_SESSION_ACTIVE)
|
|
|
- call_user_func_array('session_set_cookie_params',$jar);
|
|
|
|
|
|
|
+ if (version_compare(PHP_VERSION, '7.3.0') >= 0)
|
|
|
|
|
+ session_set_cookie_params($jar);
|
|
|
|
|
+ else {
|
|
|
|
|
+ unset($jar['samesite']);
|
|
|
|
|
+ call_user_func_array('session_set_cookie_params',$jar);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
if ($ttl)
|
|
if ($ttl)
|
|
@@ -436,7 +482,6 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Unset hive key
|
|
* Unset hive key
|
|
|
- * @return NULL
|
|
|
|
|
* @param $key string
|
|
* @param $key string
|
|
|
**/
|
|
**/
|
|
|
function clear($key) {
|
|
function clear($key) {
|
|
@@ -453,8 +498,15 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
$jar=$this->hive['JAR'];
|
|
$jar=$this->hive['JAR'];
|
|
|
unset($jar['lifetime']);
|
|
unset($jar['lifetime']);
|
|
|
$jar['expire']=0;
|
|
$jar['expire']=0;
|
|
|
- call_user_func_array('setcookie',
|
|
|
|
|
- array_merge([$parts[1],NULL],$jar));
|
|
|
|
|
|
|
+ if (version_compare(PHP_VERSION, '7.3.0') >= 0) {
|
|
|
|
|
+ $jar['expires']=$jar['expire'];
|
|
|
|
|
+ unset($jar['expire']);
|
|
|
|
|
+ setcookie($parts[1],NULL,$jar);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ unset($jar['samesite']);
|
|
|
|
|
+ call_user_func_array('setcookie',
|
|
|
|
|
+ array_merge([$parts[1],NULL],$jar));
|
|
|
|
|
+ }
|
|
|
unset($_COOKIE[$parts[1]]);
|
|
unset($_COOKIE[$parts[1]]);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -473,7 +525,9 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
// Reset global to default value
|
|
// Reset global to default value
|
|
|
$this->hive[$parts[0]]=$this->init[$parts[0]];
|
|
$this->hive[$parts[0]]=$this->init[$parts[0]];
|
|
|
else {
|
|
else {
|
|
|
- eval('unset('.$this->compile('@this->hive.'.$key).');');
|
|
|
|
|
|
|
+ $val=preg_replace('/^(\$hive)/','$this->hive',
|
|
|
|
|
+ $this->compile('@hive.'.$key, FALSE));
|
|
|
|
|
+ eval('unset('.$val.');');
|
|
|
if ($parts[0]=='SESSION') {
|
|
if ($parts[0]=='SESSION') {
|
|
|
session_commit();
|
|
session_commit();
|
|
|
session_start();
|
|
session_start();
|
|
@@ -512,7 +566,6 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Multi-variable assignment using associative array
|
|
* Multi-variable assignment using associative array
|
|
|
- * @return NULL
|
|
|
|
|
* @param $vars array
|
|
* @param $vars array
|
|
|
* @param $prefix string
|
|
* @param $prefix string
|
|
|
* @param $ttl int
|
|
* @param $ttl int
|
|
@@ -886,7 +939,22 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
'(?:,\s*(?P<mod>(?:\w+(?:\s*\{.+?\}\s*,?\s*)?)*)'.
|
|
'(?:,\s*(?P<mod>(?:\w+(?:\s*\{.+?\}\s*,?\s*)?)*)'.
|
|
|
'(?:,\s*(?P<prop>.+?))?)?)?\s*\}/',
|
|
'(?:,\s*(?P<prop>.+?))?)?)?\s*\}/',
|
|
|
function($expr) use($args,$conv) {
|
|
function($expr) use($args,$conv) {
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @var string $pos
|
|
|
|
|
+ * @var string $mod
|
|
|
|
|
+ * @var string $type
|
|
|
|
|
+ * @var string $prop
|
|
|
|
|
+ */
|
|
|
extract($expr);
|
|
extract($expr);
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @var string $thousands_sep
|
|
|
|
|
+ * @var string $negative_sign
|
|
|
|
|
+ * @var string $positive_sign
|
|
|
|
|
+ * @var string $frac_digits
|
|
|
|
|
+ * @var string $decimal_point
|
|
|
|
|
+ * @var string $int_curr_symbol
|
|
|
|
|
+ * @var string $currency_symbol
|
|
|
|
|
+ */
|
|
|
extract($conv);
|
|
extract($conv);
|
|
|
if (!array_key_exists($pos,$args))
|
|
if (!array_key_exists($pos,$args))
|
|
|
return $expr[0];
|
|
return $expr[0];
|
|
@@ -907,6 +975,8 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
$mod,$matches,PREG_SET_ORDER);
|
|
$mod,$matches,PREG_SET_ORDER);
|
|
|
$ord=['zero','one','two'];
|
|
$ord=['zero','one','two'];
|
|
|
foreach ($matches as $match) {
|
|
foreach ($matches as $match) {
|
|
|
|
|
+ /** @var string $tag */
|
|
|
|
|
+ /** @var string $data */
|
|
|
extract($match);
|
|
extract($match);
|
|
|
if (isset($ord[$args[$pos]]) &&
|
|
if (isset($ord[$args[$pos]]) &&
|
|
|
$tag==$ord[$args[$pos]] || $tag=='other')
|
|
$tag==$ord[$args[$pos]] || $tag=='other')
|
|
@@ -924,7 +994,8 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
$cstm=!$int=($prop=='int'))
|
|
$cstm=!$int=($prop=='int'))
|
|
|
$currency_symbol=$prop;
|
|
$currency_symbol=$prop;
|
|
|
if (!$cstm &&
|
|
if (!$cstm &&
|
|
|
- function_exists('money_format'))
|
|
|
|
|
|
|
+ function_exists('money_format') &&
|
|
|
|
|
+ version_compare(PHP_VERSION,'7.4.0')<0)
|
|
|
return money_format(
|
|
return money_format(
|
|
|
'%'.($int?'i':'n'),$args[$pos]);
|
|
'%'.($int?'i':'n'),$args[$pos]);
|
|
|
$fmt=[
|
|
$fmt=[
|
|
@@ -977,19 +1048,21 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
$args[$pos],
|
|
$args[$pos],
|
|
|
isset($prop)?
|
|
isset($prop)?
|
|
|
$prop:
|
|
$prop:
|
|
|
- $frac?strlen($frac)-2:0,
|
|
|
|
|
|
|
+ ($frac?strlen($frac)-2:0),
|
|
|
$decimal_point,$thousands_sep);
|
|
$decimal_point,$thousands_sep);
|
|
|
case 'date':
|
|
case 'date':
|
|
|
- $prop='%d %B %Y';
|
|
|
|
|
if (empty($mod) || $mod=='short')
|
|
if (empty($mod) || $mod=='short')
|
|
|
$prop='%x';
|
|
$prop='%x';
|
|
|
elseif ($mod=='full')
|
|
elseif ($mod=='full')
|
|
|
- $prop='%A, '.$prop;
|
|
|
|
|
|
|
+ $prop='%A, %d %B %Y';
|
|
|
|
|
+ elseif ($mod!='custom')
|
|
|
|
|
+ $prop='%d %B %Y';
|
|
|
return strftime($prop,$args[$pos]);
|
|
return strftime($prop,$args[$pos]);
|
|
|
case 'time':
|
|
case 'time':
|
|
|
- $prop='%r';
|
|
|
|
|
if (empty($mod) || $mod=='short')
|
|
if (empty($mod) || $mod=='short')
|
|
|
$prop='%X';
|
|
$prop='%X';
|
|
|
|
|
+ elseif ($mod!='custom')
|
|
|
|
|
+ $prop='%r';
|
|
|
return strftime($prop,$args[$pos]);
|
|
return strftime($prop,$args[$pos]);
|
|
|
default:
|
|
default:
|
|
|
return $expr[0];
|
|
return $expr[0];
|
|
@@ -1058,8 +1131,8 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
function lexicon($path,$ttl=0) {
|
|
function lexicon($path,$ttl=0) {
|
|
|
$languages=$this->languages?:explode(',',$this->fallback);
|
|
$languages=$this->languages?:explode(',',$this->fallback);
|
|
|
$cache=Cache::instance();
|
|
$cache=Cache::instance();
|
|
|
- if ($cache->exists(
|
|
|
|
|
- $hash=$this->hash(implode(',',$languages)).'.dic',$lex))
|
|
|
|
|
|
|
+ if ($ttl && $cache->exists(
|
|
|
|
|
+ $hash=$this->hash(implode(',',$languages).$path).'.dic',$lex))
|
|
|
return $lex;
|
|
return $lex;
|
|
|
$lex=[];
|
|
$lex=[];
|
|
|
foreach ($languages as $lang)
|
|
foreach ($languages as $lang)
|
|
@@ -1068,6 +1141,9 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
is_file($file=$base.'.php')) &&
|
|
is_file($file=$base.'.php')) &&
|
|
|
is_array($dict=require($file)))
|
|
is_array($dict=require($file)))
|
|
|
$lex+=$dict;
|
|
$lex+=$dict;
|
|
|
|
|
+ elseif (is_file($file=$base.'.json') &&
|
|
|
|
|
+ is_array($dict=json_decode(file_get_contents($file), true)))
|
|
|
|
|
+ $lex+=$dict;
|
|
|
elseif (is_file($file=$base.'.ini')) {
|
|
elseif (is_file($file=$base.'.ini')) {
|
|
|
preg_match_all(
|
|
preg_match_all(
|
|
|
'/(?<=^|\n)(?:'.
|
|
'/(?<=^|\n)(?:'.
|
|
@@ -1134,7 +1210,6 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Send cache metadata to HTTP client
|
|
* Send cache metadata to HTTP client
|
|
|
- * @return NULL
|
|
|
|
|
* @param $secs int
|
|
* @param $secs int
|
|
|
**/
|
|
**/
|
|
|
function expire($secs=0) {
|
|
function expire($secs=0) {
|
|
@@ -1248,7 +1323,6 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
* Log error; Execute ONERROR handler if defined, else display
|
|
* Log error; Execute ONERROR handler if defined, else display
|
|
|
* default error page (HTML for synchronous requests, JSON string
|
|
* default error page (HTML for synchronous requests, JSON string
|
|
|
* for AJAX requests)
|
|
* for AJAX requests)
|
|
|
- * @return NULL
|
|
|
|
|
* @param $code int
|
|
* @param $code int
|
|
|
* @param $text string
|
|
* @param $text string
|
|
|
* @param $trace array
|
|
* @param $trace array
|
|
@@ -1373,8 +1447,9 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
* @param $name string
|
|
* @param $name string
|
|
|
* @param $params array|string
|
|
* @param $params array|string
|
|
|
* @param $query string|array
|
|
* @param $query string|array
|
|
|
|
|
+ * @param $fragment string
|
|
|
**/
|
|
**/
|
|
|
- function alias($name,$params=[],$query=NULL) {
|
|
|
|
|
|
|
+ function alias($name,$params=[],$query=NULL,$fragment=NULL) {
|
|
|
if (!is_array($params))
|
|
if (!is_array($params))
|
|
|
$params=$this->parse($params);
|
|
$params=$this->parse($params);
|
|
|
if (empty($this->hive['ALIASES'][$name]))
|
|
if (empty($this->hive['ALIASES'][$name]))
|
|
@@ -1382,7 +1457,7 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
$url=$this->build($this->hive['ALIASES'][$name],$params);
|
|
$url=$this->build($this->hive['ALIASES'][$name],$params);
|
|
|
if (is_array($query))
|
|
if (is_array($query))
|
|
|
$query=http_build_query($query);
|
|
$query=http_build_query($query);
|
|
|
- return $url.($query?('?'.$query):'');
|
|
|
|
|
|
|
+ return $url.($query?('?'.$query):'').($fragment?'#'.$fragment:'');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1403,8 +1478,11 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
}
|
|
}
|
|
|
preg_match('/([\|\w]+)\h+(?:(?:@?(.+?)\h*:\h*)?(@(\w+)|[^\h]+))'.
|
|
preg_match('/([\|\w]+)\h+(?:(?:@?(.+?)\h*:\h*)?(@(\w+)|[^\h]+))'.
|
|
|
'(?:\h+\[('.implode('|',$types).')\])?/u',$pattern,$parts);
|
|
'(?:\h+\[('.implode('|',$types).')\])?/u',$pattern,$parts);
|
|
|
- if (isset($parts[2]) && $parts[2])
|
|
|
|
|
|
|
+ if (isset($parts[2]) && $parts[2]) {
|
|
|
|
|
+ if (!preg_match('/^\w+$/',$parts[2]))
|
|
|
|
|
+ user_error(sprintf(self::E_Alias,$parts[2]),E_USER_ERROR);
|
|
|
$this->hive['ALIASES'][$alias=$parts[2]]=$parts[3];
|
|
$this->hive['ALIASES'][$alias=$parts[2]]=$parts[3];
|
|
|
|
|
+ }
|
|
|
elseif (!empty($parts[4])) {
|
|
elseif (!empty($parts[4])) {
|
|
|
if (empty($this->hive['ALIASES'][$parts[4]]))
|
|
if (empty($this->hive['ALIASES'][$parts[4]]))
|
|
|
user_error(sprintf(self::E_Named,$parts[4]),E_USER_ERROR);
|
|
user_error(sprintf(self::E_Named,$parts[4]),E_USER_ERROR);
|
|
@@ -1433,15 +1511,18 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
$url=$this->hive['REALM'];
|
|
$url=$this->hive['REALM'];
|
|
|
if (is_array($url))
|
|
if (is_array($url))
|
|
|
$url=call_user_func_array([$this,'alias'],$url);
|
|
$url=call_user_func_array([$this,'alias'],$url);
|
|
|
- elseif (preg_match('/^(?:@?([^\/()?]+)(?:(\(.+?)\))*(\?.+)*)/',
|
|
|
|
|
- $url,$parts) &&
|
|
|
|
|
- isset($this->hive['ALIASES'][$parts[1]]))
|
|
|
|
|
- $url=$this->hive['ALIASES'][$parts[1]];
|
|
|
|
|
- $url=$this->build($url,isset($parts[2])?$this->parse($parts[2]):[]).
|
|
|
|
|
- (isset($parts[3])?$parts[3]:'');
|
|
|
|
|
|
|
+ elseif (preg_match('/^(?:@([^\/()?#]+)(?:\((.+?)\))*(\?[^#]+)*(#.+)*)/',
|
|
|
|
|
+ $url,$parts) && isset($this->hive['ALIASES'][$parts[1]]))
|
|
|
|
|
+ $url=$this->build($this->hive['ALIASES'][$parts[1]],
|
|
|
|
|
+ isset($parts[2])?$this->parse($parts[2]):[]).
|
|
|
|
|
+ (isset($parts[3])?$parts[3]:'').(isset($parts[4])?$parts[4]:'');
|
|
|
|
|
+ else
|
|
|
|
|
+ $url=$this->build($url);
|
|
|
if (($handler=$this->hive['ONREROUTE']) &&
|
|
if (($handler=$this->hive['ONREROUTE']) &&
|
|
|
- $this->call($handler,[$url,$permanent])!==FALSE)
|
|
|
|
|
|
|
+ $this->call($handler,[$url,$permanent,$die])!==FALSE)
|
|
|
return;
|
|
return;
|
|
|
|
|
+ if ($url[0]!='/' && !preg_match('/^\w+:\/\//i',$url))
|
|
|
|
|
+ $url='/'.$url;
|
|
|
if ($url[0]=='/' && (empty($url[1]) || $url[1]!='/')) {
|
|
if ($url[0]=='/' && (empty($url[1]) || $url[1]!='/')) {
|
|
|
$port=$this->hive['PORT'];
|
|
$port=$this->hive['PORT'];
|
|
|
$port=in_array($port,[80,443])?'':(':'.$port);
|
|
$port=in_array($port,[80,443])?'':(':'.$port);
|
|
@@ -1802,7 +1883,8 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
if ($parts[2]=='->') {
|
|
if ($parts[2]=='->') {
|
|
|
if (is_subclass_of($parts[1],'Prefab'))
|
|
if (is_subclass_of($parts[1],'Prefab'))
|
|
|
$parts[1]=call_user_func($parts[1].'::instance');
|
|
$parts[1]=call_user_func($parts[1].'::instance');
|
|
|
- elseif ($container=$this->get('CONTAINER')) {
|
|
|
|
|
|
|
+ elseif (isset($this->hive['CONTAINER'])) {
|
|
|
|
|
+ $container=$this->hive['CONTAINER'];
|
|
|
if (is_object($container) && is_callable([$container,'has'])
|
|
if (is_object($container) && is_callable([$container,'has'])
|
|
|
&& $container->has($parts[1])) // PSR11
|
|
&& $container->has($parts[1])) // PSR11
|
|
|
$parts[1]=call_user_func([$container,'get'],$parts[1]);
|
|
$parts[1]=call_user_func([$container,'get'],$parts[1]);
|
|
@@ -1937,11 +2019,11 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
$sec=$match['section'];
|
|
$sec=$match['section'];
|
|
|
if (preg_match(
|
|
if (preg_match(
|
|
|
'/^(?!(?:global|config|route|map|redirect)s\b)'.
|
|
'/^(?!(?:global|config|route|map|redirect)s\b)'.
|
|
|
- '((?:\.?\w)+)/i',$sec,$msec) &&
|
|
|
|
|
- !$this->exists($msec[0]))
|
|
|
|
|
- $this->set($msec[0],NULL);
|
|
|
|
|
|
|
+ '(.*?)(?:\s*[:>])/i',$sec,$msec) &&
|
|
|
|
|
+ !$this->exists($msec[1]))
|
|
|
|
|
+ $this->set($msec[1],NULL);
|
|
|
preg_match('/^(config|route|map|redirect)s\b|'.
|
|
preg_match('/^(config|route|map|redirect)s\b|'.
|
|
|
- '^((?:\.?\w)+)\s*\>\s*(.*)/i',$sec,$cmd);
|
|
|
|
|
|
|
+ '^(.+?)\s*\>\s*(.*)/i',$sec,$cmd);
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
if ($allow)
|
|
if ($allow)
|
|
@@ -2021,7 +2103,7 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
mkdir($tmp,self::MODE,TRUE);
|
|
mkdir($tmp,self::MODE,TRUE);
|
|
|
// Use filesystem lock
|
|
// Use filesystem lock
|
|
|
if (is_file($lock=$tmp.
|
|
if (is_file($lock=$tmp.
|
|
|
- $this->get('SEED').'.'.$this->hash($id).'.lock') &&
|
|
|
|
|
|
|
+ $this->hive['SEED'].'.'.$this->hash($id).'.lock') &&
|
|
|
filemtime($lock)+ini_get('max_execution_time')<microtime(TRUE))
|
|
filemtime($lock)+ini_get('max_execution_time')<microtime(TRUE))
|
|
|
// Stale lock
|
|
// Stale lock
|
|
|
@unlink($lock);
|
|
@unlink($lock);
|
|
@@ -2054,7 +2136,7 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
* @param $append bool
|
|
* @param $append bool
|
|
|
**/
|
|
**/
|
|
|
function write($file,$data,$append=FALSE) {
|
|
function write($file,$data,$append=FALSE) {
|
|
|
- return file_put_contents($file,$data,LOCK_EX|($append?FILE_APPEND:0));
|
|
|
|
|
|
|
+ return file_put_contents($file,$data,$this->hive['LOCK']|($append?FILE_APPEND:0));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -2086,7 +2168,6 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Dump expression with syntax highlighting
|
|
* Dump expression with syntax highlighting
|
|
|
- * @return NULL
|
|
|
|
|
* @param $expr mixed
|
|
* @param $expr mixed
|
|
|
**/
|
|
**/
|
|
|
function dump($expr) {
|
|
function dump($expr) {
|
|
@@ -2110,6 +2191,7 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
**/
|
|
**/
|
|
|
protected function autoload($class) {
|
|
protected function autoload($class) {
|
|
|
$class=$this->fixslashes(ltrim($class,'\\'));
|
|
$class=$this->fixslashes(ltrim($class,'\\'));
|
|
|
|
|
+ /** @var callable $func */
|
|
|
$func=NULL;
|
|
$func=NULL;
|
|
|
if (is_array($path=$this->hive['AUTOLOAD']) &&
|
|
if (is_array($path=$this->hive['AUTOLOAD']) &&
|
|
|
isset($path[1]) && is_callable($path[1]))
|
|
isset($path[1]) && is_callable($path[1]))
|
|
@@ -2155,7 +2237,7 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
* Convenience method for assigning hive value
|
|
* Convenience method for assigning hive value
|
|
|
* @return mixed
|
|
* @return mixed
|
|
|
* @param $key string
|
|
* @param $key string
|
|
|
- * @param $val scalar
|
|
|
|
|
|
|
+ * @param $val mixed
|
|
|
**/
|
|
**/
|
|
|
function offsetset($key,$val) {
|
|
function offsetset($key,$val) {
|
|
|
return $this->set($key,$val);
|
|
return $this->set($key,$val);
|
|
@@ -2173,7 +2255,6 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Convenience method for removing hive key
|
|
* Convenience method for removing hive key
|
|
|
- * @return NULL
|
|
|
|
|
* @param $key string
|
|
* @param $key string
|
|
|
**/
|
|
**/
|
|
|
function offsetunset($key) {
|
|
function offsetunset($key) {
|
|
@@ -2211,7 +2292,6 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Alias for offsetunset()
|
|
* Alias for offsetunset()
|
|
|
- * @return mixed
|
|
|
|
|
* @param $key string
|
|
* @param $key string
|
|
|
**/
|
|
**/
|
|
|
function __unset($key) {
|
|
function __unset($key) {
|
|
@@ -2248,6 +2328,7 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
$check=error_reporting((E_ALL|E_STRICT)&~(E_NOTICE|E_USER_NOTICE));
|
|
$check=error_reporting((E_ALL|E_STRICT)&~(E_NOTICE|E_USER_NOTICE));
|
|
|
set_exception_handler(
|
|
set_exception_handler(
|
|
|
function($obj) {
|
|
function($obj) {
|
|
|
|
|
+ /** @var Exception $obj */
|
|
|
$this->hive['EXCEPTION']=$obj;
|
|
$this->hive['EXCEPTION']=$obj;
|
|
|
$this->error(500,
|
|
$this->error(500,
|
|
|
$obj->getmessage().' '.
|
|
$obj->getmessage().' '.
|
|
@@ -2348,7 +2429,8 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
!filter_var($_SERVER['SERVER_NAME'],FILTER_VALIDATE_IP)?
|
|
!filter_var($_SERVER['SERVER_NAME'],FILTER_VALIDATE_IP)?
|
|
|
$_SERVER['SERVER_NAME']:'',
|
|
$_SERVER['SERVER_NAME']:'',
|
|
|
'secure'=>($scheme=='https'),
|
|
'secure'=>($scheme=='https'),
|
|
|
- 'httponly'=>TRUE
|
|
|
|
|
|
|
+ 'httponly'=>TRUE,
|
|
|
|
|
+ 'samesite'=>'Lax',
|
|
|
];
|
|
];
|
|
|
$port=80;
|
|
$port=80;
|
|
|
if (isset($headers['X-Forwarded-Port']))
|
|
if (isset($headers['X-Forwarded-Port']))
|
|
@@ -2396,6 +2478,7 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
$this->language($headers['Accept-Language']):
|
|
$this->language($headers['Accept-Language']):
|
|
|
$this->fallback,
|
|
$this->fallback,
|
|
|
'LOCALES'=>'./',
|
|
'LOCALES'=>'./',
|
|
|
|
|
+ 'LOCK'=>LOCK_EX,
|
|
|
'LOGGABLE'=>'*',
|
|
'LOGGABLE'=>'*',
|
|
|
'LOGS'=>'./',
|
|
'LOGS'=>'./',
|
|
|
'MB'=>extension_loaded('mbstring'),
|
|
'MB'=>extension_loaded('mbstring'),
|
|
@@ -2435,7 +2518,12 @@ final class Base extends Prefab implements ArrayAccess {
|
|
|
if (!headers_sent() && session_status()!=PHP_SESSION_ACTIVE) {
|
|
if (!headers_sent() && session_status()!=PHP_SESSION_ACTIVE) {
|
|
|
unset($jar['expire']);
|
|
unset($jar['expire']);
|
|
|
session_cache_limiter('');
|
|
session_cache_limiter('');
|
|
|
- call_user_func_array('session_set_cookie_params',$jar);
|
|
|
|
|
|
|
+ if (version_compare(PHP_VERSION, '7.3.0') >= 0)
|
|
|
|
|
+ session_set_cookie_params($jar);
|
|
|
|
|
+ else {
|
|
|
|
|
+ unset($jar['samesite']);
|
|
|
|
|
+ call_user_func_array('session_set_cookie_params',$jar);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
if (PHP_SAPI=='cli-server' &&
|
|
if (PHP_SAPI=='cli-server' &&
|
|
|
preg_match('/^'.preg_quote($base,'/').'$/',$this->hive['URI']))
|
|
preg_match('/^'.preg_quote($base,'/').'$/',$this->hive['URI']))
|
|
@@ -2682,10 +2770,12 @@ class Cache extends Prefab {
|
|
|
if ($dsn=trim($dsn)) {
|
|
if ($dsn=trim($dsn)) {
|
|
|
if (preg_match('/^redis=(.+)/',$dsn,$parts) &&
|
|
if (preg_match('/^redis=(.+)/',$dsn,$parts) &&
|
|
|
extension_loaded('redis')) {
|
|
extension_loaded('redis')) {
|
|
|
- list($host,$port,$db)=explode(':',$parts[1])+[1=>6379,2=>NULL];
|
|
|
|
|
|
|
+ list($host,$port,$db,$password)=explode(':',$parts[1])+[1=>6379,2=>NULL,3=>NULL];
|
|
|
$this->ref=new Redis;
|
|
$this->ref=new Redis;
|
|
|
if(!$this->ref->connect($host,$port,2))
|
|
if(!$this->ref->connect($host,$port,2))
|
|
|
$this->ref=NULL;
|
|
$this->ref=NULL;
|
|
|
|
|
+ if(!empty($password))
|
|
|
|
|
+ $this->ref->auth($password);
|
|
|
if(isset($db))
|
|
if(isset($db))
|
|
|
$this->ref->select($db);
|
|
$this->ref->select($db);
|
|
|
}
|
|
}
|
|
@@ -2798,7 +2888,8 @@ class View extends Prefab {
|
|
|
!preg_grep ('/^Content-Type:/',headers_list()))
|
|
!preg_grep ('/^Content-Type:/',headers_list()))
|
|
|
header('Content-Type: '.$mime.'; '.
|
|
header('Content-Type: '.$mime.'; '.
|
|
|
'charset='.$fw->ENCODING);
|
|
'charset='.$fw->ENCODING);
|
|
|
- if ($fw->ESCAPE)
|
|
|
|
|
|
|
+ if ($fw->ESCAPE && (!$mime ||
|
|
|
|
|
+ preg_match('/^(text\/html|(application|text)\/(.+\+)?xml)$/i',$mime)))
|
|
|
$hive=$this->esc($hive);
|
|
$hive=$this->esc($hive);
|
|
|
if (isset($hive['ALIASES']))
|
|
if (isset($hive['ALIASES']))
|
|
|
$hive['ALIASES']=$fw->build($hive['ALIASES']);
|
|
$hive['ALIASES']=$fw->build($hive['ALIASES']);
|
|
@@ -2901,13 +2992,11 @@ class Preview extends View {
|
|
|
* @param $str string
|
|
* @param $str string
|
|
|
**/
|
|
**/
|
|
|
function token($str) {
|
|
function token($str) {
|
|
|
- $fw=$this->fw;
|
|
|
|
|
- $str=trim(preg_replace('/\{\{(.+?)\}\}/s',trim('\1'),
|
|
|
|
|
- $fw->compile($str)));
|
|
|
|
|
|
|
+ $str=trim(preg_replace('/\{\{(.+?)\}\}/s','\1',$this->fw->compile($str)));
|
|
|
if (preg_match('/^(.+)(?<!\|)\|((?:\h*\w+(?:\h*[,;]?))+)$/s',
|
|
if (preg_match('/^(.+)(?<!\|)\|((?:\h*\w+(?:\h*[,;]?))+)$/s',
|
|
|
$str,$parts)) {
|
|
$str,$parts)) {
|
|
|
$str=trim($parts[1]);
|
|
$str=trim($parts[1]);
|
|
|
- foreach ($fw->split(trim($parts[2],"\xC2\xA0")) as $func)
|
|
|
|
|
|
|
+ foreach ($this->fw->split(trim($parts[2],"\xC2\xA0")) as $func)
|
|
|
$str=((empty($this->filter[$cmd=$func]) &&
|
|
$str=((empty($this->filter[$cmd=$func]) &&
|
|
|
function_exists($cmd)) ||
|
|
function_exists($cmd)) ||
|
|
|
is_string($cmd=$this->filter($func)))?
|
|
is_string($cmd=$this->filter($func)))?
|
|
@@ -3475,7 +3564,6 @@ final class Registry {
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Delete object from catalog
|
|
* Delete object from catalog
|
|
|
- * @return NULL
|
|
|
|
|
* @param $key string
|
|
* @param $key string
|
|
|
**/
|
|
**/
|
|
|
static function clear($key) {
|
|
static function clear($key) {
|