diff --git a/lib/CHANGELOG.md b/lib/CHANGELOG.md index b406321c4..b98111f71 100644 --- a/lib/CHANGELOG.md +++ b/lib/CHANGELOG.md @@ -1,19 +1,34 @@ CHANGELOG +3.7.3 +* NEW: added auto_increment detection, [bcosca/fatfree#1192](https://github.com/bcosca/fatfree/issues/1192), [bcosca/fatfree#1093](https://github.com/bcosca/fatfree/issues/1093), [bcosca/fatfree#1175](https://github.com/bcosca/fatfree/issues/1175), [#290](https://github.com/bcosca/fatfree-core/issues/290) +* added SMTP dialog error handling, [#317](https://github.com/bcosca/fatfree-core/issues/317) +* Fix: Check active transaction before rollback/commit (PHP8 issue) +* refactored increment/decrement operator to preceed variables +* added error output in CLI mode, [bcosca/fatfree#1185](https://github.com/bcosca/fatfree/issues/1185) +* Set PORT to 80 when SERVER_PORT is an empty string +* Fix: unescape dbname when extracting from dsn, [#316](https://github.com/bcosca/fatfree-core/issues/316) +* Fix: handling of PDO prepare() errors +* Fix: edge case in DB\SQL->schema(): PK not detected in PgSQL when the column is also a FK [bcosca/fatfree#1207](https://github.com/bcosca/fatfree/issues/1207) +* Fix: Escape literal hyphens in regex character classes, [bcosca/fatfree#1206](https://github.com/bcosca/fatfree/issues/1206) +* Fix: error highlighting +* Fix: pagination with order by on virtual fields +* Fixed a couple PHPDOC issues + 3.7.2 (28 May 2020) -* CHANGED, View->sandbox: disable escaping when rendering as text/plain, bcosca/fatfree#654 -* update HTTP protocol checks, #bcosca/fatfree#1190 -* Base->clear: close vulnerability on variable compilation, bcosca/fatfree#1191 -* DB\SQL\Mapper: fix empty ID after insert, bcosca/fatfree#1175 +* CHANGED, View->sandbox: disable escaping when rendering as text/plain, [bcosca/fatfree#654](https://github.com/bcosca/fatfree/issues/654) +* update HTTP protocol checks, [bcosca/fatfree#1190](https://github.com/bcosca/fatfree/issues/1190) +* Base->clear: close vulnerability on variable compilation, [bcosca/fatfree#1191](https://github.com/bcosca/fatfree/issues/1191) +* DB\SQL\Mapper: fix empty ID after insert, [bcosca/fatfree#1175](https://github.com/bcosca/fatfree/issues/1175) * DB\SQL\Mapper: fix using correct key variable for grouped sql pagination sets -* Fix return type of 'count' in Cursor->paginate() (bcosca/fatfree#1187) -* Bug fix, Web->minify: fix minification of ES6 template literals, bcosca/fatfree#1178 -* Bug fix, config: refactoring custom section parser regex, bcosca/fatfree#1149 -* Bug fix: token resolve on non-alias reroute paths, ref. 221f0c930f8664565c9825faeb9ed9af0f7a01c8 +* Fix return type of 'count' in Cursor->paginate(), [bcosca/fatfree#1187](https://github.com/bcosca/fatfree/issues/1187) +* Bug fix, Web->minify: fix minification of ES6 template literals, [bcosca/fatfree#1178](https://github.com/bcosca/fatfree/issues/1178) +* Bug fix, config: refactoring custom section parser regex, [bcosca/fatfree#1149](https://github.com/bcosca/fatfree/issues/1149) +* Bug fix: token resolve on non-alias reroute paths, [ref. 221f0c9](https://github.com/bcosca/fatfree-core/commit/221f0c930f8664565c9825faeb9ed9af0f7a01c8) * Websocket: Improved event handler usage * optimized internal get calls * only use cached lexicon when a $ttl was given -* only use money_format up until php7.4, fixes bcosca/fatfree#1174 +* only use money_format up until php7.4, [bcosca/fatfree#1174](https://github.com/bcosca/fatfree/issues/1174) 3.7.1 (30. December 2019) * Base->build: Add support for brace-enclosed route tokens diff --git a/lib/audit.php b/lib/audit.php index 8fcc95ae5..a0d4338e6 100644 --- a/lib/audit.php +++ b/lib/audit.php @@ -145,7 +145,7 @@ function mod10($id) { return FALSE; $id=strrev($id); $sum=0; - for ($i=0,$l=strlen($id);$i<$l;$i++) + for ($i=0,$l=strlen($id);$i<$l;++$i) $sum+=$id[$i]+$i%2*(($id[$i]>4)*-4+$id[$i]%5); return !($sum%10); } diff --git a/lib/base.php b/lib/base.php index ea72e7c31..dfb59c193 100644 --- a/lib/base.php +++ b/lib/base.php @@ -45,7 +45,7 @@ final class Base extends Prefab implements ArrayAccess { //@{ Framework details const PACKAGE='Fat-Free Framework', - VERSION='3.7.2-Release'; + VERSION='3.7.3-Release'; //@} //@{ HTTP status codes (RFC 2616) @@ -186,7 +186,7 @@ function($match) use(&$i,$args) { array_key_exists($match[3],$args)) { if (!is_array($args[$match[3]])) return $args[$match[3]]; - $i++; + ++$i; return $args[$match[3]][$i-1]; } return $match[0]; @@ -1293,10 +1293,10 @@ function trace(array $trace=NULL,$format=TRUE) { function($frame) use($debug) { return isset($frame['file']) && ($debug>1 || - ($frame['file']!=__FILE__ || $debug) && + (($frame['file']!=__FILE__ || $debug) && (empty($frame['function']) || !preg_match('/^(?:(?:trigger|user)_error|'. - '__call|call_user_func)/',$frame['function']))); + '__call|call_user_func)/',$frame['function'])))); } ); if (!$format) @@ -1349,8 +1349,8 @@ function error($code,$text='',array $trace=NULL,$level=0) { error_log($nexus); break; } - if ($highlight=!$this->hive['CLI'] && !$this->hive['AJAX'] && - $this->hive['HIGHLIGHT'] && is_file($css=__DIR__.'/'.self::CSS)) + if ($highlight=(!$this->hive['CLI'] && !$this->hive['AJAX'] && + $this->hive['HIGHLIGHT'] && is_file($css=__DIR__.'/'.self::CSS))) $trace=$this->highlight($trace); $this->hive['ERROR']=[ 'status'=>$header, @@ -1366,29 +1366,34 @@ function error($code,$text='',array $trace=NULL,$level=0) { if ((!$handler || $this->call($handler,[$this,$this->hive['PARAMS']], 'beforeroute,afterroute')===FALSE) && - !$prior && !$this->hive['CLI'] && !$this->hive['QUIET']) - echo $this->hive['AJAX']? - json_encode( - array_diff_key( - $this->hive['ERROR'], - $this->hive['DEBUG']? - []: - ['trace'=>1] - ) - ): - (''.$eol. - ''.$eol. - ''. - ''.$code.' '.$header.''. - ($highlight? - (''):''). - ''.$eol. - ''.$eol. - '

'.$header.'

'.$eol. - '

'.$this->encode($text?:$req).'

'.$eol. - ($this->hive['DEBUG']?('
'.$trace.'
'.$eol):''). - ''.$eol. - ''); + !$prior && !$this->hive['QUIET']) { + $error=array_diff_key( + $this->hive['ERROR'], + $this->hive['DEBUG']? + []: + ['trace'=>1] + ); + if ($this->hive['CLI']) + echo PHP_EOL.'==================================='.PHP_EOL. + 'ERROR '.$error['code'].' - '.$error['status'].PHP_EOL. + $error['text'].PHP_EOL.PHP_EOL.$error['trace']; + else + echo $this->hive['AJAX']? + json_encode($error): + (''.$eol. + ''.$eol. + ''. + ''.$code.' '.$header.''. + ($highlight? + (''):''). + ''.$eol. + ''.$eol. + '

'.$header.'

'.$eol. + '

'.$this->encode($text?:$req).'

'.$eol. + ($this->hive['DEBUG']?('
'.$trace.'
'.$eol):''). + ''.$eol. + ''); + } if ($this->hive['HALT']) die(1); } @@ -1615,7 +1620,7 @@ function mask($pattern,$url=NULL) { $i=0; while (is_int($pos=strpos($wild,'\*'))) { $wild=substr_replace($wild,'(?P<_'.$i.'>[^\?]*)',$pos,2); - $i++; + ++$i; } preg_match('/^'. preg_replace( @@ -1767,7 +1772,7 @@ function($id) use($args) { $ctr=0; foreach (str_split($body,1024) as $part) { // Throttle output - $ctr++; + ++$ctr; if ($ctr/$kbps>($elapsed=microtime(TRUE)-$now) && !connection_aborted()) usleep(1e6*($ctr/$kbps-$elapsed)); @@ -2197,7 +2202,7 @@ protected function autoload($class) { isset($path[1]) && is_callable($path[1])) list($path,$func)=$path; foreach ($this->split($this->hive['PLUGINS'].';'.$path) as $auto) - if ($func && is_file($file=$func($auto.$class).'.php') || + if (($func && is_file($file=$func($auto.$class).'.php')) || is_file($file=$auto.$class.'.php') || is_file($file=$auto.strtolower($class).'.php') || is_file($file=strtolower($auto.$class).'.php')) @@ -2345,11 +2350,11 @@ function($level,$text,$file,$line) { if (!isset($_SERVER['SERVER_NAME']) || $_SERVER['SERVER_NAME']==='') $_SERVER['SERVER_NAME']=gethostname(); $headers=[]; - if ($cli=PHP_SAPI=='cli') { + if ($cli=(PHP_SAPI=='cli')) { // Emulate HTTP request $_SERVER['REQUEST_METHOD']='GET'; if (!isset($_SERVER['argv'][1])) { - $_SERVER['argc']++; + ++$_SERVER['argc']; $_SERVER['argv'][1]='/'; } $req=$query=''; @@ -2433,9 +2438,9 @@ function($level,$text,$file,$line) { 'samesite'=>'Lax', ]; $port=80; - if (isset($headers['X-Forwarded-Port'])) + if (!empty($headers['X-Forwarded-Port'])) $port=$headers['X-Forwarded-Port']; - elseif (isset($_SERVER['SERVER_PORT'])) + elseif (!empty($_SERVER['SERVER_PORT'])) $port=$_SERVER['SERVER_PORT']; // Default configuration $this->hive+=[ @@ -2496,7 +2501,7 @@ function($level,$text,$file,$line) { 'QUIET'=>FALSE, 'RAW'=>FALSE, 'REALM'=>$scheme.'://'.$_SERVER['SERVER_NAME']. - ($port && !in_array($port,[80,443])?(':'.$port):''). + (!in_array($port,[80,443])?(':'.$port):''). $_SERVER['REQUEST_URI'], 'RESPONSE'=>'', 'ROOT'=>$_SERVER['DOCUMENT_ROOT'], @@ -2740,7 +2745,7 @@ function reset($suffix=NULL) { case 'xcache': if ($suffix && !ini_get('xcache.admin.enable_auth')) { $cnt=xcache_count(XC_TYPE_VAR); - for ($i=0;$i<$cnt;$i++) { + for ($i=0;$i<$cnt;++$i) { $list=xcache_list(XC_TYPE_VAR,$i); foreach ($list['cache_list'] as $item) if (preg_match($regex,$item['name'])) @@ -2898,10 +2903,10 @@ protected function sandbox(array $hive=NULL,$mime=NULL) { unset($fw,$hive,$implicit,$mime); extract($this->temp); $this->temp=NULL; - $this->level++; + ++$this->level; ob_start(); require($this->file); - $this->level--; + --$this->level; return ob_get_clean(); } diff --git a/lib/bcrypt.php b/lib/bcrypt.php index f044ff1dd..414daa739 100644 --- a/lib/bcrypt.php +++ b/lib/bcrypt.php @@ -56,7 +56,7 @@ function hash($pw,$salt=NULL,$cost=self::COST) { if (!$iv && extension_loaded('openssl')) $iv=openssl_random_pseudo_bytes($raw); if (!$iv) - for ($i=0;$i<$raw;$i++) + for ($i=0;$i<$raw;++$i) $iv.=chr(mt_rand(0,255)); $salt=str_replace('+','.',base64_encode($iv)); } @@ -88,7 +88,7 @@ function verify($pw,$hash) { if ($len!=strlen($hash) || $len<14) return FALSE; $out=0; - for ($i=0;$i<$len;$i++) + for ($i=0;$i<$len;++$i) $out|=(ord($val[$i])^ord($hash[$i])); return $out===0; } diff --git a/lib/cli/ws.php b/lib/cli/ws.php index f1573c010..4545e9bcc 100644 --- a/lib/cli/ws.php +++ b/lib/cli/ws.php @@ -424,16 +424,16 @@ function fetch() { } else if ($len==0x7f) { - for ($i=0,$len=0;$i<8;$i++) + for ($i=0,$len=0;$i<8;++$i) $len=$len*256+ord($buf[$i+2]); $pos+=8; } - for ($i=0,$mask=[];$i<4;$i++) + for ($i=0,$mask=[];$i<4;++$i) $mask[$i]=ord($buf[$pos+$i]); $pos+=4; if (strlen($buf)<$len+$pos) return FALSE; - for ($i=0,$data='';$i<$len;$i++) + for ($i=0,$data='';$i<$len;++$i) $data.=chr(ord($buf[$pos+$i])^$mask[$i%4]); // Dispatch switch ($op & WS::OpCode) { diff --git a/lib/db/jig/mapper.php b/lib/db/jig/mapper.php index 784b2a8f0..5d26427f0 100644 --- a/lib/db/jig/mapper.php +++ b/lib/db/jig/mapper.php @@ -206,7 +206,7 @@ function($_row) use($fw,$args,$tokens) { if (is_string($token)) if ($token=='?') { // Positional - $ctr++; + ++$ctr; $key=$ctr; } else { diff --git a/lib/db/sql.php b/lib/db/sql.php index 4e464d7e8..566b94a73 100644 --- a/lib/db/sql.php +++ b/lib/db/sql.php @@ -66,7 +66,9 @@ function begin() { * @return bool **/ function rollback() { - $out=$this->pdo->rollback(); + $out=FALSE; + if ($this->pdo->inTransaction()) + $out=$this->pdo->rollback(); $this->trans=FALSE; return $out; } @@ -76,7 +78,9 @@ function rollback() { * @return bool **/ function commit() { - $out=$this->pdo->commit(); + $out=FALSE; + if ($this->pdo->inTransaction()) + $out=$this->pdo->commit(); $this->trans=FALSE; return $out; } @@ -173,7 +177,7 @@ function exec($cmds,$args=NULL,$ttl=0,$log=TRUE,$stamp=FALSE) { $fw=\Base::instance(); $cache=\Cache::instance(); $result=FALSE; - for ($i=0;$i<$count;$i++) { + for ($i=0;$i<$count;++$i) { $cmd=$cmds[$i]; $arg=$args[$i]; // ensure 1-based arguments @@ -257,7 +261,7 @@ function exec($cmds,$args=NULL,$ttl=0,$log=TRUE,$stamp=FALSE) { $query->closecursor(); unset($query); } - elseif (($error=$this->errorinfo()) && $error[0]!=\PDO::ERR_NONE) { + elseif (($error=$this->pdo->errorInfo()) && $error[0]!=\PDO::ERR_NONE) { // PDO-level error occurred if ($this->trans) $this->rollback(); @@ -321,19 +325,37 @@ function schema($table,$fields=NULL,$ttl=0) { if (strpos($table,'.')) list($schema,$table)=explode('.',$table); // Supported engines + // format: engine_name => array of: + // 0: query + // 1: field name of column name + // 2: field name of column type + // 3: field name of default value + // 4: field name of nullable value + // 5: expected field value to be nullable + // 6: field name of primary key flag + // 7: expected field value to be a primary key + // 8: field name of auto increment check (optional) + // 9: expected field value to be an auto-incremented identifier $cmd=[ 'sqlite2?'=>[ - 'PRAGMA table_info(`'.$table.'`)', - 'name','type','dflt_value','notnull',0,'pk',TRUE], + 'SELECT * FROM pragma_table_info('.$this->quote($table).') JOIN ('. + 'SELECT sql FROM sqlite_master WHERE type=\'table\' AND '. + 'name='.$this->quote($table).')', + 'name','type','dflt_value','notnull',0,'pk',TRUE,'sql', + '/\W(%s)\W+[^,]+?AUTOINCREMENT\W/i'], 'mysql'=>[ 'SHOW columns FROM `'.$this->dbname.'`.`'.$table.'`', - 'Field','Type','Default','Null','YES','Key','PRI'], + 'Field','Type','Default','Null','YES','Key','PRI','Extra','auto_increment'], 'mssql|sqlsrv|sybase|dblib|pgsql|odbc'=>[ 'SELECT '. 'C.COLUMN_NAME AS field,'. 'C.DATA_TYPE AS type,'. 'C.COLUMN_DEFAULT AS defval,'. 'C.IS_NULLABLE AS nullable,'. + ($this->engine=='pgsql' + ?'COALESCE(POSITION(\'nextval\' IN C.COLUMN_DEFAULT),0) AS autoinc,' + :'columnproperty(object_id(C.TABLE_NAME),C.COLUMN_NAME,\'IsIdentity\')' + .' AS autoinc,'). 'T.CONSTRAINT_TYPE AS pkey '. 'FROM INFORMATION_SCHEMA.COLUMNS AS C '. 'LEFT OUTER JOIN '. @@ -356,7 +378,7 @@ function schema($table,$fields=NULL,$ttl=0) { ($this->dbname? (' AND C.TABLE_CATALOG='. $this->quote($this->dbname)):''), - 'field','type','defval','nullable','YES','pkey','PRIMARY KEY'], + 'field','type','defval','nullable','YES','pkey','PRIMARY KEY','autoinc',1], 'oci'=>[ 'SELECT c.column_name AS field, '. 'c.data_type AS type, '. @@ -390,15 +412,22 @@ function schema($table,$fields=NULL,$ttl=0) { foreach ($conv as $regex=>$type) if (preg_match('/'.$regex.'/i',$row[$val[2]])) break; - $rows[$row[$val[1]]]=[ - 'type'=>$row[$val[2]], - 'pdo_type'=>$type, - 'default'=>is_string($row[$val[3]])? - preg_replace('/^\s*([\'"])(.*)\1\s*/','\2', - $row[$val[3]]):$row[$val[3]], - 'nullable'=>$row[$val[4]]==$val[5], - 'pkey'=>$row[$val[6]]==$val[7] - ]; + if (!isset($rows[$row[$val[1]]])) // handle duplicate rows in PgSQL + $rows[$row[$val[1]]]=[ + 'type'=>$row[$val[2]], + 'pdo_type'=>$type, + 'default'=>is_string($row[$val[3]])? + preg_replace('/^\s*([\'"])(.*)\1\s*/','\2', + $row[$val[3]]):$row[$val[3]], + 'nullable'=>$row[$val[4]]==$val[5], + 'pkey'=>$row[$val[6]]==$val[7], + 'auto_inc'=>isset($val[8]) && isset($row[$val[8]]) + ? ($this->engine=='sqlite'? + (bool) preg_match(sprintf($val[9],$row[$val[1]]), + $row[$val[8]]): + ($row[$val[8]]==$val[9]) + ) : NULL, + ]; } if ($fw->CACHE && $ttl) // Save to cache backend @@ -510,7 +539,7 @@ function __construct($dsn,$user=NULL,$pw=NULL,array $options=NULL) { $fw=\Base::instance(); $this->uuid=$fw->hash($this->dsn=$dsn); if (preg_match('/^.+?(?:dbname|database)=(.+?)(?=;|$)/is',$dsn,$parts)) - $this->dbname=$parts[1]; + $this->dbname=str_replace('\\ ',' ',$parts[1]); if (!$options) $options=[]; if (isset($parts[0]) && strstr($parts[0],':',TRUE)=='mysql') diff --git a/lib/db/sql/mapper.php b/lib/db/sql/mapper.php index 1eb45c6d0..574cc9fbd 100644 --- a/lib/db/sql/mapper.php +++ b/lib/db/sql/mapper.php @@ -378,6 +378,9 @@ function count($filter=NULL,array $options=NULL,$ttl=0) { // for simple count just add a new adhoc counter $fields='COUNT(*) AS '.$this->db->quotekey('_rows'); } + // no need to order for a count query as that could include virtual + // field references that are not present here + unset($options['order']); list($sql,$args)=$this->stringify($fields,$filter,$options); if ($subquery_mode) $sql='SELECT COUNT(*) AS '.$this->db->quotekey('_rows').' '. @@ -438,27 +441,30 @@ function insert() { // duplicate record foreach ($this->fields as $key=>&$field) { $field['changed']=true; - if ($field['pkey'] && !$inc && $field['pdo_type']==\PDO::PARAM_INT - && !$field['nullable']) + if ($field['pkey'] && !$inc && ($field['auto_inc'] === TRUE || + ($field['auto_inc'] === NULL && !$field['nullable'] + && $field['pdo_type']==\PDO::PARAM_INT) + )) $inc=$key; unset($field); } foreach ($this->fields as $key=>&$field) { if ($field['pkey']) { $field['previous']=$field['value']; - if (!$inc && $field['pdo_type']==\PDO::PARAM_INT && - empty($field['value']) && !$field['nullable'] && - is_null($field['default'])) + if (!$inc && empty($field['value']) && + ($field['auto_inc'] === TRUE || ($field['auto_inc'] === NULL + && $field['pdo_type']==\PDO::PARAM_INT && !$field['nullable'])) + ) $inc=$key; $filter.=($filter?' AND ':'').$this->db->quotekey($key).'=?'; $nkeys[$nctr+1]=[$field['value'],$field['pdo_type']]; - $nctr++; + ++$nctr; } if ($field['changed'] && $key!=$inc) { $fields.=($actr?',':'').$this->db->quotekey($key); $values.=($actr?',':'').'?'; $args[$actr+1]=[$field['value'],$field['pdo_type']]; - $actr++; + ++$actr; $ckeys[]=$key; } unset($field); @@ -617,7 +623,7 @@ function erase($filter=NULL,$quick=TRUE) { $filter.=($filter?' AND ':'').$this->db->quotekey($key).'=?'; $args[$ctr+1]=[$field['previous'],$field['pdo_type']]; $pkeys[$key]=$field['previous']; - $ctr++; + ++$ctr; } $field['value']=NULL; $field['changed']=(bool)$field['default']; diff --git a/lib/image.php b/lib/image.php index 59c165eb7..b7f149ced 100644 --- a/lib/image.php +++ b/lib/image.php @@ -367,15 +367,15 @@ function identicon($str,$size=64,$blocks=4) { imagefill($this->data,0,0,IMG_COLOR_TRANSPARENT); $ctr=count($sprites); $dim=$blocks*floor($size/$blocks)*2/$blocks; - for ($j=0,$y=ceil($blocks/2);$j<$y;$j++) - for ($i=$j,$x=$blocks-1-$j;$i<$x;$i++) { + for ($j=0,$y=ceil($blocks/2);$j<$y;++$j) + for ($i=$j,$x=$blocks-1-$j;$i<$x;++$i) { $sprite=imagecreatetruecolor($dim,$dim); imagefill($sprite,0,0,IMG_COLOR_TRANSPARENT); $block=$sprites[hexdec($hash[($j*$blocks+$i)*2])%$ctr]; - for ($k=0,$pts=count($block);$k<$pts;$k++) + for ($k=0,$pts=count($block);$k<$pts;++$k) $block[$k]*=$dim; imagefilledpolygon($sprite,$block,$pts/2,$fg); - for ($k=0;$k<4;$k++) { + for ($k=0;$k<4;++$k) { imagecopyresampled($this->data,$sprite, $i*$dim/2,$j*$dim/2,0,0,$dim/2,$dim/2,$dim,$dim); $this->data=imagerotate($this->data,90, @@ -416,7 +416,7 @@ function captcha($font,$size=24,$len=5, -$len)); $block=$size*3; $tmp=[]; - for ($i=0,$width=0,$height=0;$i<$len;$i++) { + for ($i=0,$width=0,$height=0;$i<$len;++$i) { // Process at 2x magnification $box=imagettfbbox($size*2,0,$path,$seed[$i]); $w=$box[2]-$box[0]; @@ -440,7 +440,7 @@ function captcha($font,$size=24,$len=5, } $this->data=imagecreatetruecolor($width,$height); imagefill($this->data,0,0,IMG_COLOR_TRANSPARENT); - for ($i=0;$i<$len;$i++) { + for ($i=0;$i<$len;++$i) { imagecopy($this->data,$tmp[$i], $i*$block/2,($height-imagesy($tmp[$i]))/2,0,0, imagesx($tmp[$i]),imagesy($tmp[$i])); @@ -520,7 +520,7 @@ function save() { if ($this->flag) { if (!is_dir($dir=$fw->TEMP)) mkdir($dir,Base::MODE,TRUE); - $this->count++; + ++$this->count; $fw->write($dir.'/'.$fw->SEED.'.'. $fw->hash($this->file).'-'.$this->count.'.png', $this->dump()); diff --git a/lib/markdown.php b/lib/markdown.php index 885f21582..4be4c5611 100644 --- a/lib/markdown.php +++ b/lib/markdown.php @@ -224,7 +224,7 @@ protected function _li($str) { $type='ul'; // Main loop while ($ptr<$len) { - if (preg_match('/^\h*[*-](?:\h?[*-]){2,}(?:\n+|$)/', + if (preg_match('/^\h*[*\-](?:\h?[*\-]){2,}(?:\n+|$)/', substr($str,$ptr),$match)) { $ptr+=strlen($match[0]); // Embedded horizontal rule @@ -232,7 +232,7 @@ protected function _li($str) { ('<'.$type.'>'."\n".$dst.''."\n\n"):''). '
'."\n\n".$this->build(substr($str,$ptr)); } - elseif (preg_match('/(?<=^|\n)([*+-]|\d+\.)\h'. + elseif (preg_match('/(?<=^|\n)([*+\-]|\d+\.)\h'. '(.+?(?:\n+|$))((?:(?: {4}|\t)+.+?(?:\n+|$))*)/s', substr($str,$ptr),$match)) { $match[3]=preg_replace('/(?<=^|\n)(?: {4}|\t)/','',$match[3]); @@ -466,10 +466,10 @@ protected function build($str) { 'pre'=>'/^(?:(?: {4}|\t).+?(?:\n+|$))+/', 'fence'=>'/^`{3}\h*(\w+)?.*?[^\n]*\n+(.+?)`{3}[^\n]*'. '(?:\n+|$)/s', - 'hr'=>'/^\h*[*_-](?:\h?[\*_-]){2,}\h*(?:\n+|$)/', + 'hr'=>'/^\h*[*_\-](?:\h?[\*_\-]){2,}\h*(?:\n+|$)/', 'atx'=>'/^\h*(#{1,6})\h?(.+?)\h*(?:#.*)?(?:\n+|$)/', - 'setext'=>'/^\h*(.+?)\h*\n([=-])+\h*(?:\n+|$)/', - 'li'=>'/^(?:(?:[*+-]|\d+\.)\h.+?(?:\n+|$)'. + 'setext'=>'/^\h*(.+?)\h*\n([=\-])+\h*(?:\n+|$)/', + 'li'=>'/^(?:(?:[*+\-]|\d+\.)\h.+?(?:\n+|$)'. '(?:(?: {4}|\t)+.+?(?:\n+|$))*)+/s', 'raw'=>'/^((?:|'. '<(address|article|aside|audio|blockquote|canvas|dd|'. diff --git a/lib/matrix.php b/lib/matrix.php index d1f00877f..6c22bae21 100644 --- a/lib/matrix.php +++ b/lib/matrix.php @@ -130,7 +130,7 @@ function calendar($date='now',$first=0) { $days=cal_days_in_month(CAL_GREGORIAN,$parts['mon'],$parts['year']); $ref=date('w',strtotime(date('Y-m',$parts[0]).'-01'))+(7-$first)%7; $out=[]; - for ($i=0;$i<$days;$i++) + for ($i=0;$i<$days;++$i) $out[floor(($ref+$i)/7)][($ref+$i)%7]=$i+1; } return $out; diff --git a/lib/smtp.php b/lib/smtp.php index 415a13991..8cef93932 100644 --- a/lib/smtp.php +++ b/lib/smtp.php @@ -27,7 +27,8 @@ class SMTP extends Magic { const E_Header='%s: header is required', E_Blank='Message must not be blank', - E_Attach='Attachment %s not found'; + E_Attach='Attachment %s not found', + E_DIALOG='SMTP dialog error: %s'; //@} protected @@ -59,7 +60,7 @@ class SMTP extends Magic { **/ protected function fixheader($key) { return str_replace(' ','-', - ucwords(preg_replace('/[_-]/',' ',strtolower($key)))); + ucwords(preg_replace('/[_\-]/',' ',strtolower($key)))); } /** @@ -157,6 +158,8 @@ protected function dialog($cmd=NULL,$log=TRUE,$mock=FALSE) { $this->log.=$cmd."\n"; $this->log.=str_replace("\r",'',$reply); } + if (preg_match('/^(4|5)\d{2}\s.*$/', $reply)) + user_error(sprintf(self::E_DIALOG,$reply),E_USER_ERROR); return $reply; } diff --git a/lib/template.php b/lib/template.php index 6d920c5cf..fb6f21dd6 100644 --- a/lib/template.php +++ b/lib/template.php @@ -273,7 +273,7 @@ function parse($text) { // 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)) { @@ -283,7 +283,7 @@ function parse($text) { if ($match[2]) { // Find matching start tag $stack=[]; - for($i=count($tree)-1;$i>=0;$i--) { + for($i=count($tree)-1;$i>=0;--$i) { $item=$tree[$i]; if (is_array($item) && array_key_exists($match[3],$item) && @@ -326,7 +326,7 @@ function parse($text) { $tmp.=substr($text,$ptr,$w); $ptr+=$w; if ($w<50) - $w++; + ++$w; } if (strlen($tmp)) // Append trailing text diff --git a/lib/web.php b/lib/web.php index 05aecac72..7a69051d1 100644 --- a/lib/web.php +++ b/lib/web.php @@ -230,7 +230,7 @@ function send($file,$mime=NULL,$kbps=0,$force=TRUE,$name=NULL,$flush=TRUE) { !$info['timed_out'] && !connection_aborted()) { if ($kbps) { // Throttle output - $ctr++; + ++$ctr; if ($ctr/$kbps>$elapsed=microtime(TRUE)-$start) usleep(1e6*($ctr/$kbps-$elapsed)); } @@ -385,7 +385,7 @@ function($curl,$line) use(&$headers) { $options['follow_location'] && $open_basedir && preg_grep('/HTTP\/[\d.]{1,3} 3\d{2}/',$headers) && preg_match('/^Location: (.+)$/m',implode(PHP_EOL,$headers),$loc)) { - $options['max_redirects']--; + --$options['max_redirects']; if($loc[1][0] == '/') { $parts=parse_url($url); $loc[1]=$parts['scheme'].'://'.$parts['host']. @@ -533,7 +533,7 @@ protected function _socket($url,$options) { preg_grep('/HTTP\/[\d.]{1,3} 3\d{2}/',$headers) && preg_match('/Location: (.+?)'.preg_quote($eol).'/', $html[0],$loc)) { - $options['max_redirects']--; + --$options['max_redirects']; return $this->request($loc[1],$options); } } @@ -743,7 +743,7 @@ function minify($files,$mime=NULL,$header=TRUE,$path=NULL) { // Presume it's a regex pattern $regex=TRUE; // Backtrack and validate - for ($ofs=$ptr;$ofs;$ofs--) { + for ($ofs=$ptr;$ofs;--$ofs) { // Pattern should be preceded by // open parenthesis, colon, // object property or operator @@ -751,13 +751,13 @@ function minify($files,$mime=NULL,$header=TRUE,$path=NULL) { '/(return|[(:=!+\-*&|])$/', substr($src,0,$ofs))) { $data.='/'; - $ptr++; + ++$ptr; while ($ptr<$len) { $data.=$src[$ptr]; - $ptr++; + ++$ptr; if ($src[$ptr-1]=='\\') { $data.=$src[$ptr]; - $ptr++; + ++$ptr; } elseif ($src[$ptr-1]=='/') break; @@ -773,7 +773,7 @@ function minify($files,$mime=NULL,$header=TRUE,$path=NULL) { if (!$regex) { // Division operator $data.=$src[$ptr]; - $ptr++; + ++$ptr; } } continue; @@ -781,14 +781,14 @@ function minify($files,$mime=NULL,$header=TRUE,$path=NULL) { if (in_array($src[$ptr],['\'','"','`'])) { $match=$src[$ptr]; $data.=$match; - $ptr++; + ++$ptr; // String literal while ($ptr<$len) { $data.=$src[$ptr]; - $ptr++; + ++$ptr; if ($src[$ptr-1]=='\\') { $data.=$src[$ptr]; - $ptr++; + ++$ptr; } elseif ($src[$ptr-1]==$match) break; @@ -804,11 +804,11 @@ function minify($files,$mime=NULL,$header=TRUE,$path=NULL) { ($ext[0]=='css' && $ptr+2channel)) { $out['source']=(string)$xml->channel->title; $max=min($max,count($xml->channel->item)); - for ($i=0;$i<$max;$i++) { + for ($i=0;$i<$max;++$i) { $item=$xml->channel->item[$i]; $list=[''=>NULL]+$item->getnamespaces(TRUE); $fields=[]; @@ -984,7 +984,7 @@ function filler($count=1,$max=20,$std=TRUE) { 'repudiandae rerum saepe sapiente sequi similique sint soluta '. 'suscipit tempora tenetur totam ut ullam unde vel veniam vero '. 'vitae voluptas'); - for ($i=0,$add=$count-(int)$std;$i<$add;$i++) { + for ($i=0,$add=$count-(int)$std;$i<$add;++$i) { shuffle($rnd); $words=array_slice($rnd,0,mt_rand(3,$max)); $out.=(!$std&&$i==0?'':' ').ucfirst(implode(' ',$words)).'.'; diff --git a/lib/web/oauth2.php b/lib/web/oauth2.php index 7a04602cb..eda6e45f1 100644 --- a/lib/web/oauth2.php +++ b/lib/web/oauth2.php @@ -44,10 +44,10 @@ function uri($endpoint,$query=TRUE) { /** * Send request to API/token endpoint - * @return string|FALSE + * @return string|array|FALSE * @param $uri string * @param $method string - * @param $token array + * @param $token string **/ function request($uri,$method,$token=NULL) { $web=\Web::instance(); diff --git a/lib/web/openid.php b/lib/web/openid.php index c940af32c..6e84b6122 100644 --- a/lib/web/openid.php +++ b/lib/web/openid.php @@ -103,7 +103,7 @@ protected function discover($proxy) { $ptr+=strlen($parts[0]); } else - $ptr++; + ++$ptr; } // Get OpenID provider's endpoint URL if (isset($this->args['provider'])) {