ソースを参照

Merge branch 'master' of https://code.istudy.wang/root/Qii

# Conflicts:
#	src/Base/Request.php
Jinhui Zhu 4 年 前
コミット
f0d806ae42

+ 7 - 6
src/Application.php

@@ -46,6 +46,10 @@ class Application
      * 分发器
      */
     public $dispatcher = null;
+    /**
+     * @var mixed $helper
+     */
+    public $helper;
 
     public function __construct()
     {
@@ -178,11 +182,7 @@ class Application
         if ($env == '') $env = $this->getEnv();
         $ini = Psr4::getInstance()->getFileByPrefix($ini);
         $this->setAppIniFile($ini);
-        if (!Register::setAppConfigure(
-            $ini,
-            $env
-        )
-        ) throw new \Qii\Exceptions\FileNotFound($ini, 404);
+        if (!Register::setAppConfigure($ini, $env)) throw new \Qii\Exceptions\FileNotFound($ini, 404);
         //载入request方法
         $this->request = Psr4::getInstance()->loadClass('\Qii\Request\Http');
         Setting::getInstance()->setDefaultTimeZone();
@@ -316,8 +316,9 @@ class Application
 
         $servers = explode(";", $cacheInfo['servers']);
         $ports = explode(";", $cacheInfo['ports']);
+        $password = explode(';', $cacheInfo['password']);
         for ($i = 0; $i < count($servers); $i++) {
-            $data[] = array('host' => $servers[$i], 'port' => $ports[$i]);
+            $data[] = array('host' => $servers[$i], 'port' => $ports[$i], 'password' => $password[$i]);
         }
         return $data;
     }

+ 30 - 18
src/Base/Request.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace Qii\Base;
 
 abstract class Request
@@ -33,6 +34,7 @@ abstract class Request
      * @var Qii_Request_Url url
      */
     public $url;
+
     /**
      * 初始化参数,获取链接中对应的参数并存放到$this->params中
      *
@@ -50,6 +52,11 @@ abstract class Request
         $routeInfo = (array)$this->url->getPathArgs();
 		$controller = $this->defaultController();
         $action = $this->defaultAction();
+        //cli 模式处理
+        if(IS_CLI) {
+            $routeInfo = $this->url->request->getCliPathArgs();
+        }
+
 		if(count($routeInfo) > 1)
 		{
 			$action = array_pop($routeInfo);
@@ -57,14 +64,14 @@ abstract class Request
 		}
 		else if(count($routeInfo) == 1 && !empty($routeInfo[0])) {
 			$controller = $routeInfo[0];
-		}
-        //处理url中的数据
-        if(ucwords($rewriteRule) == 'Short'){
+		}        //处理url中的数据
+        if (ucwords($rewriteRule) == 'Short') {
             $this->setControllerName($controller);
             $this->setActionName($action);
         }
         return $this;
     }
+
     /**
      * 获取POST数据
      */
@@ -72,6 +79,7 @@ abstract class Request
     {
         return call_user_func_array(array($this->url, 'post'), func_get_args());
     }
+
     /**
      * 默认controller
      */
@@ -79,6 +87,7 @@ abstract class Request
     {
         return \Qii\Config\Register::get(\Qii\Config\Consts::APP_DEFAULT_CONTROLLER, 'index');
     }
+
     /**
      * 默认action
      */
@@ -98,7 +107,7 @@ abstract class Request
     public function redirect($url)
     {
         ob_clean();
-        header('Location:'. $url);
+        header('Location:' . $url);
     }
 
     /**
@@ -524,6 +533,7 @@ abstract class Request
         }
         return false;
     }
+
     /**
      * 是否需要转发
      */
@@ -531,6 +541,7 @@ abstract class Request
     {
         return $this->forward;
     }
+
     /**
      * 设置是否需要转发
      * @param bool $flag
@@ -549,16 +560,16 @@ abstract class Request
      * __setbaseUri
      *
      * @param string $baseUri
-     * @param string $request_uri
+     * @param string $requestUri
      * @return boolean
      */
-    protected function _setbaseUri($baseUri, $request_uri = null)
+    protected function _setBaseUri($baseUri, $requestUri = null)
     {
         if ($baseUri && is_string($baseUri)) {
             $this->_baseUri = $baseUri;
 
             return true;
-        } elseif ($request_uri && is_string($request_uri)) {
+        } elseif ($requestUri && is_string($requestUri)) {
             $scriptFileName = $this->getServer('SCRIPT_FILENAME');
 
             do {
@@ -566,21 +577,21 @@ abstract class Request
                     $fileName = basename($scriptFileName, \Qii::getInstance()->appConfigure('ext', '.php'));
                     $fileNameLen = strlen($fileName);
 
-                    $script_name = $this->getServer('SCRIPT_NAME');
-                    if ($script_name && is_string($script_name)) {
-                        $script = basename($script_name);
+                    $scriptName = $this->getServer('SCRIPT_NAME');
+                    if ($scriptName && is_string($scriptName)) {
+                        $script = basename($scriptName);
 
                         if (strncmp($fileName, $script, $fileNameLen) == 0) {
-                            $basename = $script_name;
+                            $basename = $scriptName;
                             break;
                         }
                     }
 
-                    $phpself_name = $this->getServer('PHP_SELF');
-                    if ($phpself_name && is_string($phpself_name)) {
-                        $phpself = basename($phpself_name);
-                        if (strncmp($fileName, $phpself, $fileNameLen) == 0) {
-                            $basename = $phpself_name;
+                    $phpSelfName = $this->getServer('PHP_SELF');
+                    if ($phpSelfName && is_string($phpSelfName)) {
+                        $phpSelf = basename($phpSelfName);
+                        if (strncmp($fileName, $phpSelf, $fileNameLen) == 0) {
+                            $basename = $phpSelfName;
                             break;
                         }
                     }
@@ -596,14 +607,14 @@ abstract class Request
                 }
             } while (0);
 
-            if ($basename && strstr($request_uri, $basename) == $request_uri) {
+            if ($basename && strstr($requestUri, $basename) == $requestUri) {
                 $this->_baseUri = rtrim($basename, '/');
 
                 return true;
             } elseif ($basename) {
                 $dirname = rtrim(dirname($basename), '/');
                 if ($dirname) {
-                    if (strstr($request_uri, $dirname) == $request_uri) {
+                    if (strstr($requestUri, $dirname) == $requestUri) {
                         $this->_baseUri = $dirname;
 
                         return true;
@@ -618,6 +629,7 @@ abstract class Request
 
         return false;
     }
+
     /**
      * 对于不存在的方法默认调用url中的方法
      */

+ 6 - 4
src/Cache/Redis.php

@@ -19,7 +19,7 @@ class Redis implements Intf
          * 缓存服务器配置,参看$_default_server
          * 允许多个缓存服务器
          */
-        'servers' => array(['host' => '127.0.0.1', 'port' => '6379']),
+        'servers' => array(['host' => '127.0.0.1', 'port' => '6379', 'password' => '']),
 
         /**
          * 缓存有效时间
@@ -42,7 +42,7 @@ class Redis implements Intf
 
         $redisServer = array();
         foreach ($this->policy['servers'] AS $value) {
-            $redisServer[] = array('host' => $value['host'], 'port' => $value['port']);
+            $redisServer[] = array('host' => $value['host'], 'port' => $value['port'], 'password' => (isset($value['password']) ? $value['password'] : ''));
         }
         $this->redis = new \Qii\Cache\Redis\Cluster($redisServer, 128);
     }
@@ -59,7 +59,8 @@ class Redis implements Intf
         try {
             $res = $this->redis->hMset($id, $data);
             if (isset($this->policy['life_time']) && $this->policy['life_time'] > 0) {
-                $this->redis->setTimeout($id, $this->policy['life_time']);
+                //$this->redis->setTimeout($id, $this->policy['life_time']);
+                $this->redis->expire($id, $this->policy['life_time']);
             }
         } catch (\CredisException $e) {
             throw new \Qii\Exceptions\Errors(\Qii::i(-1, $e->getMessage()), __LINE__);
@@ -79,7 +80,8 @@ class Redis implements Intf
         try {
             $res = $this->redis->set($id, $value);
             if (isset($this->policy['life_time']) && $this->policy['life_time'] > 0) {
-                $this->redis->setTimeout($id, $this->policy['life_time']);
+                //$this->redis->setTimeout($id, $this->policy['life_time']);
+                $this->redis->expire($id, $this->policy['life_time']);
             }
         } catch (\CredisException $e) {
             throw new \Qii\Exceptions\Errors(\Qii::i(-1, $e->getMessage()), __LINE__);

+ 25 - 7
src/Driver/Base.php

@@ -40,7 +40,7 @@ class Base
     protected $_query = array(
         "INSERT" => "INSERT INTO %s(%s) VALUES('%s')",
         "REPLACE" => "REPLACE %s (%s) VALUES('%s')",
-        "SELECT" => "SELECT %s FROM `%s` %s",
+        "SELECT" => "SELECT %s FROM %s %s",
         "UPDATE" => "UPDATE %s SET ",
         "DELETE" => "DELETE FROM %s %s",
         "WHERE" => " WHERE %s",
@@ -224,7 +224,7 @@ class Base
         $this->whereCondition = array();
 
         $alias = $this->getTableAlias($table);
-        $this->modelSQL = $sql = sprintf($this->_query['UPDATE'], "`". $alias['name'] ."` ". $alias['alias']) . $set. $where;
+        $this->modelSQL = $sql = sprintf($this->_query['UPDATE'], $alias['name'] . $alias['alias']) . $set. $where;
         return $this->exec($sql);
     }
     /**
@@ -258,9 +258,9 @@ class Base
         $where = count($this->whereCondition) > 0 ? " WHERE ". join(" ", $this->whereCondition) : "";
         $this->whereCondition = array();
 
-        $this->modelSQL = $sql = sprintf($this->_query['DELETE'], $table, $where);
-
-        return $sql;
+        $alias = $this->getTableAlias($table);
+        $this->modelSQL = $sql = sprintf($this->_query['DELETE'], $alias['name'], $where);
+        return $this->exec($sql);
     }
 
     /**
@@ -345,6 +345,7 @@ class Base
         $operator = array("equal" => "%s`%s` = '%s'", "plus" => "%s`%s` = %s`%s`+%s", "minus" => "%s`%s` = %s`%s`-%s", "multiply" => "%s`%s` = %s`%s`*%s", "divide" => "%s`%s` = %s`%s`/%s");
         foreach($set as $key => $val)
         {
+            $val = $this->setQuote($val);
             $alias = $this->getFieldAlias($key);
             $operate = $this->getFieldOperator($alias['name']);
             if($operate['operator'] == '') {
@@ -355,8 +356,8 @@ class Base
             }else{
                 $this->sets[] = sprintf($operator[$operate['operator']], $alias['alias'], $operate['field'], $alias['alias'], $operate['field'], $val);
             }
-
         }
+
         return $this;
     }
 
@@ -830,12 +831,29 @@ class Base
         //去掉table前后的``符号
         $name = str_replace('`', '', $name);
         $aliases = explode(' ', $name);
+        //检查表名中时候含数据库名,有数据表名的时候需要单独处理
+        $hasDatabaseName = false;
+        if(stristr($name, '.')) {
+            $hasDatabaseName = true;
+        }
         if(count($aliases) == 1) {
+            if($hasDatabaseName) {
+                $names = explode(".", $name);
+                $name = $names[0] . ".`". $names[1] . "`";
+            }else{
+                $name = "`". $name ."`";
+            }
             return array('alias' => '', 'name' => $name);
         }
         $res = array();
         $res['alias'] = array_pop($aliases);
         $res['name'] = join(" ", array_slice($aliases, -1));
+        if($hasDatabaseName) {
+            $names = explode(".", $res['name']);
+            $res['name'] = $names[0] . ".`". $names[1] . "`";
+        }else{
+            $res['name'] = "`". $res['name'] ."`";
+        }
         return $res;
     }
     /**
@@ -949,7 +967,7 @@ class Base
             $extraParams = array_slice(func_get_args(), 2);
         }
         $where = array();
-        $operator = array('equal' => "%s`%s` = '%s'",'in' => "%s`%s` in (%s)", 'unequal' => "%s`%s` != '%s'", 'greater' => "%s`%s` > '%s'", 'greaterEqual' => "%s`%s` >= '%s'", 'less' => "%s`%s` < '%s'", 'lessEqual' => "%s`%s` <= '%s'", 'like' => "`%s%s` like '%%%s%%'");
+        $operator = array('equal' => "%s`%s` = '%s'",'in' => "%s`%s` in (%s)", 'unequal' => "%s`%s` != '%s'", 'greater' => "%s`%s` > '%s'", 'greaterEqual' => "%s`%s` >= '%s'", 'less' => "%s`%s` < '%s'", 'lessEqual' => "%s`%s` <= '%s'", 'like' => "%s`%s` like '%%%s%%'");
         $lastIsOperator = false;
         $lastIsValue = null;
         $i = 0;

+ 13 - 11
src/Driver/traitDatabase.php

@@ -73,11 +73,13 @@ trait traitDatabase
     {
         if (!$database) $database = $this->currentDB;
         $sql = "SELECT * from information_schema.COLUMNS where table_name = '" . $table . "' and table_schema = '" . $database . "'";
-        $data = ['fields' => [],
-            'rules' => [
-                'pri' => [], 'required' => []
-            ]
-        ];
+        $data = array(
+            'fields' => array(),
+            'rules' => array(
+                'pri' => array(),
+                'required' => array()
+            )
+        );
 
         $rs = $this->setQuery($sql);
         while ($row = $rs->fetch()) {
@@ -92,24 +94,24 @@ trait traitDatabase
             if ($row['IS_NULLABLE'] == 'NO') {
                 $data['rules']['required'][] = $row['COLUMN_NAME'];
             }
-            if (in_array($row['DATA_TYPE'], ['varchar', 'char'])) {
+            if (in_array($row['DATA_TYPE'], array('varchar', 'char'))) {
                 $data['rules']['maxlength'][$row['COLUMN_NAME']] = $row['CHARACTER_MAXIMUM_LENGTH'];
             }
-            if (in_array($row['DATA_TYPE'], ['mediumtext', 'TINYTEXT', 'text', 'longtext'])) {
+            if (in_array($row['DATA_TYPE'], array('mediumtext', 'TINYTEXT', 'text', 'longtext'))) {
                 $data['rules']['text'][] = $row['COLUMN_NAME'];
             }
-            if (in_array($row['DATA_TYPE'], ['bigint', 'int', 'smallint', 'tinyint', 'integer'])) {
+            if (in_array($row['DATA_TYPE'], array('bigint', 'int', 'smallint', 'tinyint', 'integer'))) {
                 preg_match('/[\d]{1,}/', $row['COLUMN_TYPE'], $matches);
                 $data['rules']['int'][$row['COLUMN_NAME']] = $matches[0];
                 $data['rules']['number'][] = $row['COLUMN_NAME'];
             }
-            if (in_array($row['DATA_TYPE'], ['float', 'double', 'decimal'])) {
+            if (in_array($row['DATA_TYPE'], array('float', 'double', 'decimal'))) {
                 $data['rules']['float'][$row['COLUMN_NAME']] = $this->getValueFromBrackets($row['COLUMN_TYPE']);
             }
-            if (in_array($row['DATA_TYPE'], ['timestamp', 'datatime'])) {
+            if (in_array($row['DATA_TYPE'], array('timestamp', 'datatime'))) {
                 $data['rules']['timestamp'][] = $row['COLUMN_NAME'];
             }
-            if (in_array($row['DATA_TYPE'], ['enum', 'set'])) {
+            if (in_array($row['DATA_TYPE'], array('enum', 'set'))) {
                 $data['rules']['sets'][$row['COLUMN_NAME']] = $this->getValueFromBrackets($row['COLUMN_TYPE']);
             }
             if (isset($row['COLUMN_DEFAULT'])) {

+ 252 - 0
src/Library/GoogleAuthenticator.php

@@ -0,0 +1,252 @@
+<?php
+namespace Qii\Library;
+/**
+ * PHP Class for handling Google Authenticator 2-factor authentication.
+ *
+ * @author Michael Kliewe
+ * @copyright 2012 Michael Kliewe
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ *
+ * @link http://www.phpgangsta.de/
+ */
+class GoogleAuthenticator
+{
+    protected $_codeLength = 6;
+
+    /**
+     * Create new secret.
+     * 16 characters, randomly chosen from the allowed base32 characters.
+     *
+     * @param int $secretLength
+     *
+     * @return string
+     */
+    public function createSecret($secretLength = 16)
+    {
+        $validChars = $this->_getBase32LookupTable();
+
+        // Valid secret lengths are 80 to 640 bits
+        if ($secretLength < 16 || $secretLength > 128) {
+            throw new Exception('Bad secret length');
+        }
+        $secret = '';
+        $rnd = false;
+        if (function_exists('random_bytes')) {
+            $rnd = random_bytes($secretLength);
+        } elseif (function_exists('mcrypt_create_iv')) {
+            $rnd = mcrypt_create_iv($secretLength, MCRYPT_DEV_URANDOM);
+        } elseif (function_exists('openssl_random_pseudo_bytes')) {
+            $rnd = openssl_random_pseudo_bytes($secretLength, $cryptoStrong);
+            if (!$cryptoStrong) {
+                $rnd = false;
+            }
+        }
+        if ($rnd !== false) {
+            for ($i = 0; $i < $secretLength; ++$i) {
+                $secret .= $validChars[ord($rnd[$i]) & 31];
+            }
+        } else {
+            throw new Exception('No source of secure random');
+        }
+
+        return $secret;
+    }
+
+    /**
+     * Calculate the code, with given secret and point in time.
+     *
+     * @param string   $secret
+     * @param int|null $timeSlice
+     *
+     * @return string
+     */
+    public function getCode($secret, $timeSlice = null)
+    {
+        if ($timeSlice === null) {
+            $timeSlice = floor(time() / 30);
+        }
+
+        $secretkey = $this->_base32Decode($secret);
+
+        // Pack time into binary string
+        $time = chr(0).chr(0).chr(0).chr(0).pack('N*', $timeSlice);
+        // Hash it with users secret key
+        $hm = hash_hmac('SHA1', $time, $secretkey, true);
+        // Use last nipple of result as index/offset
+        $offset = ord(substr($hm, -1)) & 0x0F;
+        // grab 4 bytes of the result
+        $hashpart = substr($hm, $offset, 4);
+
+        // Unpak binary value
+        $value = unpack('N', $hashpart);
+        $value = $value[1];
+        // Only 32 bits
+        $value = $value & 0x7FFFFFFF;
+
+        $modulo = pow(10, $this->_codeLength);
+
+        return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT);
+    }
+
+    /**
+     * Get QR-Code URL for image, from google charts.
+     *
+     * @param string $name
+     * @param string $secret
+     * @param string $title
+     * @param array  $params
+     *
+     * @return string
+     */
+    public function getQRCodeGoogleUrl($name, $secret, $title = null, $params = array())
+    {
+        $width = !empty($params['width']) && (int) $params['width'] > 0 ? (int) $params['width'] : 200;
+        $height = !empty($params['height']) && (int) $params['height'] > 0 ? (int) $params['height'] : 200;
+        $level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M';
+
+        $urlencoded = urlencode('otpauth://totp/'.$name.'?secret='.$secret.'');
+        if (isset($title)) {
+            $urlencoded .= urlencode('&issuer='.urlencode($title));
+        }
+
+        return "https://api.qrserver.com/v1/create-qr-code/?data=$urlencoded&size=${width}x${height}&ecc=$level";
+    }
+
+    /**
+     * Check if the code is correct. This will accept codes starting from $discrepancy*30sec ago to $discrepancy*30sec from now.
+     *
+     * @param string   $secret
+     * @param string   $code
+     * @param int      $discrepancy      This is the allowed time drift in 30 second units (8 means 4 minutes before or after)
+     * @param int|null $currentTimeSlice time slice if we want use other that time()
+     *
+     * @return bool
+     */
+    public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = null)
+    {
+        if ($currentTimeSlice === null) {
+            $currentTimeSlice = floor(time() / 30);
+        }
+
+        if (strlen($code) != 6) {
+            return false;
+        }
+
+        for ($i = -$discrepancy; $i <= $discrepancy; ++$i) {
+            $calculatedCode = $this->getCode($secret, $currentTimeSlice + $i);
+            if ($this->timingSafeEquals($calculatedCode, $code)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Set the code length, should be >=6.
+     *
+     * @param int $length
+     *
+     * @return PHPGangsta_GoogleAuthenticator
+     */
+    public function setCodeLength($length)
+    {
+        $this->_codeLength = $length;
+
+        return $this;
+    }
+
+    /**
+     * Helper class to decode base32.
+     *
+     * @param $secret
+     *
+     * @return bool|string
+     */
+    protected function _base32Decode($secret)
+    {
+        if (empty($secret)) {
+            return '';
+        }
+
+        $base32chars = $this->_getBase32LookupTable();
+        $base32charsFlipped = array_flip($base32chars);
+
+        $paddingCharCount = substr_count($secret, $base32chars[32]);
+        $allowedValues = array(6, 4, 3, 1, 0);
+        if (!in_array($paddingCharCount, $allowedValues)) {
+            return false;
+        }
+        for ($i = 0; $i < 4; ++$i) {
+            if ($paddingCharCount == $allowedValues[$i] &&
+                substr($secret, -($allowedValues[$i])) != str_repeat($base32chars[32], $allowedValues[$i])) {
+                return false;
+            }
+        }
+        $secret = str_replace('=', '', $secret);
+        $secret = str_split($secret);
+        $binaryString = '';
+        for ($i = 0; $i < count($secret); $i = $i + 8) {
+            $x = '';
+            if (!in_array($secret[$i], $base32chars)) {
+                return false;
+            }
+            for ($j = 0; $j < 8; ++$j) {
+                $x .= str_pad(base_convert(@$base32charsFlipped[@$secret[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
+            }
+            $eightBits = str_split($x, 8);
+            for ($z = 0; $z < count($eightBits); ++$z) {
+                $binaryString .= (($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48) ? $y : '';
+            }
+        }
+
+        return $binaryString;
+    }
+
+    /**
+     * Get array with all 32 characters for decoding from/encoding to base32.
+     *
+     * @return array
+     */
+    protected function _getBase32LookupTable()
+    {
+        return array(
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', //  7
+            'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
+            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
+            'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
+            '=',  // padding char
+        );
+    }
+
+    /**
+     * A timing safe equals comparison
+     * more info here: http://blog.ircmaxell.com/2014/11/its-all-about-time.html.
+     *
+     * @param string $safeString The internal (safe) value to be checked
+     * @param string $userString The user submitted (unsafe) value
+     *
+     * @return bool True if the two strings are identical
+     */
+    private function timingSafeEquals($safeString, $userString)
+    {
+        if (function_exists('hash_equals')) {
+            return hash_equals($safeString, $userString);
+        }
+        $safeLen = strlen($safeString);
+        $userLen = strlen($userString);
+
+        if ($userLen != $safeLen) {
+            return false;
+        }
+
+        $result = 0;
+
+        for ($i = 0; $i < $userLen; ++$i) {
+            $result |= (ord($safeString[$i]) ^ ord($userString[$i]));
+        }
+
+        // They are only identical strings if $result is exactly 0...
+        return $result === 0;
+    }
+}

+ 2 - 0
src/Library/Upload.php

@@ -233,6 +233,8 @@ class Upload
         'zip' => 'application/zip',
         'epub' => 'application/epub+zip',
         'mobi' => 'application/octet-stream',
+        'flac' => 'application/flac',
+        'ape' => 'application/ape',
     );
     public $size = 0;
     public static $fileHash = array();

+ 4 - 2
src/Qii.php

@@ -32,7 +32,8 @@ define('QII_SPACE', IS_CLI ? ' ' : '&nbsp;');
 require Qii_DIR . DS . 'Autoloader' . DS . 'Import.php';
 \Qii\Autoloader\Import::setFileLoaded(Qii_DIR . DS . 'Autoloader' . DS . 'Import.php');
 
-\Qii\Autoloader\Import::requires(array(Qii_DIR . DS . 'Consts' . DS . 'Config.php',
+\Qii\Autoloader\Import::requires(
+    array(Qii_DIR . DS . 'Consts' . DS . 'Config.php',
         Qii_DIR . DS . 'Functions' . DS . 'Funcs.php',
         Qii_DIR . DS . 'Autoloader' . DS . 'Factory.php',
         Qii_DIR . DS . 'Application.php',
@@ -181,7 +182,8 @@ if (!function_exists('catch_fatal_error')) {
             $message[] = 'Error line : ' . $error['line'] . ' on ' . \Qii\Exceptions\Errors::getLineMessage($error['file'], $error['line']);
             $message[] = 'Error description : ' . $error['message'];
             if (IS_CLI) {
-                return (new \Qii\Response\Cli())->stdout(
+                $cli = new \Qii\Response\Cli();
+                return $cli->stdout(
                     str_replace("&nbsp;"
                         , " "
                         , strip_tags(join(PHP_EOL, preg_replace("/[\n|\r\n]/", PHP_EOL, $message)))

+ 18 - 18
src/Request/Http.php

@@ -9,10 +9,10 @@ final class Http extends Request
     /**
      * __construct
      *
-     * @param string $request_uri
-     * @param string $base_uri
+     * @param string $requestURI
+     * @param string $baseURI
      */
-    public function __construct($request_uri = null, $base_uri = null)
+    public function __construct($requestURI = null, $baseURI = null)
     {
         if (isset($_SERVER['REQUEST_METHOD'])) {
             $this->method = $_SERVER['REQUEST_METHOD'];
@@ -23,12 +23,12 @@ final class Http extends Request
                 $this->method = 'Unknown';
             }
         }
-        if (empty($request_uri)) {
+        if (empty($requestURI)) {
             do {
                 // #ifdef PHP_WIN32
                 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
                     /* check this first so IIS will catch */
-                    if ($request_uri = $this->getServer('HTTP_X_REWRITE_URL')) {
+                    if ($requestURI = $this->getServer('HTTP_X_REWRITE_URL')) {
                         break;
                     }
 
@@ -36,32 +36,32 @@ final class Http extends Request
                     if ($rewrited = (boolean)$this->getServer('IIS_WasUrlRewritten')) {
                         $unencode = $this->getServer('UNENCODED_URL');
                         if ($unencode && is_string($unencode)) {
-                            $request_uri = $unencode;
+                            $requestURI = $unencode;
                         }
                         break;
                     }
                     // #endif
                 }
-                if ($request_uri = $this->getServer('PATH_INFO')) {
+                if ($requestURI = $this->getServer('PATH_INFO')) {
                     break;
                 }
 
-                if ($request_uri = $this->getServer('REQUEST_URI')) {
+                if ($requestURI = $this->getServer('REQUEST_URI')) {
                     /* Http proxy reqs setup request uri with scheme and host [and port] + the url path, only use url path */
-                    if (strstr($request_uri, 'http') == $request_uri) {
-                        $url_info = parse_url($request_uri);
+                    if (strstr($requestURI, 'http') == $requestURI) {
+                        $url_info = parse_url($requestURI);
                         if ($url_info && isset($url_info['path'])) {
-                            $request_uri = $url_info['path'];
+                            $requestURI = $url_info['path'];
                         }
                     } else {
-                        if ($pos = strstr($request_uri, '?')) {
-                            $request_uri = substr($request_uri, 0, strlen($pos) - 1);
+                        if ($pos = strstr($requestURI, '?')) {
+                            $requestURI = substr($requestURI, 0, strlen($pos) - 1);
                         }
                     }
                     break;
                 }
 
-                if ($request_uri = $this->getServer('ORIG_PATH_INFO')) {
+                if ($requestURI = $this->getServer('ORIG_PATH_INFO')) {
                     /* intended do nothing */
                     /*
                     if ($query = $this->getServer('QUERY_STRING')) {
@@ -72,12 +72,12 @@ final class Http extends Request
 
             } while (0);
         }
-        if ($request_uri && is_string($request_uri)) {
-            $request_uri = str_replace('//', '/', $request_uri);
-            $this->uri = $request_uri;
+        if ($requestURI && is_string($requestURI)) {
+            $requestURI = str_replace('//', '/', $requestURI);
+            $this->uri = $requestURI;
 
             // request_set_base_uri
-            $this->_setbaseUri($base_uri, $request_uri);
+            $this->_setBaseUri($baseURI, $requestURI);
         }
         $this->params = array();
         parent::__construct();

+ 1 - 1
src/Request/Url.php

@@ -41,7 +41,7 @@ class Url
     public static function getPathInfo()
     {
         if (PATH_INFO) {
-            return PATH_INFO;
+            return explode("?", PATH_INFO)[0];
         }
         
         $path = pathinfo($_SERVER['SCRIPT_NAME'], PATHINFO_DIRNAME);

+ 31 - 3
src/Request/Url/Base.php

@@ -255,7 +255,7 @@ abstract class Base
      *
      * @param string $key
      */
-    protected function CLIParams($key = '')
+    public function CliParams($key = '')
     {
         $argv = array();
         if (isset($_SERVER['argv'])) $argv = $_SERVER['argv'];
@@ -263,8 +263,19 @@ abstract class Base
         if ($argv && $_SERVER['PHP_SELF'] == $_SERVER['SCRIPT_NAME']) {
             if (count($argv) == 1) return;
             array_shift($argv);
-            $args = (array)$this->parseArgs($argv[0]);
+            $path = $argv[0];
+            if($query = stristr($path, '?')) {
+                $path = str_replace(stristr($path, '?'), '', $path);
+            }
+            $args = (array)$this->parseArgs($path);
             //处理GET或POST方法 数据结构 key1=value1 key2=value2 键和值中间不能有空格
+            if($query && strlen($query) > 1) {
+                $queryArr = explode("&", substr($query, 1));
+                foreach ($queryArr as $value) {
+                    list($index, $val) = explode('=', $value, 2);
+                    $args[$index] = $val;
+                }
+            }
             if ($_SERVER['argc'] > 2) {
                 for ($i = 1; $i < $_SERVER['argc'] - 1; $i++) {
                     list($index, $val) = explode('=', $argv[$i], 2);
@@ -281,6 +292,23 @@ abstract class Base
         return array();
     }
 
+    public function getCliPathArgs() {
+        $argv = array();
+        $args = array();
+        if (isset($_SERVER['argv'])) $argv = $_SERVER['argv'];
+        //修正部分服务器Rewrite 后再加参数不识别的问题(直接进入命令行的模式)
+        if ($argv && $_SERVER['PHP_SELF'] == $_SERVER['SCRIPT_NAME']) {
+            if (count($argv) == 1) return $args;
+            array_shift($argv);
+            $path = $argv[0];
+            if(stristr($path, '?')) {
+                $path = str_replace(stristr($path, '?'), '', $path);
+            }
+            $args = (array)$this->parseArgs($path);
+        }
+        return $args;
+    }
+
     /**
      * 获取参数
      *
@@ -294,7 +322,7 @@ abstract class Base
         if ($this->params != null) return $this->params;
         $this->checkMode($this->_mode);
         //如果是命令行模式
-        if (IS_CLI) return $this->CLIParams($key);
+        if (IS_CLI) return $this->CliParams($key);
 
         if ($this->_mode == 'Normal') {
             if (empty($key)) return $_GET;