- upgrade PHP "Fat Free Framework" v3.6.3 -> v3.6.4, #595
This commit is contained in:
@@ -1,5 +1,145 @@
|
||||
CHANGELOG
|
||||
|
||||
3.6.4 (19 April 2018)
|
||||
* NEW: Added Dependency Injection support with CONTAINER variable [#221](https://github.com/bcosca/fatfree-core/issues/221)
|
||||
* NEW: configurable LOGGABLE error codes [#1091](https://github.com/bcosca/fatfree/issues/1091#issuecomment-364674701)
|
||||
* NEW: JAR.lifetime option, [#178](https://github.com/bcosca/fatfree-core/issues/178)
|
||||
* Template: reduced Prefab calls
|
||||
* Template: optimized reflection for better derivative support, [bcosca/fatfree#1088](https://github.com/bcosca/fatfree/issues/1088)
|
||||
* Template: optimized parsing for template attributes and tokens
|
||||
* DB\Mongo: fixed logging with mongodb extention
|
||||
* DB\Jig: added lazy-loading [#7e1cd9b9b89](https://github.com/bcosca/fatfree-core/commit/7e1cd9b9b89c4175d0f6b86ced9d9bd49c04ac39)
|
||||
* DB\Jig\Mapper: Added group feature, bcosca/fatfree#616
|
||||
* DB\SQL\Mapper: fix PostgreSQL RETURNING ID when no pkey is available, [bcosca/fatfree#1069](https://github.com/bcosca/fatfree/issues/1069), [#230](https://github.com/bcosca/fatfree-core/issues/230)
|
||||
* DB\SQL\Mapper: disable order clause auto-quoting when it's already been quoted
|
||||
* Web->location: add failsafe for geoip_region_name_by_code() [#GB:Bxyn9xn9AgAJ](https://groups.google.com/d/msg/f3-framework/APau4wnwNzE/Bxyn9xn9AgAJ)
|
||||
* Web->request: Added proxy support [#e936361b](https://github.com/bcosca/fatfree-core/commit/e936361bc03010c4c7c38a396562e5e96a8a100d)
|
||||
* Web->mime: Added JFIF format
|
||||
* Markdown: handle line breaks in paragraph blocks, [bcosca/fatfree#1100](https://github.com/bcosca/fatfree/issues/1100)
|
||||
* config: reduced cast calls on parsing config sections
|
||||
* Patch empty SERVER_NAME [bcosca/fatfree#1084](https://github.com/bcosca/fatfree/issues/1084)
|
||||
* Bugfix: unreliable request headers in Web->request() response [bcosca/fatfree#1092](https://github.com/bcosca/fatfree/issues/1092)
|
||||
* Fixed, View->render: utilizing multiple UI paths, [bcosca/fatfree#1083](https://github.com/bcosca/fatfree/issues/1083)
|
||||
* Fixed URL parsing with PHP 5.4 [#247](https://github.com/bcosca/fatfree-core/issues/247)
|
||||
* Fixed PHP 7.2 warnings when session is active prematurely, [#238](https://github.com/bcosca/fatfree-core/issues/238)
|
||||
* Fixed setcookie $expire variable type [#240](https://github.com/bcosca/fatfree-core/issues/240)
|
||||
* Fixed expiration time when updating an existing cookie
|
||||
|
||||
3.6.3 (31 December 2017)
|
||||
* PHP7 fix: remove deprecated (unset) cast
|
||||
* Web->request: restricted follow_location to 3XX responses only
|
||||
* CLI mode: refactored arguments parsing
|
||||
* CLI mode: fixed query string encoding
|
||||
* SMTP: Refactor parsing of attachments
|
||||
* SMTP: clean-up mail headers for multipart messages, [#1065](https://github.com/bcosca/fatfree/issues/1065)
|
||||
* config: fixed performance issues on parsing config files
|
||||
* config: cast command parameters in config entries to php type & constant, [#1030](https://github.com/bcosca/fatfree/issues/1030)
|
||||
* config: reduced registry calls
|
||||
* config: skip hive escaping when resolving dynamic config vars, [#1030](https://github.com/bcosca/fatfree/issues/1030)
|
||||
* Bug fix: Incorrect cookie lifetime computation, [#1070](https://github.com/bcosca/fatfree/issues/1070), [#1016](https://github.com/bcosca/fatfree/issues/1016)
|
||||
* DB\SQL\Mapper: use RETURNING option instead of a sequence query to get lastInsertId in PostgreSQL, [#1069](https://github.com/bcosca/fatfree/issues/1069), [#230](https://github.com/bcosca/fatfree-core/issues/230)
|
||||
* DB\SQL\Session: check if _agent is too long for SQL based sessions [#236](https://github.com/bcosca/fatfree-core/issues/236)
|
||||
* DB\SQL\Session: fix Session handler table creation issue on SQL Server, [#899](https://github.com/bcosca/fatfree/issues/899)
|
||||
* DB\SQL: fix oracle db issue with empty error variable, [#1072](https://github.com/bcosca/fatfree/issues/1072)
|
||||
* DB\SQL\Mapper: fix sorting issues on SQL Server, [#1052](https://github.com/bcosca/fatfree/issues/1052) [#225](https://github.com/bcosca/fatfree-core/issues/225)
|
||||
* Prevent directory traversal attacks on filesystem based cache [#1073](https://github.com/bcosca/fatfree/issues/1073)
|
||||
* Bug fix, Template: PHP constants used in include with attribute, [#983](https://github.com/bcosca/fatfree/issues/983)
|
||||
* Bug fix, Template: Numeric value in expression alters PHP_EOL context
|
||||
* Template: use existing linefeed instead of PHP_EOL, [#1048](https://github.com/bcosca/fatfree/issues/1048)
|
||||
* Template: make newline interpolation handling configurable [#223](https://github.com/bcosca/fatfree-core/issues/223)
|
||||
* Template: add beforerender to Preview
|
||||
* fix custom FORMATS without modifiers
|
||||
* Cache: Refactor Cache->reset for XCache
|
||||
* Cache: loosen reset cache key pattern, [#1041](https://github.com/bcosca/fatfree/issues/1041)
|
||||
* XCache: suffix reset only works if xcache.admin.enable_auth is disabled
|
||||
* Added HTTP 103 as recently approved by the IETF
|
||||
* LDAP changes to for AD flexibility [#227](https://github.com/bcosca/fatfree-core/issues/227)
|
||||
* Hide debug trace from ajax errors when DEBUG=0 [#1071](https://github.com/bcosca/fatfree/issues/1071)
|
||||
* fix View->render using potentially wrong cache entry
|
||||
|
||||
3.6.2 (26 June 2017)
|
||||
* Return a status code > 0 when dying on error [#220](https://github.com/bcosca/fatfree-core/issues/220)
|
||||
* fix SMTP line width [#215](https://github.com/bcosca/fatfree-core/issues/215)
|
||||
* Allow using a custom field for ldap user id checking [#217](https://github.com/bcosca/fatfree-core/issues/217)
|
||||
* NEW: DB\SQL->exists: generic method to check if SQL table exists
|
||||
* Pass handler to route handler and hooks [#1035](https://github.com/bcosca/fatfree/issues/1035)
|
||||
* pass carriage return of multiline dictionary keys
|
||||
* Better Web->slug customization
|
||||
* fix incorrect header issue [#211](https://github.com/bcosca/fatfree-core/issues/211)
|
||||
* fix schema issue on databases with case-sensitive collation, fixes [#209](https://github.com/bcosca/fatfree-core/issues/209)
|
||||
* Add filter for deriving C-locale equivalent of a number
|
||||
* Bug fix: @LANGUAGE remains unchanged after override
|
||||
* abort: added Header pre-check
|
||||
* Assemble URL after ONREROUTE
|
||||
* Add reroute argument to skip script termination
|
||||
* Invoke ONREROUTE after headers are sent
|
||||
* SQLite switch to backtick as quote
|
||||
* Bug fix: Incorrect timing in SQL query logs
|
||||
* DB\SQL\Mapper: Cast return value of count to integer
|
||||
* Patched $_SERVER['REQUEST_URI'] to ensure it contains a relative URI
|
||||
* Tweak debug verbosity
|
||||
* fix php carriage return issue in preview->build [#205](https://github.com/bcosca/fatfree-core/pull/205)
|
||||
* fixed template string resolution [#205](https://github.com/bcosca/fatfree-core/pull/205)
|
||||
* Fixed unexpected default seed on CACHE set [#1028](https://github.com/bcosca/fatfree/issues/1028)
|
||||
* DB\SQL\Mapper: Optimized field escaping on options
|
||||
* Optimize template conversion to PHP file
|
||||
|
||||
3.6.1 (2 April 2017)
|
||||
* NEW: Recaptcha plugin [#194](https://github.com/bcosca/fatfree-core/pull/194)
|
||||
* NEW: MB variable for detecting multibyte support
|
||||
* NEW: DB\SQL: Cache parsed schema for the TTL duration
|
||||
* NEW: quick erase flag on Jig/Mongo/SQL mappers [#193](https://github.com/bcosca/fatfree-core/pull/193)
|
||||
* NEW: Allow OPTIONS method to return a response body [#171](https://github.com/bcosca/fatfree-core/pull/171)
|
||||
* NEW: Add support for Memcached (bcosca/fatfree#997)
|
||||
* NEW: Rudimentary preload resource (HTTP2 server) support via template push()
|
||||
* NEW: Add support for new MongoDB driver [#177](https://github.com/bcosca/fatfree-core/pull/177)
|
||||
* Changed: template filter are all lowercase now
|
||||
* Changed: Fix template lookup inconsistency: removed base dir from UI on render
|
||||
* Changed: count() method now has an options argument [#192](https://github.com/bcosca/fatfree-core/pull/192)
|
||||
* Changed: SMTP, Spit out error message if any
|
||||
* \DB\SQL\Mapper: refactored row count strategy
|
||||
* DB\SQL\Mapper: Allow non-scalar values to be assigned as mapper property
|
||||
* DB\SQL::PARAM_FLOAT: remove cast to float (#106 and bcosca/fatfree#984) (#191)
|
||||
* DB\SQL\mapper->erase: allow empty string
|
||||
* DB\SQL\mapper->insert: fields reset after successful INSERT
|
||||
* Add option to debounce Cursor->paginate subset [#195](https://github.com/bcosca/fatfree-core/pull/195)
|
||||
* View: Don't delete sandboxed variables (#198)
|
||||
* Preview: Optimize compilation of template expressions
|
||||
* Preview: Use shorthand tag for direct rendering
|
||||
* Preview->resolve(): new tweak to allow template persistence as option
|
||||
* Web: Expose diacritics translation table
|
||||
* SMTP: Enable logging of message body only when $log argument is 'verbose'
|
||||
* SMTP: Convert headers to camelcase for consistency
|
||||
* make cache seed more flexible, #164
|
||||
* Improve trace details for DEBUG>2
|
||||
* Enable config() to read from an array of input files
|
||||
* Improved alias and reroute regex
|
||||
* Make camelCase and snakeCase Unicode-aware
|
||||
* format: Provision for optional whitespaces
|
||||
* Break APCu-BC dependence
|
||||
* Old PHP 5.3 cleanup
|
||||
* Debug log must include HTTP query
|
||||
* Recognize X-Forwarded-Port header (bcosca/fatfree#1002)
|
||||
* Avoid use of deprecated mcrypt module
|
||||
* Return only the client's IP when using the `X-Forwarded-For` header to deduce an IP address
|
||||
* Remove orphan mutex locks on termination (#157)
|
||||
* Use 80 as default port number to avoid issues when `$_SERVER['SERVER_PORT']` is not existing
|
||||
* fread replaced with readfile() for simple send() usecase
|
||||
* Bug fix: request URI with multiple leading slashes, #203
|
||||
* Bug fix: Query generates wrong adhoc field value
|
||||
* Bug fix: SMTP stream context issue #200
|
||||
* Bug fix: child pseudo class selector in minify, bcosca/fatfree#1008
|
||||
* Bug fix: "Undefined index: CLI" error (#197)
|
||||
* Bug fix: cast Cache-Control expire time to int, bcosca/fatfree#1004
|
||||
* Bug fix: Avoid issuance of multiple Content-Type headers for nested templates
|
||||
* Bug fix: wildcard token issue with digits (bcosca/fatfree#996)
|
||||
* Bug fix: afterupdate ignored when row does not change
|
||||
* Bug fix: session handler read() method for PHP7 (need strict string) #184 #185
|
||||
* Bug fix: reroute mocking in CLI mode (#183)
|
||||
* Bug fix: Reroute authoritative relative references (#181)
|
||||
* Bug fix: locales order and charset hyphen
|
||||
* Bug fix: base stripped twice in router (#176)
|
||||
|
||||
3.6.0 (19 November 2016)
|
||||
* NEW: [cli] request type
|
||||
* NEW: console-friendly CLI mode
|
||||
@@ -89,6 +229,7 @@ CHANGELOG
|
||||
* Bug fix: encode CLI parameters
|
||||
* Bug fix: Close connection on abort explicitly (#162)
|
||||
* Bug fix: Image->identicon, Avoid double-size sprite rotation (and possible segfault)
|
||||
* Bug fix: Image->render and Image->dump, removed unnecessary 2nd argument (#146)
|
||||
* Bug fix: Magic->offsetset, access property as array element (#147)
|
||||
* Bug fix: multi-line custom template tag parsing (bcosca/fatfree#935)
|
||||
* Bug fix: cache headers on errors (bcosca/fatfree#885)
|
||||
107
app/lib/base.php
107
app/lib/base.php
@@ -45,7 +45,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
//@{ Framework details
|
||||
const
|
||||
PACKAGE='Fat-Free Framework',
|
||||
VERSION='3.6.3-Release';
|
||||
VERSION='3.6.4-Release';
|
||||
//@}
|
||||
|
||||
//@{ HTTP status codes (RFC 2616)
|
||||
@@ -346,17 +346,16 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
* @param $ttl int
|
||||
**/
|
||||
function set($key,$val,$ttl=0) {
|
||||
$time=$this->hive['TIME'];
|
||||
$time=(int)$this->hive['TIME'];
|
||||
if (preg_match('/^(GET|POST|COOKIE)\b(.+)/',$key,$expr)) {
|
||||
$this->set('REQUEST'.$expr[2],$val);
|
||||
if ($expr[1]=='COOKIE') {
|
||||
$parts=$this->cut($key);
|
||||
$jar=$this->unserialize($this->serialize($this->hive['JAR']));
|
||||
if (isset($_COOKIE[$parts[1]])) {
|
||||
$jar['expire']=0;
|
||||
unset($jar['lifetime']);
|
||||
if (isset($_COOKIE[$parts[1]]))
|
||||
call_user_func_array('setcookie',
|
||||
array_merge([$parts[1],NULL],$jar));
|
||||
}
|
||||
array_merge([$parts[1],NULL],['expire'=>0]+$jar));
|
||||
if ($ttl)
|
||||
$jar['expire']=$time+$ttl;
|
||||
call_user_func_array('setcookie',[$parts[1],$val]+$jar);
|
||||
@@ -395,9 +394,17 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
$ref=&$this->ref($key);
|
||||
$ref=$val;
|
||||
if (preg_match('/^JAR\b/',$key)) {
|
||||
$jar=$this->unserialize($this->serialize($this->hive['JAR']));
|
||||
$jar['expire']-=$time;
|
||||
call_user_func_array('session_set_cookie_params',$jar);
|
||||
if ($key=='JAR.lifetime')
|
||||
$this->set('JAR.expire',$val==0?0:
|
||||
(is_int($val)?$time+$val:strtotime($val)));
|
||||
else {
|
||||
if ($key=='JAR.expire')
|
||||
$this->hive['JAR']['lifetime']=max(0,$val-$time);
|
||||
$jar=$this->unserialize($this->serialize($this->hive['JAR']));
|
||||
unset($jar['expire']);
|
||||
if (!headers_sent() && session_status()!=PHP_SESSION_ACTIVE)
|
||||
call_user_func_array('session_set_cookie_params',$jar);
|
||||
}
|
||||
}
|
||||
if ($ttl)
|
||||
// Persist the key-value pair
|
||||
@@ -442,6 +449,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
if ($expr[1]=='COOKIE') {
|
||||
$parts=$this->cut($key);
|
||||
$jar=$this->hive['JAR'];
|
||||
unset($jar['lifetime']);
|
||||
$jar['expire']=0;
|
||||
call_user_func_array('setcookie',
|
||||
array_merge([$parts[1],NULL],$jar));
|
||||
@@ -1231,11 +1239,18 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
$req.='?'.$this->hive['QUERY'];
|
||||
if (!$text)
|
||||
$text='HTTP '.$code.' ('.$req.')';
|
||||
error_log($text);
|
||||
$trace=$this->trace($trace);
|
||||
foreach (explode("\n",$trace) as $nexus)
|
||||
if ($nexus)
|
||||
error_log($nexus);
|
||||
$loggable=$this->hive['LOGGABLE'];
|
||||
if (!is_array($loggable))
|
||||
$loggable=$this->split($loggable);
|
||||
foreach ($loggable as $status)
|
||||
if ($status=='*' || preg_match('/^'.preg_replace('/\D/','\d',$status).'$/',$code)) {
|
||||
error_log($text);
|
||||
foreach (explode("\n",$trace) as $nexus)
|
||||
if ($nexus)
|
||||
error_log($nexus);
|
||||
break;
|
||||
}
|
||||
if ($highlight=!$this->hive['CLI'] && !$this->hive['AJAX'] &&
|
||||
$this->hive['HIGHLIGHT'] && is_file($css=__DIR__.'/'.self::CSS))
|
||||
$trace=$this->highlight($trace);
|
||||
@@ -1750,6 +1765,19 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
if ($parts[2]=='->') {
|
||||
if (is_subclass_of($parts[1],'Prefab'))
|
||||
$parts[1]=call_user_func($parts[1].'::instance');
|
||||
elseif ($container=$this->get('CONTAINER')) {
|
||||
if (is_object($container) && is_callable([$container,'has'])
|
||||
&& $container->has($parts[1])) // PSR11
|
||||
$parts[1]=call_user_func([$container,'get'],$parts[1]);
|
||||
elseif (is_callable($container))
|
||||
$parts[1]=call_user_func($container,$parts[1],$args);
|
||||
elseif (is_string($container) && is_subclass_of($container,'Prefab'))
|
||||
$parts[1]=call_user_func($container.'::instance')->get($parts[1]);
|
||||
else
|
||||
user_error(sprintf(self::E_Class,
|
||||
$this->stringify($container)),
|
||||
E_USER_ERROR);
|
||||
}
|
||||
else {
|
||||
$ref=new ReflectionClass($parts[1]);
|
||||
$parts[1]=method_exists($parts[1],'__construct') && $args?
|
||||
@@ -1888,7 +1916,8 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
call_user_func_array(
|
||||
[$this,$cmd[1]],
|
||||
array_merge([$match['lval']],
|
||||
str_getcsv($this->cast($match['rval'])))
|
||||
str_getcsv($cmd[1]=='config'?$this->cast($match['rval']):
|
||||
$match['rval']))
|
||||
);
|
||||
}
|
||||
else {
|
||||
@@ -2190,7 +2219,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
$this->error(500,$text,NULL,$level);
|
||||
}
|
||||
);
|
||||
if (!isset($_SERVER['SERVER_NAME']))
|
||||
if (!isset($_SERVER['SERVER_NAME']) || $_SERVER['SERVER_NAME']==='')
|
||||
$_SERVER['SERVER_NAME']=gethostname();
|
||||
if ($cli=PHP_SAPI=='cli') {
|
||||
// Emulate HTTP request
|
||||
@@ -2266,14 +2295,14 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
$base=rtrim($this->fixslashes(
|
||||
dirname($_SERVER['SCRIPT_NAME'])),'/');
|
||||
$uri=parse_url((preg_match('/^\w+:\/\//',$_SERVER['REQUEST_URI'])?'':
|
||||
'//'.$_SERVER['SERVER_NAME']).$_SERVER['REQUEST_URI']);
|
||||
$scheme.'://'.$_SERVER['SERVER_NAME']).$_SERVER['REQUEST_URI']);
|
||||
$_SERVER['REQUEST_URI']=$uri['path'].
|
||||
(isset($uri['query'])?'?'.$uri['query']:'').
|
||||
(isset($uri['fragment'])?'#'.$uri['fragment']:'');
|
||||
$path=preg_replace('/^'.preg_quote($base,'/').'/','',$uri['path']);
|
||||
session_cache_limiter('');
|
||||
$jar=[
|
||||
'expire'=>0,
|
||||
'lifetime'=>0,
|
||||
'path'=>$base?:'/',
|
||||
'domain'=>is_int(strpos($_SERVER['SERVER_NAME'],'.')) &&
|
||||
!filter_var($_SERVER['SERVER_NAME'],FILTER_VALIDATE_IP)?
|
||||
@@ -2281,7 +2310,6 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
'secure'=>($scheme=='https'),
|
||||
'httponly'=>TRUE
|
||||
];
|
||||
call_user_func_array('session_set_cookie_params',$jar);
|
||||
$port=80;
|
||||
if (isset($headers['X-Forwarded-Port']))
|
||||
$port=$headers['X-Forwarded-Port'];
|
||||
@@ -2328,6 +2356,7 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
$this->language($headers['Accept-Language']):
|
||||
$this->fallback,
|
||||
'LOCALES'=>'./',
|
||||
'LOGGABLE'=>'*',
|
||||
'LOGS'=>'./',
|
||||
'MB'=>extension_loaded('mbstring'),
|
||||
'ONERROR'=>NULL,
|
||||
@@ -2363,6 +2392,11 @@ final class Base extends Prefab implements ArrayAccess {
|
||||
'VERSION'=>self::VERSION,
|
||||
'XFRAME'=>'SAMEORIGIN'
|
||||
];
|
||||
if (!headers_sent() && session_status()!=PHP_SESSION_ACTIVE) {
|
||||
unset($jar['expire']);
|
||||
session_cache_limiter('');
|
||||
call_user_func_array('session_set_cookie_params',$jar);
|
||||
}
|
||||
if (PHP_SAPI=='cli-server' &&
|
||||
preg_match('/^'.preg_quote($base,'/').'$/',$this->hive['URI']))
|
||||
$this->reroute('/');
|
||||
@@ -2673,16 +2707,22 @@ class View extends Prefab {
|
||||
//! Nesting level
|
||||
$level=0;
|
||||
|
||||
/** @var \Base Framework instance */
|
||||
protected $fw;
|
||||
|
||||
function __construct() {
|
||||
$this->fw=\Base::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode characters to equivalent HTML entities
|
||||
* @return string
|
||||
* @param $arg mixed
|
||||
**/
|
||||
function esc($arg) {
|
||||
$fw=Base::instance();
|
||||
return $fw->recursive($arg,
|
||||
function($val) use($fw) {
|
||||
return is_string($val)?$fw->encode($val):$val;
|
||||
return $this->fw->recursive($arg,
|
||||
function($val) {
|
||||
return is_string($val)?$this->fw->encode($val):$val;
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -2693,10 +2733,9 @@ class View extends Prefab {
|
||||
* @param $arg mixed
|
||||
**/
|
||||
function raw($arg) {
|
||||
$fw=Base::instance();
|
||||
return $fw->recursive($arg,
|
||||
function($val) use($fw) {
|
||||
return is_string($val)?$fw->decode($val):$val;
|
||||
return $this->fw->recursive($arg,
|
||||
function($val) {
|
||||
return is_string($val)?$this->fw->decode($val):$val;
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -2708,7 +2747,7 @@ class View extends Prefab {
|
||||
* @param $mime string
|
||||
**/
|
||||
protected function sandbox(array $hive=NULL,$mime=NULL) {
|
||||
$fw=Base::instance();
|
||||
$fw=$this->fw;
|
||||
$implicit=FALSE;
|
||||
if (is_null($hive)) {
|
||||
$implicit=TRUE;
|
||||
@@ -2744,9 +2783,9 @@ class View extends Prefab {
|
||||
* @param $ttl int
|
||||
**/
|
||||
function render($file,$mime='text/html',array $hive=NULL,$ttl=0) {
|
||||
$fw=Base::instance();
|
||||
$fw=$this->fw;
|
||||
$cache=Cache::instance();
|
||||
foreach ($fw->split($fw->UI) as $dir)
|
||||
foreach ($fw->split($fw->UI) as $dir) {
|
||||
if ($cache->exists($hash=$fw->hash($dir.$file),$data))
|
||||
return $data;
|
||||
if (is_file($this->file=$fw->fixslashes($dir.$file))) {
|
||||
@@ -2762,6 +2801,7 @@ class View extends Prefab {
|
||||
$cache->set($hash,$data,$ttl);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
user_error(sprintf(Base::E_Open,$file),E_USER_ERROR);
|
||||
}
|
||||
|
||||
@@ -2807,7 +2847,6 @@ class Preview extends View {
|
||||
* @param $val int|float
|
||||
**/
|
||||
function c($val) {
|
||||
$fw=Base::instance();
|
||||
$locale=setlocale(LC_NUMERIC,0);
|
||||
setlocale(LC_NUMERIC,'C');
|
||||
$out=(string)(float)$val;
|
||||
@@ -2821,13 +2860,13 @@ class Preview extends View {
|
||||
* @param $str string
|
||||
**/
|
||||
function token($str) {
|
||||
$fw = Base::instance();
|
||||
$fw=$this->fw;
|
||||
$str=trim(preg_replace('/\{\{(.+?)\}\}/s',trim('\1'),
|
||||
$fw->compile($str)));
|
||||
if (preg_match('/^(.+)(?<!\|)\|((?:\h*\w+(?:\h*[,;]?))+)$/s',
|
||||
$str,$parts)) {
|
||||
$str=trim($parts[1]);
|
||||
foreach ($fw->split($parts[2]) as $func)
|
||||
foreach ($fw->split(trim($parts[2],"\xC2\xA0")) as $func)
|
||||
$str=is_string($cmd=$this->filter($func))?
|
||||
$cmd.'('.$str.')':
|
||||
'Base::instance()->'.
|
||||
@@ -2890,7 +2929,7 @@ class Preview extends View {
|
||||
* @param $escape bool
|
||||
**/
|
||||
function resolve($node,array $hive=NULL,$ttl=0,$persist=FALSE,$escape=NULL) {
|
||||
$fw=Base::instance();
|
||||
$fw=$this->fw;
|
||||
$cache=Cache::instance();
|
||||
if ($escape!==NULL) {
|
||||
$esc=$fw->ESCAPE;
|
||||
@@ -2951,7 +2990,7 @@ class Preview extends View {
|
||||
* @param $ttl int
|
||||
**/
|
||||
function render($file,$mime='text/html',array $hive=NULL,$ttl=0) {
|
||||
$fw=Base::instance();
|
||||
$fw=$this->fw;
|
||||
$cache=Cache::instance();
|
||||
if (!is_dir($tmp=$fw->TEMP))
|
||||
mkdir($tmp,Base::MODE,TRUE);
|
||||
|
||||
@@ -41,7 +41,9 @@ class Jig {
|
||||
//! Jig log
|
||||
$log,
|
||||
//! Memory-held data
|
||||
$data;
|
||||
$data,
|
||||
//! lazy load/save files
|
||||
$lazy;
|
||||
|
||||
/**
|
||||
* Read data from memory/file
|
||||
@@ -54,6 +56,8 @@ class Jig {
|
||||
$this->data[$file]=[];
|
||||
return $this->data[$file];
|
||||
}
|
||||
if ($this->lazy && isset($this->data[$file]))
|
||||
return $this->data[$file];
|
||||
$fw=\Base::instance();
|
||||
$raw=$fw->read($dst);
|
||||
switch ($this->format) {
|
||||
@@ -75,7 +79,7 @@ class Jig {
|
||||
* @param $data array
|
||||
**/
|
||||
function write($file,array $data=NULL) {
|
||||
if (!$this->dir)
|
||||
if (!$this->dir || $this->lazy)
|
||||
return count($this->data[$file]=$data);
|
||||
$fw=\Base::instance();
|
||||
switch ($this->format) {
|
||||
@@ -131,6 +135,8 @@ class Jig {
|
||||
* @return NULL
|
||||
**/
|
||||
function drop() {
|
||||
if ($this->lazy) // intentional
|
||||
$this->data=[];
|
||||
if (!$this->dir)
|
||||
$this->data=[];
|
||||
elseif ($glob=@glob($this->dir.'/*',GLOB_NOSORT))
|
||||
@@ -147,11 +153,23 @@ class Jig {
|
||||
* @param $dir string
|
||||
* @param $format int
|
||||
**/
|
||||
function __construct($dir=NULL,$format=self::FORMAT_JSON) {
|
||||
function __construct($dir=NULL,$format=self::FORMAT_JSON,$lazy=FALSE) {
|
||||
if ($dir && !is_dir($dir))
|
||||
mkdir($dir,\Base::MODE,TRUE);
|
||||
$this->uuid=\Base::instance()->hash($this->dir=$dir);
|
||||
$this->format=$format;
|
||||
$this->lazy=$lazy;
|
||||
}
|
||||
|
||||
/**
|
||||
* save file on destruction
|
||||
**/
|
||||
function __destruct() {
|
||||
if ($this->lazy) {
|
||||
$this->lazy = FALSE;
|
||||
foreach ($this->data as $file => $data)
|
||||
$this->write($file,$data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,9 @@ class Mapper extends \DB\Cursor {
|
||||
//! Document identifier
|
||||
$id,
|
||||
//! Document contents
|
||||
$document=[];
|
||||
$document=[],
|
||||
//! field map-reduce handlers
|
||||
$_reduce;
|
||||
|
||||
/**
|
||||
* Return database type
|
||||
@@ -160,7 +162,8 @@ class Mapper extends \DB\Cursor {
|
||||
$options+=[
|
||||
'order'=>NULL,
|
||||
'limit'=>0,
|
||||
'offset'=>0
|
||||
'offset'=>0,
|
||||
'group'=>NULL,
|
||||
];
|
||||
$fw=\Base::instance();
|
||||
$cache=\Cache::instance();
|
||||
@@ -232,30 +235,46 @@ class Mapper extends \DB\Cursor {
|
||||
}
|
||||
);
|
||||
}
|
||||
if (isset($options['order'])) {
|
||||
$cols=$fw->split($options['order']);
|
||||
uasort(
|
||||
$data,
|
||||
function($val1,$val2) use($cols) {
|
||||
foreach ($cols as $col) {
|
||||
$parts=explode(' ',$col,2);
|
||||
$order=empty($parts[1])?
|
||||
SORT_ASC:
|
||||
constant($parts[1]);
|
||||
$col=$parts[0];
|
||||
if (!array_key_exists($col,$val1))
|
||||
$val1[$col]=NULL;
|
||||
if (!array_key_exists($col,$val2))
|
||||
$val2[$col]=NULL;
|
||||
list($v1,$v2)=[$val1[$col],$val2[$col]];
|
||||
if ($out=strnatcmp($v1,$v2)*
|
||||
(($order==SORT_ASC)*2-1))
|
||||
return $out;
|
||||
}
|
||||
return 0;
|
||||
if (isset($options['group'])) {
|
||||
$cols=array_reverse($fw->split($options['group']));
|
||||
// sort into groups
|
||||
$data=$this->sort($data,$options['group']);
|
||||
foreach($data as $i=>&$row) {
|
||||
if (!isset($prev)) {
|
||||
$prev=$row;
|
||||
$prev_i=$i;
|
||||
}
|
||||
$drop=false;
|
||||
foreach ($cols as $col)
|
||||
if ($prev_i!=$i && array_key_exists($col,$row) &&
|
||||
array_key_exists($col,$prev) && $row[$col]==$prev[$col])
|
||||
// reduce/modify
|
||||
$drop=!isset($this->_reduce[$col]) || call_user_func_array(
|
||||
$this->_reduce[$col][0],[&$prev,&$row])!==FALSE;
|
||||
elseif (isset($this->_reduce[$col])) {
|
||||
$null=null;
|
||||
// initial
|
||||
call_user_func_array($this->_reduce[$col][0],[&$row,&$null]);
|
||||
}
|
||||
if ($drop)
|
||||
unset($data[$i]);
|
||||
else {
|
||||
$prev=&$row;
|
||||
$prev_i=$i;
|
||||
}
|
||||
unset($row);
|
||||
}
|
||||
// finalize
|
||||
if ($this->_reduce[$col][1])
|
||||
foreach($data as $i=>&$row) {
|
||||
$row=call_user_func($this->_reduce[$col][1],$row);
|
||||
if (!$row)
|
||||
unset($data[$i]);
|
||||
unset($row);
|
||||
}
|
||||
);
|
||||
}
|
||||
if (isset($options['order']))
|
||||
$data=$this->sort($data,$options['order']);
|
||||
$data=array_slice($data,
|
||||
$options['offset'],$options['limit']?:NULL,TRUE);
|
||||
if ($fw->CACHE && $ttl)
|
||||
@@ -281,6 +300,48 @@ class Mapper extends \DB\Cursor {
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort a collection
|
||||
* @param $data
|
||||
* @param $cond
|
||||
* @return mixed
|
||||
*/
|
||||
protected function sort($data,$cond) {
|
||||
$cols=\Base::instance()->split($cond);
|
||||
uasort(
|
||||
$data,
|
||||
function($val1,$val2) use($cols) {
|
||||
foreach ($cols as $col) {
|
||||
$parts=explode(' ',$col,2);
|
||||
$order=empty($parts[1])?
|
||||
SORT_ASC:
|
||||
constant($parts[1]);
|
||||
$col=$parts[0];
|
||||
if (!array_key_exists($col,$val1))
|
||||
$val1[$col]=NULL;
|
||||
if (!array_key_exists($col,$val2))
|
||||
$val2[$col]=NULL;
|
||||
list($v1,$v2)=[$val1[$col],$val2[$col]];
|
||||
if ($out=strnatcmp($v1,$v2)*
|
||||
(($order==SORT_ASC)*2-1))
|
||||
return $out;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add reduce handler for grouped fields
|
||||
* @param $key string
|
||||
* @param $handler callback
|
||||
* @param $finalize callback
|
||||
*/
|
||||
function reduce($key,$handler,$finalize=null){
|
||||
$this->_reduce[$key]=[$handler,$finalize];
|
||||
}
|
||||
|
||||
/**
|
||||
* Count records that match criteria
|
||||
* @return int
|
||||
|
||||
@@ -68,8 +68,9 @@ class Mongo {
|
||||
$cursor=$this->db->selectcollection('system.profile')->find();
|
||||
foreach (iterator_to_array($cursor) as $frame)
|
||||
if (!preg_match('/\.system\..+$/',$frame['ns']))
|
||||
$this->log.=date('r',$frame['ts']->sec).' ('.
|
||||
sprintf('%.1f',$frame['millis']).'ms) '.
|
||||
$this->log.=date('r',$this->legacy() ?
|
||||
$frame['ts']->sec : (round((string)$frame['ts'])/1000)).
|
||||
' ('.sprintf('%.1f',$frame['millis']).'ms) '.
|
||||
$frame['ns'].' ['.$frame['op'].'] '.
|
||||
(empty($frame['query'])?
|
||||
'':json_encode($frame['query'])).
|
||||
|
||||
@@ -153,7 +153,7 @@ class Mapper extends \DB\Cursor {
|
||||
|
||||
/**
|
||||
* Convert array to mapper object
|
||||
* @return object
|
||||
* @return static
|
||||
* @param $row array
|
||||
**/
|
||||
protected function factory($row) {
|
||||
@@ -236,14 +236,15 @@ class Mapper extends \DB\Cursor {
|
||||
explode(',',$options['group'])));
|
||||
}
|
||||
if ($options['order']) {
|
||||
$order=' ORDER BY '.implode(',',array_map(
|
||||
function($str) use($db) {
|
||||
$char=substr($db->quotekey(''),0,1);// quoting char
|
||||
$order=' ORDER BY '.(FALSE===strpos($options['order'],$char)?
|
||||
implode(',',array_map(function($str) use($db) {
|
||||
return preg_match('/^\h*(\w+[._\-\w]*)(?:\h+((?:ASC|DESC)[\w\h]*))?\h*$/i',
|
||||
$str,$parts)?
|
||||
($db->quotekey($parts[1]).
|
||||
(isset($parts[2])?(' '.$parts[2]):'')):$str;
|
||||
},
|
||||
explode(',',$options['order'])));
|
||||
},explode(',',$options['order']))):
|
||||
$options['order']);
|
||||
}
|
||||
// SQL Server fixes
|
||||
if (preg_match('/mssql|sqlsrv|odbc/', $this->engine) &&
|
||||
@@ -285,7 +286,7 @@ class Mapper extends \DB\Cursor {
|
||||
|
||||
/**
|
||||
* Build query string and execute
|
||||
* @return object
|
||||
* @return static[]
|
||||
* @param $fields string
|
||||
* @param $filter string|array
|
||||
* @param $options array
|
||||
@@ -360,7 +361,7 @@ class Mapper extends \DB\Cursor {
|
||||
/**
|
||||
* Return record at specified offset using same criteria as
|
||||
* previous load() call and make it active
|
||||
* @return array
|
||||
* @return static
|
||||
* @param $ofs int
|
||||
**/
|
||||
function skip($ofs=1) {
|
||||
@@ -385,7 +386,7 @@ class Mapper extends \DB\Cursor {
|
||||
|
||||
/**
|
||||
* Insert new record
|
||||
* @return object
|
||||
* @return static
|
||||
**/
|
||||
function insert() {
|
||||
$args=[];
|
||||
@@ -424,8 +425,8 @@ class Mapper extends \DB\Cursor {
|
||||
}
|
||||
}
|
||||
if ($fields) {
|
||||
$add='';
|
||||
if ($this->engine=='pgsql') {
|
||||
$add=$aik='';
|
||||
if ($this->engine=='pgsql' && !empty($pkeys)) {
|
||||
$names=array_keys($pkeys);
|
||||
$aik=end($names);
|
||||
$add=' RETURNING '.$this->db->quotekey($aik);
|
||||
@@ -437,12 +438,12 @@ class Mapper extends \DB\Cursor {
|
||||
'INSERT INTO '.$this->table.' ('.$fields.') '.
|
||||
'VALUES ('.$values.')'.$add,$args
|
||||
);
|
||||
if ($this->engine=='pgsql' && $lID)
|
||||
if ($this->engine=='pgsql' && $lID && $aik)
|
||||
$this->_id=$lID[0][$aik];
|
||||
elseif ($this->engine!='oci')
|
||||
$this->_id=$this->db->lastinsertid();
|
||||
// Reload to obtain default and auto-increment field values
|
||||
if ($reload=($inc || $filter))
|
||||
if ($reload=(($inc && $this->_id) || $filter))
|
||||
$this->load($inc?
|
||||
[$inc.'=?',$this->db->value(
|
||||
$this->fields[$inc]['pdo_type'],$this->_id)]:
|
||||
@@ -463,7 +464,7 @@ class Mapper extends \DB\Cursor {
|
||||
|
||||
/**
|
||||
* Update current record
|
||||
* @return object
|
||||
* @return static
|
||||
**/
|
||||
function update() {
|
||||
$args=[];
|
||||
@@ -652,7 +653,7 @@ class Mapper extends \DB\Cursor {
|
||||
|
||||
/**
|
||||
* Instantiate class
|
||||
* @param $db object
|
||||
* @param $db \DB\SQL
|
||||
* @param $table string
|
||||
* @param $fields array|string
|
||||
* @param $ttl int|array
|
||||
|
||||
@@ -306,6 +306,7 @@ class Markdown extends Prefab {
|
||||
},
|
||||
$str
|
||||
);
|
||||
$str=preg_replace('/\s{2}\r?\n/','<br />',$str);
|
||||
return '<p>'.$this->scan($str).'</p>'."\n\n";
|
||||
}
|
||||
return '';
|
||||
|
||||
@@ -273,7 +273,7 @@ class Template extends Preview {
|
||||
// Build tree structure
|
||||
for ($ptr=0,$w=5,$len=strlen($text),$tree=[],$tmp='';$ptr<$len;)
|
||||
if (preg_match('/^(.{0,'.$w.'}?)<(\/?)(?:F3:)?'.
|
||||
'('.$this->tags.')\b((?:\s+[\w-]+'.
|
||||
'('.$this->tags.')\b((?:\s+[\w-.:@!]+'.
|
||||
'(?:\h*=\h*(?:"(?:.*?)"|\'(?:.*?)\'))?|'.
|
||||
'\h*\{\{.+?\}\})*)\h*(\/?)>/is',
|
||||
substr($text,$ptr),$match)) {
|
||||
@@ -303,19 +303,18 @@ class Template extends Preview {
|
||||
if ($match[4]) {
|
||||
// Process attributes
|
||||
preg_match_all(
|
||||
'/(?:\b([\w-]+)\h*'.
|
||||
'(?:=\h*(?:"(.*?)"|\'(.*?)\'))?|'.
|
||||
'(\{\{.+?\}\}))/s',
|
||||
'/(?:(\{\{.+?\}\})|([^\s\/"\'=]+))'.
|
||||
'\h*(?:=\h*(?:"(.*?)"|\'(.*?)\'))?/s',
|
||||
$match[4],$attr,PREG_SET_ORDER);
|
||||
foreach ($attr as $kv)
|
||||
if (isset($kv[4]))
|
||||
$node['@attrib'][]=$kv[4];
|
||||
if (!empty($kv[1]) && !isset($kv[3]) && !isset($kv[4]))
|
||||
$node['@attrib'][]=$kv[1];
|
||||
else
|
||||
$node['@attrib'][$kv[1]]=
|
||||
(isset($kv[2]) && $kv[2]!==''?
|
||||
$kv[2]:
|
||||
(isset($kv[3]) && $kv[3]!==''?
|
||||
$kv[3]:NULL));
|
||||
$node['@attrib'][$kv[1]?:$kv[2]]=
|
||||
(isset($kv[3]) && $kv[3]!==''?
|
||||
$kv[3]:
|
||||
(isset($kv[4]) && $kv[4]!==''?
|
||||
$kv[4]:NULL));
|
||||
}
|
||||
}
|
||||
$tmp='';
|
||||
@@ -342,12 +341,13 @@ class Template extends Preview {
|
||||
* return object
|
||||
**/
|
||||
function __construct() {
|
||||
$ref=new ReflectionClass(__CLASS__);
|
||||
$ref=new ReflectionClass(get_called_class());
|
||||
$this->tags='';
|
||||
foreach ($ref->getmethods() as $method)
|
||||
if (preg_match('/^_(?=[[:alpha:]])/',$method->name))
|
||||
$this->tags.=(strlen($this->tags)?'|':'').
|
||||
substr($method->name,1);
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class Web extends Prefab {
|
||||
'hqx'=>'application/mac-binhex40',
|
||||
'html?'=>'text/html',
|
||||
'jar'=>'application/java-archive',
|
||||
'jpe?g'=>'image/jpeg',
|
||||
'jpe?g|jfif?'=>'image/jpeg',
|
||||
'js'=>'application/x-javascript',
|
||||
'midi'=>'audio/x-midi',
|
||||
'mp3'=>'audio/mpeg',
|
||||
@@ -281,6 +281,8 @@ class Web extends Prefab {
|
||||
curl_setopt($curl,CURLOPT_HTTPHEADER,$options['header']);
|
||||
if (isset($options['content']))
|
||||
curl_setopt($curl,CURLOPT_POSTFIELDS,$options['content']);
|
||||
if (isset($options['proxy']))
|
||||
curl_setopt($curl,CURLOPT_PROXY,$options['proxy']);
|
||||
curl_setopt($curl,CURLOPT_ENCODING,'gzip,deflate');
|
||||
$timeout=isset($options['timeout'])?
|
||||
$options['timeout']:
|
||||
@@ -333,6 +335,12 @@ class Web extends Prefab {
|
||||
**/
|
||||
protected function _stream($url,$options) {
|
||||
$eol="\r\n";
|
||||
if (isset($options['proxy'])) {
|
||||
$options['proxy']=preg_replace('/https?/i','tcp',$options['proxy']);
|
||||
$options['request_fulluri']=true;
|
||||
if (preg_match('/socks4?/i',$options['proxy']))
|
||||
return $this->_socket($url,$options);
|
||||
}
|
||||
$options['header']=implode($eol,$options['header']);
|
||||
$body=@file_get_contents($url,FALSE,
|
||||
stream_context_create(['http'=>$options]));
|
||||
@@ -378,25 +386,46 @@ class Web extends Prefab {
|
||||
$headers=[];
|
||||
$body='';
|
||||
$parts=parse_url($url);
|
||||
$empty=empty($parts['port']);
|
||||
if ($parts['scheme']=='https') {
|
||||
$hostname=$parts['host'];
|
||||
$proxy=false;
|
||||
if ($parts['scheme']=='https')
|
||||
$parts['host']='ssl://'.$parts['host'];
|
||||
if ($empty)
|
||||
$parts['port']=443;
|
||||
}
|
||||
elseif ($empty)
|
||||
$parts['port']=80;
|
||||
if (empty($parts['port']))
|
||||
$parts['port']=$parts['scheme']=='https'?443:80;
|
||||
if (empty($parts['path']))
|
||||
$parts['path']='/';
|
||||
if (empty($parts['query']))
|
||||
$parts['query']='';
|
||||
if ($socket=@fsockopen($parts['host'],$parts['port'],$code,$err)) {
|
||||
if (isset($options['proxy'])) {
|
||||
$req=$url;
|
||||
$pp=parse_url($options['proxy']);
|
||||
$proxy=$pp['scheme'];
|
||||
if ($pp['scheme']=='https')
|
||||
$pp['host']='ssl://'.$pp['host'];
|
||||
if (empty($pp['port']))
|
||||
$pp['port']=$pp['scheme']=='https'?443:80;
|
||||
$socket=@fsockopen($pp['host'],$pp['port'],$code,$err);
|
||||
} else {
|
||||
$req=$parts['path'].($parts['query']?('?'.$parts['query']):'');
|
||||
$socket=@fsockopen($parts['host'],$parts['port'],$code,$err);
|
||||
}
|
||||
if ($socket) {
|
||||
stream_set_blocking($socket,TRUE);
|
||||
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
|
||||
);
|
||||
if ($proxy=='socks4') {
|
||||
// SOCKS4; http://en.wikipedia.org/wiki/SOCKS#Protocol
|
||||
$packet="\x04\x01".pack("n", $parts['port']).
|
||||
pack("H*",dechex(ip2long(gethostbyname($hostname))))."\0";
|
||||
fputs($socket, $packet, strlen($packet));
|
||||
$response=fread($socket, 9);
|
||||
if (strlen($response)==8 && (ord($response[0])==0 || ord($response[0])==4)
|
||||
&& ord($response[1])==90) {
|
||||
$options['header'][]='Host: '.$hostname;
|
||||
} else
|
||||
$err='Socket Status '.ord($response[1]);
|
||||
}
|
||||
fputs($socket,$options['method'].' '.$req.' HTTP/1.0'.$eol);
|
||||
fputs($socket,implode($eol,$options['header']).$eol.$eol);
|
||||
if (isset($options['content']))
|
||||
fputs($socket,$options['content'].$eol);
|
||||
@@ -508,12 +537,6 @@ class Web extends Prefab {
|
||||
$this->engine();
|
||||
if ($this->wrapper!='stream') {
|
||||
// PHP streams can't cope with redirects when Host header is set
|
||||
foreach ($options['header'] as &$header)
|
||||
if (preg_match('/^Host:/',$header)) {
|
||||
$header='Host: '.$parts['host'];
|
||||
unset($header);
|
||||
break;
|
||||
}
|
||||
$this->subst($options['header'],'Host: '.$parts['host']);
|
||||
}
|
||||
$this->subst($options['header'],
|
||||
|
||||
@@ -64,8 +64,8 @@ class Geo extends \Prefab {
|
||||
$out=@geoip_record_by_name($ip)) {
|
||||
$out['request']=$ip;
|
||||
$out['region_code']=$out['region'];
|
||||
$out['region_name']=geoip_region_name_by_code(
|
||||
$out['country_code'],$out['region']);
|
||||
$out['region_name']=(!empty($out['country_code']) && !empty($out['region']))
|
||||
? geoip_region_name_by_code($out['country_code'],$out['region']) : '';
|
||||
unset($out['country_code3'],$out['region'],$out['postal_code']);
|
||||
return $out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user