0
0
Переглянути джерело

Merge branch 'message_v1' of yanglin/logSystem-advance into master

yanglin 6 роки тому
батько
коміт
8470c4b850
63 змінених файлів з 3165 додано та 3655 видалено
  1. 1 0
      .gitignore
  2. 1 1
      api/config/.gitignore
  3. 31 28
      api/config/main.php
  4. 0 205
      api/controllers/UserController.php
  5. 0 43
      api/models/Goods.php
  6. 26 0
      api/models/User.php
  7. 1 1
      api/modules/v1/controllers/GoodsController.php
  8. 2 0
      api/modules/v1/controllers/SiteController.php
  9. 4 0
      api/web/.htaccess
  10. 7 5
      backend/config/main.php
  11. 26 0
      backend/controllers/BaseController.php
  12. 26 0
      backend/controllers/ErrorController.php
  13. 178 0
      backend/controllers/MessageController.php
  14. 83 0
      backend/controllers/QueueController.php
  15. 23 0
      backend/forms/BaseForm.php
  16. 632 0
      backend/forms/MessageForm.php
  17. 191 0
      backend/forms/QueueForm.php
  18. 1 0
      backend/forms/READ.md
  19. 42 0
      backend/models/Queue.php
  20. 36 0
      backend/models/WorkerScript.php
  21. 4 0
      backend/web/.htaccess
  22. 1 0
      common/config/.gitignore
  23. 0 9
      common/config/db-local.php
  24. 3 2
      common/config/db.php
  25. 26 4
      common/config/main.php
  26. 40 0
      common/helpers/KeyHelper.php
  27. 92 0
      common/logic/Amqp/Cache.php
  28. 38 0
      common/logic/Amqp/Connect.php
  29. 13 0
      common/logic/Amqp/Exception.php
  30. 120 0
      common/logic/Amqp/Message.php
  31. 70 0
      common/logic/Amqp/Queue.php
  32. 5 0
      common/messages/en-US/common.php
  33. 4 0
      common/messages/en-US/errorCode.php
  34. 3 0
      common/messages/zh-CN/common.php
  35. 109 0
      common/messages/zh-CN/errorCode.php
  36. 618 0
      components/Curl.php
  37. 73 0
      components/ErrorHandler.php
  38. 43 0
      components/Exception.php
  39. 108 0
      components/RabbitMQ/PhpClient.php
  40. 64 0
      components/service/Amqp.php
  41. 47 0
      components/service/AmqpConfig.php
  42. 2 1
      composer.json
  43. 0 3342
      composer.lock
  44. 24 0
      console/controllers/BaseController.php
  45. 105 0
      console/controllers/MainController.php
  46. 141 0
      console/controllers/WorkerMsgController.php
  47. 2 0
      console/migrations/README.md
  48. 13 0
      environments/dev/api/config/main-local.php
  49. 3 0
      environments/dev/api/config/params-local.php
  50. 18 0
      environments/dev/api/web/index-test.php
  51. 17 0
      environments/dev/api/web/index.php
  52. 2 0
      environments/dev/api/web/robots.txt
  53. 1 0
      environments/dev/backend/config/main-local.php
  54. 0 7
      environments/dev/common/config/main-local.php
  55. 3 0
      environments/dev/console/config/main-local.php
  56. 1 0
      environments/dev/frontend/config/main-local.php
  57. 6 0
      environments/index.php
  58. 9 0
      environments/prod/api/config/main-local.php
  59. 3 0
      environments/prod/api/config/params-local.php
  60. 17 0
      environments/prod/api/web/index.php
  61. 2 0
      environments/prod/api/web/robots.txt
  62. 0 7
      environments/prod/common/config/main-local.php
  63. 4 0
      frontend/web/.htaccess

+ 1 - 0
.gitignore

@@ -24,6 +24,7 @@ Thumbs.db
 
 # composer itself is not needed
 composer.phar
+composer.lock
 
 # Mac DS_Store Files
 .DS_Store

+ 1 - 1
api/config/.gitignore

@@ -1,3 +1,3 @@
 main-local.php
 params-local.php
-test-local.php
+test-local.php

+ 31 - 28
api/config/main.php

@@ -13,7 +13,10 @@ return [
     'modules' => [
         'v1' => [
             'class' => 'api\modules\v1\Module'
-        ]
+        ],
+		'v2' => [
+			'class' => 'api\modules\v2\Module'
+		],
     ],
     'controllerNamespace' => 'api\controllers',
     'components' => [
@@ -33,37 +36,37 @@ return [
             ],
         ],
         'request' => [
-            'class' => '\yii\web\Request',
-            'enableCookieValidation' => false,
-            'parsers' => [
-                'application/json' => 'yii\web\JsonParser',
-            ],
+            //'class' => '\yii\web\Request',
+            //'enableCookieValidation' => false,
+            //'parsers' => [
+            //    'application/json' => 'yii\web\JsonParser',
+            //],
+			'baseUrl' => '/api',
             'cookieValidationKey' => 'O1d232trde1xww-M97_7QvwPo-5QGdkLMp#@#@',
         ],
-        'errorHandler' => [
+        /*'errorHandler' => [
             'errorAction' => 'site/error',
-        ],
+        ],*/
 
-        'urlManager' =>  [
-            'class' => 'yii\web\UrlManager',
-            'enablePrettyUrl' => true,
-            'enableStrictParsing' => true,
-            'showScriptName' => false,
-            'rules' => [
-                '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
-                '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
-                '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
-//                '' => 'site/index',
-//                ['class' => 'yii\rest\UrlRule', 'controller' => 'customer/api',
-//                    'pluralize' => false,
-//                ],
-//                #  定义方法: public function actionSearch($id);   <id> 就是search方法传入的参数
-//                #  http://10.10.10.252:599/v1/wishorder/2015-08-11+12:12:12/2015-09-11+12:12:12?access-token=pBJi3hyFsLsTuvUM9paFpWjYRatn3qwS
-//                #  分页:http://10.10.10.252:599/v1/wishorder/2015-08-11+12:12:12/2015-09-11+12:12:12?page=2&access-token=pBJi3hyFsLsTuvUM9paFpWjYRatn3qwS
-//                'GET v1/wishorder/<begin_datetime>/<end_datetime>' => 'v1/wishorder/viewbydate',
-//                'GET v1/ebayorder/<begin_datetime>/<end_datetime>' => 'v1/ebayorder/viewbydate',
-            ]
-        ],
+		'urlManager' => [
+			'enablePrettyUrl' => true,
+			'enableStrictParsing' => true,
+			'showScriptName' => false,
+			'rules' => [
+                [
+                     'class' => 'yii\rest\UrlRule',
+                     'controller' => [
+                         'v1/site'
+                     ]
+                 ],
+                 [
+                     'class' => 'yii\rest\UrlRule',
+                     'controller' => [
+                         'v2/site'
+                     ]
+                 ]
+			],
+		],
 
         'db' =>   require __DIR__ . '/../../common/config/db.php'
     ],

+ 0 - 205
api/controllers/UserController.php

@@ -1,205 +0,0 @@
-<?php
-namespace common\models;
-
-use Yii;
-use yii\base\NotSupportedException;
-use yii\behaviors\TimestampBehavior;
-use yii\db\ActiveRecord;
-use yii\web\IdentityInterface;
-
-/**
- * User model
- *
- * @property integer $id
- * @property string $username
- * @property string $password_hash
- * @property string $password_reset_token
- * @property string $email
- * @property string $auth_key
- * @property integer $status
- * @property integer $created_at
- * @property integer $updated_at
- * @property integer  $curr_login_ip
- * @property integer $curr_login_at
- * @property string $password write-only password
- */
-
-
-
-class User extends ActiveRecord implements IdentityInterface
-{
-
-    public $curr_login_at;
-    const STATUS_DELETED = 0;
-    const STATUS_ACTIVE = 10;
-
-
-    /**
-     * @inheritdoc
-     */
-    public static function tableName()
-    {
-        return '{{%user}}';
-    }
-
-    /**
-     * @inheritdoc
-     */
-    public function behaviors()
-    {
-        return [
-            TimestampBehavior::className(),
-        ];
-    }
-
-    # 生成access_token
-    public function generateAccessToken()
-    {
-        $this->access_token = Yii::$app->security->generateRandomString();
-    }
-
-    /**
-     * @inheritdoc
-     */
-    public function rules()
-    {
-        return [
-            ['status', 'default', 'value' => self::STATUS_ACTIVE],
-            ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
-        ];
-    }
-
-    /**
-     * @inheritdoc
-     */
-    public static function findIdentity($id)
-    {
-        return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
-    }
-
-
-
-
-    public static function findIdentityByAccessToken($token, $type = null)
-    {
-
-        return static::findOne(['access_token' => $token]);
-    }
-
-    /**
-     * Finds user by username
-     *
-     * @param string $username
-     * @return static|null
-     */
-    public static function findByUsername($username)
-    {
-        return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);
-    }
-
-    /**
-     * Finds user by password reset token
-     *
-     * @param string $token password reset token
-     * @return static|null
-     */
-    public static function findByPasswordResetToken($token)
-    {
-        if (!static::isPasswordResetTokenValid($token)) {
-            return null;
-        }
-
-        return static::findOne([
-            'password_reset_token' => $token,
-            'status' => self::STATUS_ACTIVE,
-        ]);
-    }
-
-    /**
-     * Finds out if password reset token is valid
-     *
-     * @param string $token password reset token
-     * @return bool
-     */
-    public static function isPasswordResetTokenValid($token)
-    {
-        if (empty($token)) {
-            return false;
-        }
-
-        $timestamp = (int) substr($token, strrpos($token, '_') + 1);
-        $expire = Yii::$app->params['user.passwordResetTokenExpire'];
-        return $timestamp + $expire >= time();
-    }
-
-    /**
-     * @inheritdoc
-     */
-    public function getId()
-    {
-        return $this->getPrimaryKey();
-    }
-
-    /**
-     * @inheritdoc
-     */
-    public function getAuthKey()
-    {
-        return $this->auth_key;
-    }
-
-    /**
-     * @inheritdoc
-     */
-    public function validateAuthKey($authKey)
-    {
-        return $this->getAuthKey() === $authKey;
-    }
-
-    /**
-     * Validates password
-     *
-     * @param string $password password to validate
-     * @return bool if password provided is valid for current user
-     */
-    public function validatePassword($password)
-    {
-
-
-        return Yii::$app->security->validatePassword($password, $this->password_hash);
-    }
-
-    /**
-     * Generates password hash from password and sets it to the model
-     *
-     * @param string $password
-     */
-    public function setPassword($password)
-    {
-        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
-    }
-
-    /**
-     * Generates "remember me" authentication key
-     */
-    public function generateAuthKey()
-    {
-        $this->auth_key = Yii::$app->security->generateRandomString();
-    }
-
-    /**
-     * Generates new password reset token
-     */
-    public function generatePasswordResetToken()
-    {
-        $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
-    }
-
-    /**
-     * Removes password reset token
-     */
-    public function removePasswordResetToken()
-    {
-        $this->password_reset_token = null;
-    }
-}

+ 0 - 43
api/models/Goods.php

@@ -1,43 +0,0 @@
-<?php
-
-namespace api\models;
-
-use Yii;
-
-/**
- * This is the model class for table "goods".
- *
- * @property int $id
- * @property string $name
- */
-class Goods extends \yii\db\ActiveRecord
-{
-    /**
-     * @inheritdoc
-     */
-    public static function tableName()
-    {
-        return 'goods';
-    }
-
-    /**
-     * @inheritdoc
-     */
-    public function rules()
-    {
-        return [
-            [['name'], 'string', 'max' => 100],
-        ];
-    }
-
-    /**
-     * @inheritdoc
-     */
-    public function attributeLabels()
-    {
-        return [
-            'id' => 'ID',
-            'name' => 'Name',
-        ];
-    }
-}

+ 26 - 0
api/models/User.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace api\models;
+
+use Yii;
+
+class User extends \yii\db\ActiveRecord
+{
+    /**
+     * @inheritdoc
+     */
+    public static function tableName()
+    {
+        return 'user';
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function rules()
+    {
+        return [
+            [['name'], 'string', 'max' => 100],
+        ];
+    }
+}

+ 1 - 1
api/modules/v1/controllers/GoodsController.php

@@ -6,7 +6,7 @@ use yii\rest\ActiveController;
 
 class GoodsController extends ActiveController
 {
-    public $modelClass = 'api\models\Goods';
+    public $modelClass = 'api\models\User';
 
 
     public function actionIndex()

+ 2 - 0
api/modules/v1/controllers/SiteController.php

@@ -8,6 +8,8 @@ use yii\rest\Controller;
  */
 class SiteController extends ActiveController
 {
+	public $modelClass = 'api\models\user';
+
     public function actionIndex()
     {
         \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

+ 4 - 0
api/web/.htaccess

@@ -0,0 +1,4 @@
+RewriteEngine On
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteRule . index.php

+ 7 - 5
backend/config/main.php

@@ -14,6 +14,7 @@ return [
     'modules' => [],
     'components' => [
         'request' => [
+			'baseUrl' => '',
             'csrfParam' => '_csrf-backend',
         ],
         'user' => [
@@ -34,9 +35,10 @@ return [
                 ],
             ],
         ],
-        'errorHandler' => [
-            'errorAction' => 'site/error',
-        ],
+		'errorHandler' => [
+			'class' => 'components\ErrorHandler',
+			'errorAction' => 'site/error',
+		],
         'db' =>   require __DIR__ . '/../../common/config/db.php',
 
         'urlManager' => [
@@ -44,8 +46,8 @@ return [
             'enableStrictParsing' => false,  //不启用严格解析
             'showScriptName' => false,   //隐藏index.php
             'rules' => [
-                '<module:\w+>/<controller:\w+>/<id:\d+>' => '<module>/<controller>/view',
-                '<controller:\w+>/<id:\d+>' => '<controller>/view',
+                /*'<module:\w+>/<controller:\w+>/<id:\d+>' => '<module>/<controller>/view',
+                '<controller:\w+>/<id:\d+>' => '<controller>/view',*/
             ],
         ]
     ],

+ 26 - 0
backend/controllers/BaseController.php

@@ -0,0 +1,26 @@
+<?php
+namespace backend\controllers;
+
+use yii\web\Controller;
+
+/**
+ * Class BaseController
+ * @package backend\controllers
+ */
+class BaseController extends Controller
+{
+	public function init()
+	{
+		\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
+		parent::init();
+	}
+
+	public function beforeAction($action)
+	{
+		//todo
+		/*if (Yii::$app->user->isGuest) {
+
+		}*/
+		return true;
+	}
+}

+ 26 - 0
backend/controllers/ErrorController.php

@@ -0,0 +1,26 @@
+<?php
+namespace backend\controllers;
+
+/**
+ * 错误控制器
+ * Class ErrorController
+ * @package backend\controllers
+ */
+class ErrorController extends BaseController
+{
+	public $layout = false;
+
+	/**
+	 * 动作设置
+	 * @author: libingke
+	 * @return array
+	 */
+	public function actions()
+	{
+		return [
+			'error' => [
+				'class' => 'yii\web\ErrorAction',
+			]
+		];
+	}
+}

+ 178 - 0
backend/controllers/MessageController.php

@@ -0,0 +1,178 @@
+<?php
+namespace backend\controllers;
+
+use backend\forms\MessageForm;
+use common\helpers\KeyHelper;
+use common\logic\Amqp\Cache;
+use components\Exception;
+use components\service\AmqpConfig;
+use Yii;
+
+class MessageController extends BaseController
+{
+	/**
+	 * [查询回执信息]
+	 * @author: libingke
+	 * @param $query
+	 * @param $queue
+	 * @return bool
+	 * @throws Exception
+	 */
+	public function actionQueryReceipt($query, $queue)
+	{
+		if (is_string($query) && is_string($query)) {
+			$statusKey = KeyHelper::getMessageStatusKey($query, $queue);
+			$resultKey = KeyHelper::getMessageResultKey($query, $queue);
+			$status = Yii::$app->redis->get($statusKey);
+
+			if ($status !== false) {
+				$mark = AmqpConfig::getMarkById($status);//状态码 => 提示信息
+
+				if (Cache::STATUS_HAND_OK == $status) {
+					return json_decode(Yii::$app->redis->get($resultKey), true);//直接返回数据
+
+				} else {
+					throw new Exception(2101, $mark);//非正常时回执
+				}
+
+			} else {
+				throw new Exception(2102);//无效
+			}
+
+		} else {
+			throw new Exception(2102);//无效
+		}
+	}
+
+	/**
+	 * 发送消息
+	 * @author: libingke
+	 * @return array
+	 * @throws Exception
+	 */
+	public function actionSend()
+	{
+		$model = new MessageForm();
+		$model->setScenario('send');
+		$model->load(['MessageForm' => Yii::$app->request->get()]);
+
+		$data = [];
+		if ($model->validate()) {
+			$data = $model->sendMessageV1_1();
+		} else {
+			$model->handleError();//处理验证失败
+		}
+
+		return [
+			'code' => 200,
+			'message' => Yii::t('error', 200),
+			'data' => $data
+		];
+	}
+
+	/**
+	 * 批量发送消息
+	 * @author: libingke
+	 * @return array
+	 */
+	public function actionBatchSend()
+	{
+		$model = new MessageForm();
+		$model->setScenario('batch_send');
+		$model->load(['MessageForm' => Yii::$app->request->get()]);
+
+		$data = [];
+		if ($model->validate()) {
+			$data = $model->batchSendMessage();
+		} else {
+			$model->handleError();
+		}
+
+		return [
+			'code' => 200,
+			'message' => Yii::t('error', 200),
+			'data' => $data
+		];
+	}
+
+	/**
+	 * 获取队列消息列表
+	 * @author: libingke
+	 */
+	public function actionList()
+	{
+		$model = new MessageForm();
+		$model->setScenario('message_list');
+		$model->load(['MessageForm' => Yii::$app->request->get()]);
+
+		$data = [];
+		if ($model->validate()) {
+			$data = $model->getMessageList();
+		} else {
+			$model->handleError();
+		}
+
+		return [
+			'code' => 200,
+			'message' => Yii::t('error', 200),
+			'data' => $data
+		];
+	}
+
+	/**
+	 * 消费消息
+	 * @author: libingke
+	 */
+	public function actionConsume()
+	{
+		$model = new MessageForm();
+		$model->setScenario('consume');
+		$model->load(['MessageForm' => Yii::$app->request->get()]);
+
+		$data = [];
+		if ($model->validate()) {
+			$data = $model->consumeMessage();
+		} else {
+			$model->handleError();
+		}
+
+		return [
+			'code' => 200,
+			'message' => Yii::t('error', 200),
+			'data' => $data
+		];
+	}
+
+	/**
+	 * 删除消息
+	 * @author: libingke
+	 */
+    public function actionDelete()
+    {
+
+    }
+
+	/**
+	 * 清空消息
+	 * @author: libingke
+	 */
+	public function actionPurge()
+	{
+		$model = new MessageForm();
+		$model->setScenario('purge');
+		$model->load(['MessageForm' => Yii::$app->request->get()]);
+
+		$data = [];
+		if ($model->validate()) {
+			$data = $model->purge();
+		} else {
+			$model->handleError();
+		}
+
+		return [
+			'code' => 200,
+			'message' => Yii::t('error', 200),
+			'data' => $data
+		];
+	}
+}

+ 83 - 0
backend/controllers/QueueController.php

@@ -0,0 +1,83 @@
+<?php
+namespace backend\controllers;
+
+use backend\forms\QueueForm;
+use components\Exception;
+use Yii;
+
+class QueueController extends BaseController
+{
+	/**
+	 * [创建队列]
+	 * @author: libingke
+	 * @return array
+	 * @throws Exception
+	 */
+	public function actionCreate()
+	{
+		if (!Yii::$app->request->isPost)
+			throw new Exception('1001');
+
+		$model = new QueueForm();
+		$model->setScenario('create_queue');
+		$model->load(['QueueForm' => Yii::$app->request->post()]);
+
+		$data = [];
+		if ($model->validate()) {
+			$data = $model->createQueue();
+		} else {
+			$model->handleError();//处理验证失败
+		}
+
+		return [
+			'code' => 200,
+			'message' => Yii::t('error', 200),
+			'data' => $data
+		];
+	}
+
+	/**
+	 * 删除队列
+	 * @author: libingke
+	 * @return array
+	 * @throws Exception
+	 */
+	public function actionDelete()
+	{
+		if (!Yii::$app->request->isPost)
+			throw new Exception('1001');
+
+		$model = new QueueForm();
+		$model->setScenario('delete_queue');
+		$model->load(['QueueForm' => Yii::$app->request->post()]);
+
+		$data = [];
+		if ($model->validate()) {
+			$data = $model->deleteQueue();
+		} else {
+			$model->handleError();
+		}
+
+		return [
+			'code' => 200,
+			'message' => Yii::t('error', 200),
+			'data' => $data
+		];
+	}
+
+
+	/**
+	 * 获取队列列表
+	 * @author: libingke
+	 */
+	public function actionList()
+	{
+		$model = new QueueForm();
+		$data = $model->getQueueList();
+		return [
+			'code' => 200,
+			'message' => Yii::t('error', 200),
+			'data' => $data
+		];
+	}
+}

+ 23 - 0
backend/forms/BaseForm.php

@@ -0,0 +1,23 @@
+<?php
+namespace backend\forms;
+
+use yii\base\Model;
+use components\Exception;
+
+/**
+ * Class BaseForm
+ * @package backend\forms
+ */
+class BaseForm extends Model
+{
+	public function handleError()
+	{
+		$errors = $this->getFirstErrors();
+		$result = reset($errors);
+		if (is_numeric($result)) {
+			throw new Exception($result, \Yii::t('error', $result));
+		} else {
+			throw new Exception(1003, $result);
+		}
+	}
+}

+ 632 - 0
backend/forms/MessageForm.php

@@ -0,0 +1,632 @@
+<?php
+
+namespace backend\forms;
+
+use components\service\AmqpConfig;
+use PhpAmqpLib\Exception\AMQPProtocolChannelException;
+use common\helpers\KeyHelper;
+use common\logic\Amqp\Cache;
+use components\Curl;
+use components\Exception;
+use PhpAmqpLib\Message\AMQPMessage;
+use yii\helpers\ArrayHelper;
+use Yii;
+
+class MessageForm extends BaseForm
+{
+	/* send */
+	public $queue;
+
+	public $message;
+
+
+	/* message_list */
+	public $name;
+
+	/**
+	 * @var integer 数量
+	 */
+	public $count;
+
+	/**
+	 * @var bool 是否重新排序
+	 */
+	public $requeue;
+
+	/**
+	 * @var string 编码
+	 */
+	public $encoding;
+
+	/**
+	 * @var string 消费id
+	 */
+	public $mid;
+
+	/**
+	 * @var string 消费类型
+	 */
+	public $type;
+
+	/**
+	 * @var bool 是否空消费
+	 */
+	public $do_nothing = false;
+
+	/**
+	 * @var bool 自动应答
+	 */
+	public $ack = false;
+
+
+	/**
+	 * @var bool
+	 */
+	private $_stop = false;
+
+
+	/**
+	 * @var string
+	 */
+	private $_mid;
+
+	/**
+	 * @var string
+	 */
+	private $_body;
+
+	/**
+	 * @var AMQPMessage
+	 */
+	private $_message;
+
+	/**
+	 * @var array
+	 */
+	private $_rows;
+
+	/**
+	 * @var array
+	 */
+	private $_result;
+
+	const TYPE_MID	 = 'mid';//消费某条
+	const TYPE_COUNT = 'count';//(从第一条开始) 消费条数
+	const TYPE_MC	 = 'mid_count';//(从某条开始) 消费条数
+
+	public function rules()
+	{
+		return [
+			/* 发送消息 */
+			[['queue'], 'trim', 'on' => ['send', 'batch_send']],
+			[['queue', 'message'], 'required', 'on' => ['send', 'batch_send']],
+			['message', 'validateMessage', 'on' => ['send', 'batch_send']],
+
+			/* 获取消息列表 */
+			[['name'], 'trim', 'on' => ['message_list', 'purge', 'consume']],
+			[['name'], 'required', 'on' => ['message_list', 'purge']],
+			['count', 'integer', 'min' => 1, 'max' => 1000, 'message' => 2012,
+				'tooSmall' => 2013, 'tooBig' => 2014, 'on' => ['message_list']],
+			['count', 'default', 'value' => 20, 'on' => ['message_list']],
+			['requeue', 'boolean', 'message' => 2010, 'on' => ['message_list']],
+			['requeue', 'default', 'value' => true, 'on' => ['message_list']],
+			['encoding', 'in', 'range' => ['auto', 'base64'], 'message' => 2011, 'on' => ['message_list']],
+			['encoding', 'default', 'value' => 'auto', 'on' => ['message_list']],
+
+			/* 消费 */
+			[['type', 'name'], 'required', 'on' => ['consume']],
+			['type', 'in', 'range' => [static::TYPE_MID, static::TYPE_COUNT, static::TYPE_MC], 'on' => 'consume'],
+			['type', 'validateType', 'on' => 'consume'],
+			['mid', 'string', 'on' => 'consume'],
+			['count', 'integer', 'min' => 1, 'max' => 65000, 'message' => 2012,
+				'tooSmall' => 2013, 'on' => ['consume']],
+			['do_nothing', 'default', 'value' => false, 'on' => 'consume'],
+			['do_nothing', 'boolean',  'on' => 'consume'],
+			['ack', 'default', 'value' => false, 'on' => 'consume'],
+			['ack', 'boolean',  'on' => 'consume'],
+		];
+	}
+
+	public function validateMessage($attribute)
+	{
+		if (!$this->$attribute)
+			throw new Exception(2001);
+
+		if (!is_array($this->$attribute))
+			throw new Exception(2002, "{$attribute} 必须是数组");
+	}
+
+	public function validateType($attribute)
+	{
+		if ($this->$attribute == static::TYPE_MC) {
+			if ($this->mid == null)
+				throw new Exception(2016);
+			if ($this->count == null)
+				throw new Exception(2017);
+
+		} else {
+			if ($this->{$this->$attribute} == null)
+				throw new Exception(2016, $this->$attribute . " 不能为空");
+		}
+	}
+
+	/**
+	 * [连接AMQP]
+	 * @author: libingke
+	 * @return \PhpAmqpLib\Connection\AMQPStreamConnection
+	 */
+	protected function getConnect()
+	{
+		return new \PhpAmqpLib\Connection\AMQPStreamConnection(
+			Yii::$app->Amqp->host,
+			Yii::$app->Amqp->port,
+			Yii::$app->Amqp->user,
+			Yii::$app->Amqp->pass,
+			Yii::$app->Amqp->vhost
+		);
+	}
+
+	/**
+	 * [发送消息]
+	 * @author: libingke
+	 * @return array
+	 * @throws Exception
+	 * @version 1.0
+	 */
+	public function sendMessage()
+	{
+		$body = call_user_func_array([$this, '_messageBody'], [$this->attributes]);
+		$mid = KeyHelper::getUniqueId('message_send');
+		$properties = [
+			'content_type' => 'text/plain',
+			'message_id' => $mid,
+			'correlation_id' => $mid,
+			'consumer_tag' => $mid
+		];
+
+		$data = [];
+		$e_name = 'message.default';
+		$k_route = 'route.default';
+		$q_name = $this->queue;
+
+		$connect  = Yii::$app->Amqp->AMQPConnection();
+		$channel  = new \AMQPChannel($connect);
+		$exchange = new \AMQPExchange($channel);
+		$exchange->setName($e_name);
+		$exchange->setType(AMQP_EX_TYPE_DIRECT);
+		$exchange->setFlags(AMQP_DURABLE);//持久化
+		$exchange->declareExchange();//声明交换机
+
+		$queue = new \AMQPQueue($channel);
+		$queue->setName($q_name);
+		$queue->declareQueue(); //声明队列
+		$queue->bind($e_name, $k_route);
+		$r = $exchange->publish($body, $k_route, AMQP_NOPARAM, $properties);
+		if ($r == true) {
+			$data['message_total'] = $queue->declareQueue();
+			$data['queue_name'] = $this->queue;
+			$data['message_new'] = [
+				'mid' => $mid,
+				'body' => $body
+			];
+
+			if ($data['message_total'] > 1) {
+				$data['message_first'] = [
+					'mid' => $queue->get()->getMessageId(),
+					'body' => $queue->get()->getBody()
+				];
+			}
+
+			Cache::setData(
+				'queue:mid:'.$mid,
+				Cache::STATUS_SEND_OK
+			);
+		} else {
+			throw new Exception(2103);
+		}
+
+		return $data;
+	}
+
+	/**
+	 * [发送消息]
+	 * @author: libingke
+	 * @return array
+	 * @throws Exception
+	 * @version 1.1
+	 */
+	public function sendMessageV1_1()
+	{
+		try {
+			//connect
+			$connect = $this->getConnect();
+			$channel = $connect->channel();
+			$this->_handleMessage($this->message);
+			//预声明
+			$channel->queue_declare($this->queue,
+				false, true, false, false);
+			$channel->basic_publish($this->_message, '', $this->queue);
+			//获取返回结果
+			list($q_name, $message_count, ) = $channel->queue_declare($this->queue,
+				false, true, false, false);
+
+			$data = [
+				'message_total' => $message_count,
+				'queue_name' => $q_name,
+				'message_add' => [
+					'mid' => $this->_mid,
+					'body' => $this->_body
+				]
+			];
+			if (($get = $channel->basic_get($q_name)) !== null) {
+				$data['basic_get'] = [
+					'mid' => $get->get('message_id'),
+					'body' => $get->body
+				];
+			}
+			$channel->close();
+			$connect->close();
+
+			$statusKey = KeyHelper::getMessageStatusKey($this->_mid, $q_name);
+			Yii::$app->redis->set($statusKey, AmqpConfig::STATUS_HAND_OK);
+
+			return $data;
+
+		} catch (\Exception $e) {
+			throw new Exception(1000, $e->getMessage());
+		}
+	}
+
+	/**
+	 * [构造消息体]
+	 * @author: libingke
+	 * @param $data
+	 */
+	private function _handleMessage($data)
+	{
+		$this->_mid = KeyHelper::getUniqueId('message_send');
+		$this->_body = call_user_func_array([$this, '_messageBody'], [$data]);
+		$properties = [
+			'message_id' 	=> $this->_mid,
+			'correlation_id'=> $this->_mid,
+			'consumer_tag'	=> $this->_mid
+		];
+		$this->_message = new AMQPMessage($this->_body, $properties);
+	}
+
+	private function _messageBody($data)
+	{
+		return json_encode($data);
+	}
+
+	/**
+	 * [批量发送消息]
+	 * @author: libingke
+	 * @return array
+	 * @throws Exception
+	 */
+	public function batchSendMessage()
+	{
+		try {
+			//connect
+			$connect = $this->getConnect();
+			$channel = $connect->channel();
+			//预声明
+			$channel->queue_declare($this->queue,
+				false, true, false, false);
+			//batch_basic_publish todo
+			foreach ($this->message as $k => $v) {
+				$this->_handleMessage($v);
+				$this->_rows[] = [
+					'mid' => $this->_mid,
+					'body' => $this->_body
+				];
+				$channel->batch_basic_publish($this->_message, '', $this->queue);
+
+				$statusKey = KeyHelper::getMessageStatusKey($this->_mid, $this->queue);
+				Yii::$app->redis->set($statusKey, AmqpConfig::STATUS_HAND_OK);
+			}
+			$channel->publish_batch();
+
+			//获取返回结果
+			list($q_name, $message_count, ) = $channel->queue_declare($this->queue,
+				false, true, false, false);
+
+			$data = [
+				'message_total' => $message_count,
+				'queue_name' => $q_name,
+				'add_count' => count($this->_rows),
+				'add_rows' => $this->_rows
+			];
+			if (($get = $channel->basic_get($q_name)) !== null) {
+				$data['basic_get'] = [
+					'mid' => $get->get('message_id'),
+					'body' => $get->body
+				];
+			}
+			$channel->close();
+			$connect->close();
+
+			return $data;
+
+		} catch (\Exception $e) {
+			throw new Exception(1000, $e->getMessage());
+		}
+	}
+
+	/**
+	 * [获取消息列表]
+	 * @author: libingke
+	 */
+	public function getMessageList()
+	{
+		/* api错误码 */
+		$badCode = 2000;
+		/* 登录验证 */
+		$authStr = Yii::$app->Amqp->getConfig('user') . ':' . Yii::$app->Amqp->getConfig('pass');
+		/* URL */
+		$vhost = urlencode(Yii::$app->Amqp->getConfig('vhost'));
+		$url = Yii::$app->Amqp->getConfig('host') . ':' . Yii::$app->Amqp->getConfig('api_port') .
+			"/api/queues/{$vhost}/" . $this->name . "/get";
+		$postParams = [
+			'name' => $this->name,
+			'count' => $this->count,
+			'encoding' => $this->encoding,
+			'requeue' => $this->requeue,
+			'truncate' => "50000",
+			'vhost' => '/',
+		];
+
+		$curl = new Curl();
+		$curl->setOption(CURLOPT_USERPWD, $authStr);
+		$curl->setRawPostData(json_encode($postParams));
+		$result = json_decode($curl->post($url), true);
+		if ($curl->responseCode != 200)
+			throw new Exception($badCode);
+		if ($curl->errorText)
+			throw new Exception($badCode, $curl->errorText);
+		if (isset($result['error']) && is_string($result['error']))
+			throw new Exception($badCode, $result['error']);
+
+		ArrayHelper::multisort($result,'message_count',SORT_ASC);
+		//print_r($result);exit();
+		$rows = [];
+		foreach ($result as $k => $v) {
+			$rows[$k]['before_count']	= $v['message_count'];
+			$rows[$k]['payload']			= $v['payload'];
+			$rows[$k]['payload_encoding']= $v['payload_encoding'];
+			$rows[$k]['message_id']		= $v['properties']['message_id'];
+		}
+		unset($result);
+
+		return ['count' => count($rows), 'rows' => $rows];
+	}
+
+	/**
+	 * [空处理]
+	 */
+	private function _consumeEmpty($mid, $body, $ack, $error, $stop = false)
+	{
+		$this->_stop = $stop;
+		$this->_result[] = [
+			'mid' => $mid,
+			'result' => 'success: do nothing!',
+			'ack' => $ack,
+			'error' => $error
+		];
+	}
+
+	/**
+	 * [处理逻辑1]
+	 * @author: libingke
+	 */
+	private function _consumeLogin($mid, $body, $ack, $error, $stop = false)
+	{
+		$this->_stop = $stop;
+		$this->_result[] = [
+			'mid' => $mid,
+			'result' => '已处理',
+			'ack' => $ack,
+			'error' => $error
+		];
+	}
+
+	/**
+	 * [消费某条消息]
+	 * @author: libingke
+	 * @param $mid
+	 * @return array
+	 * @throws Exception
+	 */
+	protected function consumeByMid($mid)
+	{
+		$q_name = $this->name;
+
+		//选择执行回调
+		if ($this->do_nothing != true) {
+			$function = '_consume' . ucfirst($q_name);
+			if (!method_exists($this, $function) || !is_callable(array($this, $function)))
+				throw new Exception(2015);
+		} else {
+			//if do nothing handle empty
+			$function = '_consumeEmpty';
+		}
+
+		$connect = $this->getConnect();
+		$channel = $connect->channel();
+		$channel->queue_declare($q_name,
+			false, true, false, false);
+		list(, $count, ) = $channel->queue_declare($q_name,
+			false, true, false, false);
+		$callback = function ($msg) use($function, $mid, $q_name) {
+			try {
+				$message_id = $msg->get('message_id');
+				$ack = $this->ack == true ? true : false;//是否应答
+				if ($mid == $message_id) {
+					call_user_func_array(
+						[$this, $function],
+						[$message_id, $msg->body, $ack, '',	true]
+					);
+
+					$statusKey = KeyHelper::getMessageStatusKey($message_id, $q_name);
+					if ($ack === true) {
+						$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
+						Yii::$app->redis->set($statusKey, AmqpConfig::STATUS_HAND_OK);
+					} else {
+						Yii::$app->redis->set($statusKey, AmqpConfig::STATUS_NO_ACK);
+					}
+				}
+			} catch (\Exception $e) {
+				//$e->getMessage();
+			}
+		};
+
+		try {
+			$channel->basic_qos(0, $count, null);
+			$channel->basic_consume($q_name,
+				'', false, false, false, false, $callback);
+
+			$i = 0;
+			while (count($channel->callbacks)) {
+				$i ++;
+				if ($i > $count || $this->_stop == true)
+					break;
+
+				$channel->wait();
+			}
+
+		} catch (\Exception $e) {
+			throw new Exception(2104, $e->getMessage());
+		}
+
+		$channel->close();
+		$connect->close();
+
+		if ($this->_result == null)
+			throw new Exception(2102);
+
+		return $this->_result;
+	}
+
+	/**
+	 * [根据数量消费]
+	 * @author: libingke
+	 * @param string | int $startPos 开始位置
+	 * @param int $count 数量
+	 */
+	protected function consumeByCount($count)
+	{
+		$q_name = $this->name;
+
+		//选择执行回调
+		if ($this->do_nothing != true) {
+			$function = '_consume' . ucfirst($q_name);
+			if (!method_exists($this, $function) || !is_callable(array($this, $function)))
+				throw new Exception(2015);
+		} else {
+			//if do nothing handle empty
+			$function = '_consumeEmpty';
+		}
+
+		$connect = $this->getConnect();
+		$channel = $connect->channel();
+		$channel->queue_declare($q_name,
+			false, true, false, false);
+		list(, $total, ) = $channel->queue_declare($q_name,
+			false, true, false, false);
+
+		$callback = function ($msg) use($function, $q_name) {
+			$ack = $this->ack == true ? true : false;//是否应答
+			try {
+				$message_id = $msg->get('message_id');
+				call_user_func_array(
+					[$this, $function],
+					[$message_id, $msg->body, $ack,	'', false]
+				);
+
+				//更新状态
+				$statusKey = KeyHelper::getMessageStatusKey($message_id, $q_name);
+				if ($ack === true) {
+					$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
+					Yii::$app->redis->set($statusKey, AmqpConfig::STATUS_HAND_OK);
+				} else {
+					Yii::$app->redis->set($statusKey, AmqpConfig::STATUS_NO_ACK);
+				}
+
+			} catch (\Exception $e) {
+				//消息体出错机制
+				call_user_func_array(
+					[$this, $function],
+					['', $msg->body, $ack, $e->getMessage(), false]
+				);
+			}
+		};
+
+		try {
+			$min = min($count, $total);
+			$channel->basic_qos(0, $min, null);
+			$channel->basic_consume($q_name,
+				'', false, false, false, false, $callback);
+
+			$i = 0;
+			while (count($channel->callbacks)) {
+				$i ++;
+				if ($i > $min || $this->_stop == true)
+					break;
+
+				$channel->wait();
+			}
+
+		} catch (\Exception $e) {
+			throw new Exception(2104, $e->getMessage());
+		}
+
+		$channel->close();
+		$connect->close();
+		return $this->_result;
+	}
+
+	/**
+	 * [消费消息]
+	 * @author: libingke
+	 */
+	public function consumeMessage()
+	{
+		switch ($this->type)
+		{
+			case static::TYPE_MID:
+				$data = $this->consumeByMid($this->mid);
+				break;
+
+			case static::TYPE_COUNT:
+				$data = $this->consumeByCount($this->count);
+				break;
+
+			case static::TYPE_MC:
+				throw new Exception(1000, '未开发');
+				break;
+
+			default:
+				return "It's not possible to get there.";
+		}
+
+		return $data;
+	}
+
+	/**
+	 * [清空消息]
+	 * @author: libingke
+	 * @return array
+	 */
+	public function purge()
+	{
+		$data = [];
+		$connect  = Yii::$app->Amqp->AMQPConnection();
+		$channel  = new \AMQPChannel($connect);
+		$queue = new \AMQPQueue($channel);
+		$queue->setName($this->name);
+		$queue->purge();
+		return $data;
+	}
+
+}

+ 191 - 0
backend/forms/QueueForm.php

@@ -0,0 +1,191 @@
+<?php
+
+namespace backend\forms;
+
+use backend\models\Queue;
+use common\helpers\KeyHelper;
+use components\Curl;
+use components\Exception;
+use Yii;
+
+/**
+ * Class QueueForm
+ * @package backend\forms
+ */
+class QueueForm extends BaseForm
+{
+	public $sign;
+
+	public $queue;
+
+	public $remark = '';
+
+	/**
+	 * @var array
+	 */
+	public $config = [];
+
+	public $qid;
+
+	public $force;//强制删除:用于删除库里没有的队列
+
+	public function rules()
+	{
+		return [
+			//create_queue
+			[['config', 'remark'], 'safe', 'on' => 'create_queue'],
+			[['sign', 'queue'], 'required', 'on' => 'create_queue'],
+			['sign', 'filter', 'filter' => 'trim', 'on' => 'create_queue'],
+			['sign', 'string', 'on' => 'create_queue'],
+			['remark', 'default', 'value' => 'sys', 'on' => 'create_queue'],
+
+			//delete_queue
+			[['qid'], 'required', 'on' => 'delete_queue'],
+		];
+	}
+
+	/**
+	 * [创建队列]
+	 * @author: libingke
+	 * @return array
+	 * @throws Exception
+	 */
+	public function createQueue()
+	{
+		try {
+			$connect = new \PhpAmqpLib\Connection\AMQPStreamConnection(
+				Yii::$app->Amqp->host,
+				Yii::$app->Amqp->port,
+				Yii::$app->Amqp->user,
+				Yii::$app->Amqp->pass,
+				Yii::$app->Amqp->vhost
+			);
+			$channel = $connect->channel();
+			list($queue,,) = $channel->queue_declare($this->queue,
+				false, true, false, false);
+
+		} catch (\PhpAmqpLib\Exception\AMQPProtocolChannelException $e) {
+			throw new Exception(2000, $e->getMessage());
+		}
+
+		$data = ['queue' => $queue];
+		try {
+			$one = Queue::findOne(['sign' => $this->sign]);
+			if ($one)
+				throw new Exception(2008);
+
+			//save
+			$one = new Queue();
+			$one->qid = KeyHelper::getUniqueId('queue-add');
+			$one->sign = $this->sign;
+			$one->queue = $this->queue;
+			$one->status = Queue::STATUS_YES;
+			$one->remark = $this->remark;
+			$one->config = serialize($this->config);
+			if ($one->save()) {
+				$data['qid'] = $one->qid;
+				$data['sign'] = $one->sign;
+				ksort($data);
+			}
+
+		} catch (\yii\db\Exception $e) {
+			//todo db没有记录成功
+		}
+
+		return $data;
+	}
+
+	/**
+	 * [删除队列]
+	 * @author: libingke
+	 * @return array
+	 * @throws Exception
+	 */
+	public function deleteQueue()
+	{
+		$cb = function($name) {
+			try {
+				$connect = new \PhpAmqpLib\Connection\AMQPStreamConnection(
+					Yii::$app->Amqp->host,
+					Yii::$app->Amqp->port,
+					Yii::$app->Amqp->user,
+					Yii::$app->Amqp->pass,
+					Yii::$app->Amqp->vhost
+				);
+				$channel = $connect->channel();
+				$message = $channel->queue_delete($name,
+					false, false, false, false
+				);
+
+			} catch (\PhpAmqpLib\Exception\AMQPProtocolChannelException $e) {
+				$message = $e->getMessage();
+			}
+			return $message == 0 ? '' : $message;
+		};
+
+		$data = ['delete_count' => 0, 'delete_message' => ''];
+		try {
+			$one = Queue::findOne(['qid' => $this->qid, 'status' => Queue::STATUS_YES]);
+
+			if ($one) {
+				$one->status = Queue::STATUS_NO;
+				if (($c = $cb($one->queue)) === '') {
+					$one->update();
+					$data['delete_count'] ++;
+				}
+
+				$data['delete_message'] = $c;
+			} else {
+				throw new Exception(2009);
+			}
+
+		} catch (\yii\db\Exception $e) {
+			$data['delete_message'] = $e->getMessage();
+		}
+
+		return $data;
+	}
+
+	/**
+	 * [获取消息列表]
+	 * @author: libingke
+	 */
+	public function getQueueList()
+	{
+		$badCode = 2000;
+		$authStr = Yii::$app->Amqp->getConfig('user') . ':' . Yii::$app->Amqp->getConfig('pass');
+		/* URL */
+		$vhost = urlencode(Yii::$app->Amqp->getConfig('vhost'));
+		$url = Yii::$app->Amqp->getConfig('host') . ':' . Yii::$app->Amqp->getConfig('api_port') . "/api/queues";
+
+		$curl = new Curl();
+		$curl->setOption(CURLOPT_USERPWD, $authStr);
+		$result = json_decode($curl->get($url), true);
+		if ($curl->responseCode != 200)
+			throw new Exception($badCode);
+		if ($curl->errorText)
+			throw new Exception($badCode, $curl->errorText);
+		if (isset($result['error']) && is_string($result['error']))
+			throw new Exception($badCode, $result['error']);
+
+		$rows = [];
+		foreach ($result as $k => $v) {
+			//$name = $v['name'];
+			$name = $v['name'];
+			$rows[$name]['name'] 			= $name;
+			$rows[$name]['messages_count']	= $v['messages'];
+			$rows[$name]['message_bytes']	= $v['message_bytes'];
+			$rows[$name]['messages_ready']	= $v['messages_ready'];
+			//$rows[$name]['message_stats']	= $v['message_stats'];
+			$rows[$name]['consumers_count']	= $v['consumers'];
+			$rows[$name]['auto_delete']		= $v['auto_delete'];
+			$rows[$name]['durable']			= $v['durable'];
+			//$rows[$name]['arguments']		= $v['arguments'];
+			$rows[$name]['state']			= $v['state'];
+			$rows[$name]['idle_since']		= $v['idle_since'];
+		}
+		unset($result);
+
+		return ['count' => count($rows), 'rows' => $rows];
+	}
+}

+ 1 - 0
backend/forms/READ.md

@@ -0,0 +1 @@
+表单验证

+ 42 - 0
backend/models/Queue.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace backend\models;
+
+use yii\behaviors\TimestampBehavior;
+use yii\db\Expression;
+
+/**
+ * 队列
+ * Class Queue
+ * @package backend\models
+ */
+class Queue extends \yii\db\ActiveRecord
+{
+	const STATUS_YES = 1;
+
+	const STATUS_NO = 0;
+
+    /**
+     * @inheritdoc
+     */
+    public static function tableName()
+    {
+        return '{{%queue}}';
+    }
+
+	/**
+	 * @inheritdoc
+	 */
+	public function behaviors()
+	{
+		return [
+			[
+				'class' => TimestampBehavior::className(),
+				'createdAtAttribute' => 'created_at',
+				'updatedAtAttribute' => 'updated_at',
+				//'value'   => new Expression('NOW()'),
+				'value'   => function() { return time();},
+			],
+		];
+	}
+}

+ 36 - 0
backend/models/WorkerScript.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace backend\models;
+
+/**
+ * worker
+ * Class WorkerScript
+ * @package backend\models
+ */
+class WorkerScript extends \yii\db\ActiveRecord
+{
+	const STATUS_RUN = 1;
+
+	const STATUS_STOP = 0;
+
+    /**
+     * @inheritdoc
+     */
+    public static function tableName()
+    {
+        return '{{%worker_script}}';
+    }
+
+	/**
+	 * [所有需要运行的脚本]
+	 * @author: libingke
+	 * @return array|\yii\db\ActiveRecord[]
+	 */
+    public static function getRunScriptList()
+	{
+		$data = self::find()
+			->where(['status' => static::STATUS_RUN])
+			->asArray()->all();
+		return $data;
+	}
+}

+ 4 - 0
backend/web/.htaccess

@@ -0,0 +1,4 @@
+RewriteEngine On
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteRule . index.php

+ 1 - 0
common/config/.gitignore

@@ -1,3 +1,4 @@
 main-local.php
 params-local.php
 test-local.php
+db-local.php

+ 0 - 9
common/config/db-local.php

@@ -1,9 +0,0 @@
-<?php
-
-return [
-    'class' => 'yii\db\Connection',
-    'dsn' => 'mysql:host=localhost;dbname=advance',
-    'username' => 'root',
-    'password' => 'root',
-    'charset' => 'utf8',
-];

+ 3 - 2
common/config/db.php

@@ -2,8 +2,9 @@
 
 return [
     'class' => 'yii\db\Connection',
-    'dsn' => 'mysql:host=localhost;dbname=advance',
+    'dsn' => 'mysql:host=localhost;dbname=log_system',
     'username' => 'root',
-    'password' => 'yang~1',
+    'password' => 'my@123456',
     'charset' => 'utf8',
+	'tablePrefix' => 'amqp_'
 ];

+ 26 - 4
common/config/main.php

@@ -5,19 +5,41 @@ return [
         '@npm'   => '@vendor/npm-asset',
     ],
     'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
+	'sourceLanguage' => 'en',
+	'language' => 'zh-CN',
     'components' => [
+		//  新添加的
+		'Amqp' => [
+			'class' => 'components\service\Amqp',
+			'host'	=> '127.0.0.1',
+			'port'	=> '5672',
+			'user'	=> 'guest',
+			'pass'	=> 'Guest',
+		],
+
         'cache' => [
             'class' => 'yii\caching\FileCache',
         ],
 
         'redis' => [
             'class' => 'yii\redis\Connection',
-            'hostname' => 'localhost',
+            'hostname' => '127.0.0.1',
             'port' => 6378,
             'database' => 1,
-            'password' => 'airent-redis~123',
-
-
+            'password' => 'redis12078',
         ],
+
+		'i18n' => [
+			'translations' => [
+				'*' => [
+					'class' => 'yii\i18n\PhpMessageSource',
+					'basePath'=>'@common/messages',
+					'fileMap' => [
+						'common' => 'common.php',
+						'error'	 => 'errorCode.php',
+					],
+				],
+			],
+		],
     ],
 ];

+ 40 - 0
common/helpers/KeyHelper.php

@@ -0,0 +1,40 @@
+<?php
+namespace common\helpers;
+
+/**
+ * Created by PhpStorm.
+ * Author: libingke
+ * Date: 2018/2/1
+ */
+class KeyHelper
+{
+	/**
+	 * [生成唯一Id]
+	 * @author: libingke
+	 * @return string
+	 */
+	public static function getUniqueId($addStr = '')
+	{
+		$sugar = is_string($addStr) && $addStr != '' ? $addStr : '';
+		return md5(uniqid(md5(microtime(true)),true) . $sugar);
+	}
+
+	public static function getMessageStatusKey($id, $queue)
+	{
+		if (is_string($queue) && is_string($id)) {
+			return "queue:{$queue}:message:{$id}:status";
+		}
+
+		return null;
+	}
+
+	public static function getMessageResultKey($id, $queue)
+	{
+		if (is_string($queue) && is_string($id)) {
+			return "queue:{$queue}:message:{$id}:result";
+		}
+
+		return null;
+	}
+}
+

+ 92 - 0
common/logic/Amqp/Cache.php

@@ -0,0 +1,92 @@
+<?php
+namespace common\logic\Amqp;
+
+use Yii;
+
+/**
+ * 缓存设置
+ * Class Cache
+ * @package common\logic\Amqp
+ */
+class Cache
+{
+	const CACHE_HEADER	= 'message:';
+
+	const STATUS_SEND_FAIL	= -1;//发送失败
+	const STATUS_SEND_OK	= 1;//已发送,待处理
+	const STATUS_WAIT		= 2;//等待中
+	const STATUS_HAND		= 3;//处理中
+	const STATUS_HAND_OK	= 99;//处理成功
+	const STATUS_HAND_FAIL	= -99;//处理失败
+
+	public static $statusMark = [
+		-1	=> '发送失败',
+		0	=> '未知状态',
+		1	=> '已发送,待处理',
+		2	=> '等待中',
+		3	=> '处理中',
+		99	=> '处理成功',
+		-99 => '处理失败',
+	];
+
+	/**
+	 * [设置缓存状态]
+	 * @author: libingke
+	 * @param $key
+	 * @param $value
+	 * @param bool $time
+	 * @return bool
+	 */
+	public static function setData($key, $value, $time = false)
+	{
+		$cache = Yii::$app->redis;
+		if ($key) {
+			if (is_numeric($time)) {
+				return $cache->set(static::CACHE_HEADER . $key, $value, $time);
+			}
+
+			return $cache->set(static::CACHE_HEADER . $key, $value);
+		}
+
+		return false;
+	}
+
+	/**
+	 * [获取缓存状态]
+	 * @author: libingke
+	 * @param $key
+	 * @return bool
+	 */
+	public static function getData($key)
+	{
+		$cache = Yii::$app->redis;
+		return $cache->get(static::CACHE_HEADER . $key);
+	}
+
+	/**
+	 * [删除缓存状态]
+	 * @author: libingke
+	 * @param $key
+	 * @return mixed
+	 */
+	public static function deleteData($key)
+	{
+		$cache = Yii::$app->redis;
+		return $cache->delete(static::CACHE_HEADER . $key);
+	}
+
+	/**
+	 * [查询状态]
+	 * @author: libingke
+	 * @param $id
+	 * @return mixed|null
+	 */
+	public static function getMarkById($id)
+	{
+		if (isset(self::$statusMark[$id]) && is_numeric($id)) {
+			return self::$statusMark[$id];
+		}
+
+		return self::$statusMark[0];
+	}
+}

+ 38 - 0
common/logic/Amqp/Connect.php

@@ -0,0 +1,38 @@
+<?php
+namespace common\logic\Amqp;
+
+/**
+ * 连接配置
+ * Class Config
+ * @package common\logic\message
+ * @author libingke
+ */
+class Connect
+{
+	CONST HOST = "127.0.0.1";
+
+	CONST PORT = 5672;
+
+	CONST USER = "guest";
+
+	CONST PASS = "Guest";
+
+	private static $_conn = null;
+
+	private function __construct(){}
+
+	private function __clone(){}
+
+	public static function connect()
+	{
+		if (self::$_conn == null) {
+			self::$_conn = new \PhpAmqpLib\Connection\AMQPStreamConnection(
+				self::HOST,
+				self::PORT,
+				self::USER,
+				self::PASS
+			);
+		}
+		return self::$_conn;
+	}
+}

+ 13 - 0
common/logic/Amqp/Exception.php

@@ -0,0 +1,13 @@
+<?php
+namespace common\logic\Amqp;
+
+use PhpAmqpLib\Exception\AMQPProtocolChannelException as BaseException;
+
+/**
+ * Class Exception
+ * @package common\logic\message
+ * @author libingke
+ */
+class Exception extends BaseException
+{
+}

+ 120 - 0
common/logic/Amqp/Message.php

@@ -0,0 +1,120 @@
+<?php
+
+namespace common\logic\Amqp;
+
+use common\helpers\KeyHelper;
+use PhpAmqpLib\Message\AMQPMessage;
+use Yii;
+
+/**
+ * 处理消息体逻辑
+ * Class Message
+ * @package common\logic\MQMessage
+ * @author libingke
+ */
+class Message extends Connect
+{
+	private $_connect;
+
+	private $_channel;
+
+	private $_callback_queue;
+
+	private $_response;
+
+	private $_corr_id;
+
+	public function __construct($queueName = '')
+	{
+		$this->_connect = self::connect();
+
+		$this->_channel = $this->_connect->channel();
+
+		$this->_callback_queue = $queueName;
+	}
+
+	/**
+	 * [发送信息]
+	 * @author: libingke
+	 * @param string $body 消息主体
+	 * @param string $routing_key
+	 * @return bool
+	 */
+	public function send($body, $routing_key)
+	{
+		$this->_corr_id = KeyHelper::getUniqueId('message_send');
+		$properties = [
+			//'content_type' => 'text/plain',
+			'correlation_id' => $this->_corr_id,
+			'reply_to' => $this->_callback_queue
+		];
+
+		if (is_string($body)) {
+			$msg = new AMQPMessage( (string) $body, $properties);
+			$this->_channel->basic_publish($msg, '', $routing_key);
+		}
+
+		return $this->_corr_id;
+	}
+
+	/**
+	 * [批量发送信息]
+	 * @author: libingke
+	 * @param $info
+	 * @param $queue
+	 */
+	public function batchSend($info, $queue)
+	{
+		foreach ($info as $str) {
+			$this->_channel->batch_basic_publish($str, '', $queue);
+		}
+		$this->_channel->publish_batch();
+	}
+
+	/**
+	 * [消费信息]  todo
+	 * @author: libingke
+	 * @param string $queue 队列名称
+	 * @param string $str
+	 * @return bool
+	 */
+	public function consume($queue)
+	{
+		$callback = function($msg) {
+			echo " [x] Received ", $msg->body, "\n";
+			$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
+		};
+
+		$this->_channel->basic_qos(null, 1, null);
+		$this->_channel->basic_consume(
+			$queue, '', false, false, false, false,
+			$callback
+		);
+
+		while(count($this->_channel->callbacks)) {
+			$this->_channel->wait();
+		}
+
+		return true;
+	}
+
+	/**
+	 * [批量消费信息]
+	 * @author: libingke
+	 * @param string $queue 队列名称
+	 * @param string $arr
+	 * @return array 返回数据
+	 */
+	public function batchConsume($queue, $arr)
+	{
+	}
+
+	/**
+	 * [删除信息]
+	 * @author: libingke
+	 */
+	public function delete($message)
+	{
+
+	}
+}

+ 70 - 0
common/logic/Amqp/Queue.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace common\logic\Amqp;
+
+use PhpAmqpLib\Exception\AMQPProtocolChannelException;
+
+/**
+ * 队列逻辑
+ * Class Queue
+ * @package common\logic\Amqp
+ * @author libingke
+ */
+class Queue extends Connect
+{
+    private $_connect;
+
+    private $_channel;
+
+    public function __construct()
+	{
+        $this->_connect = self::connect();
+
+		$this->_channel = $this->_connect->channel();
+    }
+
+	/**
+	 * [创建队列]
+	 * @author: libingke
+	 * @param string $queueName
+	 * @return array
+	 */
+    public function create($queueName)
+	{
+		try {
+			list($callback_queue, ,) = $this->_channel->queue_declare(
+				(string) $queueName,
+				false,
+				0,//持久化
+				false,
+				false
+			);
+
+			return ['status' => 1, 'result' => $callback_queue];
+
+		} catch (AMQPProtocolChannelException $e) {
+
+			return ['status' => 0, 'result' => $e->getMessage()];
+		}
+	}
+
+	/**
+	 * [删除队列]
+	 * @author: libingke
+	 * @param string $queueName
+	 * @return array
+	 */
+	public function delete($queueName)
+	{
+		try {
+			$this->_channel->queue_delete((string) $queueName);
+
+			return ['status' => 1, 'result' => 'OK'];
+
+		} catch (AMQPProtocolChannelException $e) {
+
+			return ['status' => 0, 'result' => $e->getMessage()];
+		}
+	}
+
+}

+ 5 - 0
common/messages/en-US/common.php

@@ -0,0 +1,5 @@
+<?php
+
+return [
+
+];

+ 4 - 0
common/messages/en-US/errorCode.php

@@ -0,0 +1,4 @@
+<?php
+
+return [
+];

+ 3 - 0
common/messages/zh-CN/common.php

@@ -0,0 +1,3 @@
+<?php
+
+return [];

+ 109 - 0
common/messages/zh-CN/errorCode.php

@@ -0,0 +1,109 @@
+<?php
+
+return [
+	/**
+	 * 系统错误信息
+	 */
+	'100' => 'Continue',
+	'101' => 'Switching Protocols',
+	'102' => 'Processing',
+	'103' => 'Checkpoint',
+	'122' => 'Reques­t-URI too long',
+	'200' => 'OK',
+	'201' => 'Created',
+	'202' => 'Accepted',
+	'203' => 'Non-Au­tho­rit­ative Inform­ation',
+	'204' => 'No Content',
+	'205' => 'Reset Content',
+	'206' => 'Partial Content',
+	'207' => 'Multi-­Status',
+	'208' => 'Already Reported',
+	'226' => 'IM Used',
+	'300' => 'Multiple Choices',
+	'301' => 'Moved Perman­ently',
+	'302' => 'Found',
+	'303' => 'See Other',
+	'304' => 'Not Modified',
+	'305' => 'Use Proxy',
+	'306' => 'Switch Proxy',
+	'307' => 'Temporary Redirect',
+	'308' => 'Resume Incomplete',
+	'400' => 'Bad Request',
+	'401' => 'Unauth­orized',
+	'402' => 'Payment Required',
+	'403' => 'Forbidden',
+	'404' => 'Not Found',
+	'405' => 'Method Not Allowed',
+	'406' => 'Not Acceptable',
+	'407' => 'Proxy Authen­tic­ation Required',
+	'408' => 'Request Timeout',
+	'409' => 'Conflict',
+	'410' => 'Gone',
+	'411' => 'Length Required',
+	'412' => 'Precon­dition Failed',
+	'413' => 'Request Entity Too Large',
+	'414' => 'Reques­t-URI Too Long',
+	'415' => 'Unsupp­orted Media Type',
+	'416' => 'Requested Range Not Satisf­iable',
+	'417' => 'Expect­ation Failed',
+	'418' => 'I am a teapot',
+	'422' => 'Unproc­essable Entity',
+	'423' => 'Locked',
+	'424' => 'Failed Dependency',
+	'425' => 'Unordered Collection',
+	'426' => 'Upgrade Required',
+	'428' => 'Precon­dition Required',
+	'429' => 'Too Many Requests',
+	'431' => 'Request Header Fields Too Large',
+	'444' => 'No Response',
+	'449' => 'Retry With',
+	'450' => 'Blocked By Windows Parental Controls',
+	'451' => 'Unavai­lable For Legal Reasons',
+	'499' => 'Client Closed Request',
+	'500' => 'Internal Server Error',
+	'501' => 'Not Implem­ented',
+	'502' => 'Bad Gateway',
+	'503' => 'Service Unavai­lable',
+	'504' => 'Gateway Timeout',
+	'505' => 'HTTP Version Not Supported',
+	'506' => 'Variant Also Negotiates',
+	'507' => 'Insuff­icient Storage',
+	'508' => 'Loop Detected',
+	'509' => 'Bandwidth Limit Exceeded',
+	'510' => 'Not Extended',
+	'511' => 'Network Authen­tic­ation Required',
+	'598' => 'Network read timeout error',
+	'599' => 'Network connect timeout error',
+
+
+	'1000' => 'Exception',
+	'1001' => '非POST提交',
+	'1002' => '非GET提交',
+	'1003' => '表单验证失败',
+
+	//message
+	'2000' => 'rabbitMQ连接失败',
+	'2001' => '消息主体不能为空',
+	'2002' => '消息格式错误',
+	'2003' => '队列名称不能为空',
+	'2004' => '队列名称格式错误',
+	'2005' => 'data不能为空',
+	'2006' => 'data格式错误,必须是合法json',
+	'2007' => 'data格式错误,必须包含 \'body\',\'infos\'',
+	'2008' => '队列标识sign已存在',
+	'2009' => '队列id不存在或已删除',
+	'2010' => 'requeue只能是布尔值',
+	'2011' => 'encoding格式错误',
+	'2012' => '获取数量必须是整数',
+	'2013' => '获取数量太小,必须大于0',
+	'2014' => '获取数量太大,必须小于1000 [或联系开发解除限制]',
+	'2015' => '未找到该队列对应的消费回调',
+	'2016' => '消息id不能为空',
+	'2017' => '数量不能为空',
+
+	'2100' => '队列创建失败',
+	'2101' => '消息处理中',
+	'2102' => '未知消息',
+	'2103' => '消息发送至队列过程中失败',
+	'2104' => '队列不存在',
+];

+ 618 - 0
components/Curl.php

@@ -0,0 +1,618 @@
+<?php
+
+namespace components;
+
+use Yii;
+use yii\base\Exception;
+use yii\helpers\Json;
+
+class Curl
+{
+	/**
+	 * @var string
+	 * * Holds response data right after sending a request.
+	 */
+	public $httpType = 'http';
+
+	/**
+	 * @var string|boolean
+	 * Holds response data right after sending a request.
+	 */
+	public $response = null;
+	/**
+	 * @var null|integer
+	 * Error code holder: https://curl.haxx.se/libcurl/c/libcurl-errors.html
+	 */
+	public $errorCode = null;
+	/**
+	 * @var null|string
+	 * Error text holder: http://php.net/manual/en/function.curl-strerror.php
+	 */
+	public $errorText = null;
+	/**
+	 * @var integer HTTP-Status Code
+	 * This value will hold HTTP-Status Code. False if request was not successful.
+	 */
+	public $responseCode = null;
+	/**
+	 * @var string|null HTTP Response Charset
+	 * (taken from Content-type header)
+	 */
+	public $responseCharset = null;
+	/**
+	 * @var int HTTP Response Length
+	 * (taken from Content-length header, or strlen() of downloaded content)
+	 */
+	public $responseLength = -1;
+	/**
+	 * @var string|null HTTP Response Content Type
+	 * (taken from Content-type header)
+	 */
+	public $responseType = null;
+	/**
+	 * @var array|null HTTP Response headers
+	 * Lists response header in an array if CURLOPT_HEADER is set to true.
+	 */
+	public $responseHeaders = null;
+	/**
+	 * @var array HTTP-Status Code
+	 * Custom options holder
+	 */
+	protected $_options = [];
+	/**
+	 * @var array
+	 * Hold array of get params to send with the request
+	 */
+	protected $_getParams = [];
+	/**
+	 * @var array
+	 * Hold array of post params to send with the request
+	 */
+	protected $_postParams = [];
+	/**
+	 * @var resource|null
+	 * Holds cURL-Handler
+	 */
+	public $curl = null;
+	/**
+	 * @var string
+	 * hold base URL
+	 */
+	protected $_baseUrl = '';
+	/**
+	 * @var array default curl options
+	 * Default curl options
+	 */
+	protected $_defaultOptions = [
+
+		CURLOPT_USERAGENT      => 'Yii2-Curl-Agent',
+		CURLOPT_TIMEOUT        => 10,
+		CURLOPT_CONNECTTIMEOUT => 10,
+		CURLOPT_RETURNTRANSFER => true,
+		CURLOPT_HEADER         => true,
+
+		CURLOPT_SSL_VERIFYPEER => false,
+		CURLOPT_SSL_VERIFYHOST => 2,
+	];
+	// ############################################### class methods // ##############################################
+	/**
+	 * Start performing GET-HTTP-Request
+	 *
+	 * @param string  $url
+	 * @param boolean $raw if response body contains JSON and should be decoded
+	 *
+	 * @return mixed response
+	 */
+	public function get($url, $raw = true)
+	{
+		$this->_baseUrl = $url;
+		return $this->_httpRequest('GET', $raw);
+	}
+	/**
+	 * Start performing HEAD-HTTP-Request
+	 *
+	 * @param string $url
+	 *
+	 * @return mixed response
+	 */
+	public function head($url)
+	{
+		$this->_baseUrl = $url;
+		return $this->_httpRequest('HEAD');
+	}
+	/**
+	 * Start performing POST-HTTP-Request
+	 *
+	 * @param string  $url
+	 * @param boolean $raw if response body contains JSON and should be decoded
+	 *
+	 * @return mixed response
+	 */
+	public function post($url, $raw = true)
+	{
+		$this->_baseUrl = $url;
+		return $this->_httpRequest('POST', $raw);
+	}
+	/**
+	 * Start performing PUT-HTTP-Request
+	 *
+	 * @param string  $url
+	 * @param boolean $raw if response body contains JSON and should be decoded
+	 *
+	 * @return mixed response
+	 */
+	public function put($url, $raw = true)
+	{
+		$this->_baseUrl = $url;
+		return $this->_httpRequest('PUT', $raw);
+	}
+	/**
+	 * Start performing PATCH-HTTP-Request
+	 *
+	 * @param string  $url
+	 * @param boolean $raw if response body contains JSON and should be decoded
+	 *
+	 * @return mixed response
+	 */
+	public function patch($url, $raw = true)
+	{
+		$this->_baseUrl = $url;
+		$this->setHeaders([
+			'X-HTTP-Method-Override' => 'PATCH'
+		]);
+		return $this->_httpRequest('POST',$raw);
+	}
+	/**
+	 * Start performing DELETE-HTTP-Request
+	 *
+	 * @param string  $url
+	 * @param boolean $raw if response body contains JSON and should be decoded
+	 *
+	 * @return mixed response
+	 */
+	public function delete($url, $raw = true)
+	{
+		$this->_baseUrl = $url;
+		return $this->_httpRequest('DELETE', $raw);
+	}
+	/**
+	 * Set curl option
+	 *
+	 * @param string $key
+	 * @param mixed  $value
+	 *
+	 * @return $this
+	 */
+	public function setOption($key, $value)
+	{
+		//set value
+		if (array_key_exists($key, $this->_defaultOptions) && $key !== CURLOPT_WRITEFUNCTION) {
+			$this->_defaultOptions[$key] = $value;
+		} else {
+			$this->_options[$key] = $value;
+		}
+		//return self
+		return $this;
+	}
+	/**
+	 * Set get params
+	 *
+	 * @param array $params
+	 * @return $this
+	 */
+	public function setGetParams($params)
+	{
+		if (is_array($params)) {
+			foreach ($params as $key => $value) {
+				$this->_getParams[$key] = $value;
+			}
+		}
+		//return self
+		return $this;
+	}
+	/**
+	 * Set get params
+	 *
+	 * @param array $params
+	 * @return $this
+	 */
+	public function setPostParams($params)
+	{
+		if (is_array($params)) {
+			$this->setOption(
+				CURLOPT_POSTFIELDS,
+				http_build_query($params)
+			);
+		}
+		//return self
+		return $this;
+	}
+	/**
+	 * Set raw post data allows you to post any data format.
+	 *
+	 * @param mixed $data
+	 * @return $this
+	 */
+	public function setRawPostData($data)
+	{
+		$this->setOption(
+			CURLOPT_POSTFIELDS,
+			$data
+		);
+		//return self
+		return $this;
+	}
+	/**
+	 * Set get params
+	 *
+	 * @param string $data
+	 * @return $this
+	 */
+	public function setRequestBody($data)
+	{
+		if (is_string($data)) {
+			$this->setOption(
+				CURLOPT_POSTFIELDS,
+				$data
+			);
+		}
+		//return self
+		return $this;
+	}
+	/**
+	 * Get URL - return URL parsed with given params
+	 *
+	 * @return string The full URL with parsed get params
+	 */
+	public function getUrl()
+	{
+		if (Count($this->_getParams) > 0) {
+			return $this->_baseUrl.'?'.http_build_query($this->_getParams);
+		} else {
+			return $this->_baseUrl;
+		}
+	}
+	/**
+	 * Set curl options
+	 *
+	 * @param array $options
+	 *
+	 * @return $this
+	 */
+	public function setOptions($options)
+	{
+		$this->_options = $options + $this->_options;
+		return $this;
+	}
+	/**
+	 * Set multiple headers for request.
+	 *
+	 * @param array $headers
+	 *
+	 * @return $this
+	 */
+	public function setHeaders($headers)
+	{
+		if (is_array($headers)) {
+			//init
+			$parsedHeader = [];
+			//collect currently set headers
+			foreach ($this->getRequestHeaders() as $header => $value) {
+				array_push($parsedHeader, $header.':'.$value);
+			}
+			//parse header into right format key:value
+			foreach ($headers as $header => $value) {
+				array_push($parsedHeader, $header.':'.$value);
+			}
+			//set headers
+			$this->setOption(
+				CURLOPT_HTTPHEADER,
+				$parsedHeader
+			);
+		}
+		return $this;
+	}
+	/**
+	 * Set a single header for request.
+	 *
+	 * @param string $header
+	 * @param string $value
+	 *
+	 * @return $this
+	 */
+	public function setHeader($header, $value)
+	{
+		//init
+		$parsedHeader = [];
+		//collect currently set headers
+		foreach ($this->getRequestHeaders() as $headerToSet => $valueToSet) {
+			array_push($parsedHeader, $headerToSet.':'.$valueToSet);
+		}
+		//add override new header
+		if (strlen($header) > 0) {
+			array_push($parsedHeader, $header.':'.$value);
+		}
+		//set headers
+		$this->setOption(
+			CURLOPT_HTTPHEADER,
+			$parsedHeader
+		);
+		return $this;
+	}
+	/**
+	 * Unset a single header.
+	 *
+	 * @param string $header
+	 *
+	 * @return $this
+	 */
+	public function unsetHeader($header)
+	{
+		//init
+		$parsedHeader = [];
+		//collect currently set headers and filter "unset" header param.
+		foreach ($this->getRequestHeaders() as $headerToSet => $valueToSet) {
+			if ($header !== $headerToSet) {
+				array_push($parsedHeader, $headerToSet.':'.$valueToSet);
+			}
+		}
+		//set headers
+		$this->setOption(
+			CURLOPT_HTTPHEADER,
+			$parsedHeader
+		);
+		return $this;
+	}
+	/**
+	 * Get all request headers as key:value array
+	 *
+	 * @return array
+	 */
+	public function getRequestHeaders()
+	{
+		//Init
+		$requestHeaders = $this->getOption(CURLOPT_HTTPHEADER);
+		$parsedRequestHeaders = [];
+		if (is_array($requestHeaders)) {
+			foreach ($requestHeaders as $headerValue) {
+				list ($key, $value) = explode(':', $headerValue, 2);
+				$parsedRequestHeaders[$key] = $value;
+			}
+		}
+		return $parsedRequestHeaders;
+	}
+	/**
+	 * Get specific request header as key:value array
+	 *
+	 * @param string $headerKey
+	 *
+	 * @return string|null
+	 */
+	public function getRequestHeader($headerKey)
+	{
+		//Init
+		$parsedRequestHeaders = $this->getRequestHeaders();
+		return isset($parsedRequestHeaders[$headerKey]) ? $parsedRequestHeaders[$headerKey] : null;
+	}
+	/**
+	 * Unset a single curl option
+	 *
+	 * @param string $key
+	 *
+	 * @return $this
+	 */
+	public function unsetOption($key)
+	{
+		//reset a single option if its set already
+		if (isset($this->_options[$key])) {
+			unset($this->_options[$key]);
+		}
+		return $this;
+	}
+	/**
+	 * Unset all curl option, excluding default options.
+	 *
+	 * @return $this
+	 */
+	public function unsetOptions()
+	{
+		//reset all options
+		if (isset($this->_options)) {
+			$this->_options = [];
+		}
+		return $this;
+	}
+	/**
+	 * Total reset of options, responses, etc.
+	 *
+	 * @return $this
+	 */
+	public function reset()
+	{
+		if ($this->curl !== null) {
+			curl_close($this->curl); //stop curl
+		}
+		//reset all options
+		if (isset($this->_options)) {
+			$this->_options = [];
+		}
+		//reset response & status params
+		$this->curl = null;
+		$this->errorCode = null;
+		$this->response = null;
+		$this->responseCode = null;
+		$this->responseCharset = null;
+		$this->responseLength = -1;
+		$this->responseType = null;
+		$this->errorText = null;
+		$this->_postParams = [];
+		$this->_getParams = [];
+		return $this;
+	}
+	/**
+	 * Return a single option
+	 *
+	 * @param string|integer $key
+	 * @return mixed|boolean
+	 */
+	public function getOption($key)
+	{
+		//get merged options depends on default and user options
+		$mergesOptions = $this->getOptions();
+		//return value or false if key is not set.
+		return isset($mergesOptions[$key]) ? $mergesOptions[$key] : false;
+	}
+	/**
+	 * Return merged curl options and keep keys!
+	 *
+	 * @return array
+	 */
+	public function getOptions()
+	{
+		return $this->_options + $this->_defaultOptions;
+	}
+	/**
+	 * Get curl info according to http://php.net/manual/de/function.curl-getinfo.php
+	 *
+	 * @param null $opt
+	 * @return array|mixed
+	 */
+	public function getInfo($opt = null)
+	{
+		if ($this->curl !== null && $opt === null) {
+			return curl_getinfo($this->curl);
+		} elseif ($this->curl !== null && $opt !== null) {
+			return curl_getinfo($this->curl, $opt);
+		} else {
+			return [];
+		}
+	}
+	/**
+	 * Performs HTTP request
+	 *
+	 * @param string  $method
+	 * @param boolean $raw if response body contains JSON and should be decoded -> helper.
+	 *
+	 * @throws Exception if request failed
+	 *
+	 * @return mixed
+	 */
+	protected function _httpRequest($method, $raw = false)
+	{
+		//set request type and writer function
+		$this->setOption(CURLOPT_CUSTOMREQUEST, strtoupper($method));
+		//check if method is head and set no body
+		if ($method === 'HEAD') {
+			$this->setOption(CURLOPT_NOBODY, true);
+			$this->unsetOption(CURLOPT_WRITEFUNCTION);
+		}
+		//setup error reporting and profiling
+		if (YII_DEBUG) {
+			Yii::trace('Start sending cURL-Request: '.$this->getUrl().'\n', __METHOD__);
+			Yii::beginProfile($method.' '.$this->_baseUrl.'#'.md5(serialize($this->getOption(CURLOPT_POSTFIELDS))), __METHOD__);
+		}
+		/**
+		 * proceed curl
+		 */
+		$curlOptions =  $this->getOptions();
+		$this->curl = curl_init($this->getUrl());
+		curl_setopt_array($this->curl, $curlOptions);
+		$response = curl_exec($this->curl);
+		//check if curl was successful
+		if ($response === false) {
+			//set error code
+			$this->errorCode = curl_errno($this->curl);
+			$this->errorText = curl_strerror($this->errorCode);
+			switch ($this->errorCode) {
+				// 7, 28 = timeout
+				case 7:
+				case 28:
+					$this->responseCode = 'timeout';
+					return false;
+					break;
+				default:
+					return false;
+					break;
+			}
+		}
+		//extract header / body data if CURLOPT_HEADER are set to true
+		if (isset($curlOptions[CURLOPT_HEADER]) && $curlOptions[CURLOPT_HEADER]) {
+			$this->response = $this->_extractCurlBody($response);
+			$this->responseHeaders = $this->_extractCurlHeaders($response);
+		} else {
+			$this->response = $response;
+		}
+		// Extract additional curl params
+		$this->_extractAdditionalCurlParameter();
+		//end yii debug profile
+		if (YII_DEBUG) {
+			Yii::endProfile($method.' '.$this->getUrl().'#'.md5(serialize($this->getOption(CURLOPT_POSTFIELDS))), __METHOD__);
+		}
+		//check responseCode and return data/status
+		if ($this->getOption(CURLOPT_CUSTOMREQUEST) === 'HEAD') {
+			return true;
+		} else {
+			$this->response = $raw ? $this->response : Json::decode($this->response);
+			return $this->response;
+		}
+	}
+	/**
+	 * Extract additional curl params protected class helper
+	 */
+	protected function _extractAdditionalCurlParameter ()
+	{
+		/**
+		 * retrieve response code
+		 */
+		$this->responseCode = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
+		/**
+		 * try extract response type & charset.
+		 */
+		$this->responseType = curl_getinfo($this->curl, CURLINFO_CONTENT_TYPE);
+		if (!is_null($this->responseType) && count(explode(';', $this->responseType)) > 1) {
+			list($this->responseType, $possibleCharset) = explode(';', $this->responseType);
+			//extract charset
+			if (preg_match('~^charset=(.+?)$~', trim($possibleCharset), $matches) && isset($matches[1])) {
+				$this->responseCharset = strtolower($matches[1]);
+			}
+		}
+		/**
+		 * try extract response length
+		 */
+		$this->responseLength = curl_getinfo($this->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
+		if((int)$this->responseLength == -1) {
+			$this->responseLength = strlen($this->response);
+		}
+	}
+	/**
+	 * Extract body curl data from response
+	 *
+	 * @param string $response
+	 * @return string
+	 */
+	protected function _extractCurlBody ($response)
+	{
+		return substr($response, $this->getInfo(CURLINFO_HEADER_SIZE));
+	}
+	/**
+	 * Extract header curl data from response
+	 *
+	 * @param string $response
+	 * @return array
+	 */
+	protected function _extractCurlHeaders ($response)
+	{
+		//Init
+		$headers = [];
+		$headerText = substr($response, 0, strpos($response, "\r\n\r\n"));
+		foreach (explode("\r\n", $headerText) as $i => $line) {
+			if ($i === 0) {
+				$headers['http_code'] = $line;
+			} else {
+				list ($key, $value) = explode(':', $line, 2);
+				$headers[$key] = ltrim($value);
+			}
+		}
+		return $headers;
+	}
+}

+ 73 - 0
components/ErrorHandler.php

@@ -0,0 +1,73 @@
+<?php
+namespace components;
+
+use Yii;
+use yii\base\UserException;
+use yii\web\Response;
+use yii\web\HttpException;
+use yii\web\ErrorHandler as baseErrorHandler;
+
+/**
+ * 异常处理模型
+ * Class ErrorHandler
+ * @package components
+ */
+class ErrorHandler extends baseErrorHandler
+{
+	/**
+	 * 传递异常
+	 * @author: libingke
+	 * @param \Error|\Exception $exception
+	 */
+	protected function renderException($exception)
+	{
+		if (Yii::$app->has('response')) {
+			$response = Yii::$app->getResponse();
+			$response->isSent = false;
+			$response->stream = null;
+			$response->data = null;
+			$response->content = null;
+		} else {
+			$response = new Response();
+		}
+
+		$useErrorView = $response->format === Response::FORMAT_HTML && (!YII_DEBUG || $exception instanceof UserException);
+		if ($useErrorView && $this->errorAction !== null) {
+			$result = Yii::$app->runAction($this->errorAction);
+			if ($result instanceof Response) {
+				$response = $result;
+			} else {
+				$response->data = $result;
+			}
+		} elseif ($response->format === Response::FORMAT_HTML) {
+			if (YII_ENV_TEST || isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
+				$response->data = '<pre>' . $this->htmlEncode(static::convertExceptionToString($exception)) . '</pre>';
+			} else {
+				if (YII_DEBUG) {
+					ini_set('display_errors', 1);
+				}
+				$file = $useErrorView ? $this->errorView : $this->exceptionView;
+				$response->data = $this->renderFile($file, [
+					'exception' => $exception,
+				]);
+			}
+		} elseif ($response->format === Response::FORMAT_RAW) {
+			$response->data = static::convertExceptionToString($exception);
+		} else {
+			$response->data = static::convertExceptionToArray($exception);
+		}
+		if ($exception instanceof HttpException) {
+			$response->setStatusCode($exception->statusCode);
+		} else {
+			$response->setStatusCode(200);
+		}
+
+		if (is_array($response->data)) {
+			//$response->data['error'] = $response->data['name'];
+			unset($response->data['name'], $response->data['type']);
+			ksort($response->data);
+			$response->data['data'] = [];
+		}
+		$response->send();
+	}
+}

+ 43 - 0
components/Exception.php

@@ -0,0 +1,43 @@
+<?php
+namespace components;
+
+use Yii;
+use yii\base\UserException;
+
+/**
+ * 异常 模型
+ * Class Exception
+ * @package components
+ */
+class Exception extends UserException
+{
+	const ERROR = 'AMQ ERROR';
+
+	const UNKNOWN_ERROR_CODE = 500;
+
+	/**
+	 * Exception constructor.
+	 * @param null $code
+	 * @param null $message
+	 * @param null $previous
+	 */
+	public function __construct($code = null, $message = null, $previous = null)
+	{
+		if (is_numeric($message) && is_string($code)) {
+			list($code, $message) = [$message, $code];
+		}
+
+		$code = is_numeric($code) ? $code : self::UNKNOWN_ERROR_CODE;
+		$message = $message ?: Yii::t('error', $code);
+		parent::__construct($message, $code, $previous);
+	}
+
+	/**
+	 * 获取异常信息
+	 * @return string
+	 */
+	public function getName()
+	{
+		return self::ERROR;
+	}
+}

+ 108 - 0
components/RabbitMQ/PhpClient.php

@@ -0,0 +1,108 @@
+<?php
+
+namespace components\RabbitMQ;
+
+use PhpAmqpLib\Message\AMQPMessage;
+use PhpAmqpLib\Connection\AMQPStreamConnection;
+
+class PhpClient
+{
+    private $connection;
+    private $channel;
+    private $callback_queue;
+    private $response;
+    private $corr_id;
+    private $result = '';
+
+	CONST HOST = "121.196.226.188";
+
+    CONST PORT = 5672;
+    CONST USER = "lbk";
+    CONST PASS = "123456";
+
+    public function __construct()
+	{
+        $this->connection = new AMQPStreamConnection(
+            self::HOST, self::PORT, self::USER, self::PASS); //建立连接
+
+        $this->channel = $this->connection->channel();
+        list($this->callback_queue, ,) = $this->channel->queue_declare(
+            "", false, false, true, false);
+
+        $this->channel->basic_consume(
+            $this->callback_queue, '', false, false, false, false,
+            array($this, 'on_response'));
+    }
+
+    public function on_response($rep) {
+        if($rep->get('correlation_id') == $this->corr_id) {
+            $this->result .= $rep->body;
+            $this->response = $rep->body;
+        }
+    }
+
+    public function call($n) {
+        $this->response = null;
+        $this->corr_id = uniqid();
+
+        $msg = new AMQPMessage(
+            (string) $n,
+            array('correlation_id' => $this->corr_id,
+                'reply_to' => $this->callback_queue)
+        );
+        $this->channel->basic_publish($msg, '', 'test'); //这里的queue是消息名称
+
+		var_dump($this->response, $this->result);die;
+
+        while($this->response != "end") {
+            $this->channel->wait();
+        }
+        return $this->result;
+    }
+
+
+    public static function CallMq($n){
+
+        $connection =   new AMQPStreamConnection(
+            self::HOST, self::PORT, self::USER, self::PASS); //建立连接
+        $channel = $connection->channel();
+
+        $channel->queue_declare('task_queue', false, true, false, false);
+
+        $data=empty($n)?"Hello World!":$n;
+
+        $msg = new AMQPMessage($data,
+            array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT)
+        );
+
+        $channel->basic_publish($msg, '', 'task_queue');
+
+        $channel->close();
+        $connection->close();
+
+        return true;
+    }
+
+
+    public static function CallUserMq($n){
+
+        $connection =   new AMQPStreamConnection(
+            self::HOST, self::PORT, self::USER, self::PASS); //建立连接
+        $channel = $connection->channel();
+
+        $channel->queue_declare('login', false, true, false, false);
+
+        $data=empty($n)?"Hello World!":$n;
+
+        $msg = new AMQPMessage($data,
+            array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT)
+        );
+
+        $channel->basic_publish($msg, '', 'login');
+
+        $channel->close();
+        $connection->close();
+
+        return true;
+    }
+}

+ 64 - 0
components/service/Amqp.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace components\service;
+
+use components\Exception;
+use PhpAmqpLib\Connection\AMQPStreamConnection;
+
+/**
+ * Amqp 服务组件
+ * Class Amqp
+ * @package components\service
+ */
+class Amqp extends AmqpConfig
+{
+	/* 以下即将废弃:因为使用跟踪不方便 */
+
+	/**
+	 * [获取连接]
+	 * @author: libingke
+	 * @return AMQPStreamConnection
+	 */
+	public function getConnect()
+	{
+		$conn = new \PhpAmqpLib\Connection\AMQPStreamConnection(
+			$this->host,
+			$this->port,
+			$this->user,
+			$this->pass,
+			$this->vhost
+		);
+		return $conn;//->channel()->queue_declare();
+	}
+
+	/**
+	 * [php拓展自带的连接]
+	 * @author: libingke
+	 * @return \AMQPConnection
+	 */
+	public function AMQPConnection()
+	{
+		$config = [
+			'host' => $this->host,
+			'port' => $this->port,
+			'login'=> $this->user,
+			'password' => $this->pass,
+			'vhost' => $this->vhost
+		];
+		$conn = new \AMQPConnection($config);
+		if (!$conn->connect())
+			throw new Exception(2000);
+
+		return $conn;
+	}
+
+	/**
+	 * @param string $key
+	 * @return mixed
+	 */
+	public function getConfig($key = '')
+	{
+		return is_string($key) && $key && isset($this->$key) ?
+			$this->$key : json_decode(json_encode($this), true);
+	}
+}

+ 47 - 0
components/service/AmqpConfig.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace components\service;
+
+class AmqpConfig
+{
+	public $host = '127.0.0.1';
+
+	public $port = 5672;
+
+	public $user = 'guest';
+
+	public $pass = 'Guest';
+
+	public $vhost = '/';
+
+	public $api_port = '15672';
+
+	/* status */
+	const STATUS_SEND_FAIL	= -1;//发送失败
+	const STATUS_SEND_OK	= 1;//已发送,待处理
+	const STATUS_WAIT		= 2;//等待中
+	const STATUS_HAND		= 3;//处理中
+	const STATUS_NO_ACK		= 4;//已处理,未应答
+	const STATUS_HAND_OK	= 99;//处理成功
+	const STATUS_HAND_FAIL	= -99;//处理失败
+
+	public static $statusMark = [
+		-1	=> '发送失败',
+		0	=> '未知状态',
+		1	=> '已发送,待处理',
+		2	=> '等待中',
+		3	=> '处理中',
+		4	=> '已处理,未应答',
+		99	=> '处理成功',
+		-99 => '处理失败',
+	];
+
+	public static function getMarkById($id)
+	{
+		if (isset(self::$statusMark[$id]) && is_numeric($id)) {
+			return self::$statusMark[$id];
+		}
+
+		return self::$statusMark[0];
+	}
+}

+ 2 - 1
composer.json

@@ -19,7 +19,8 @@
         "yiisoft/yii2-bootstrap": "~2.0.0",
         "yiisoft/yii2-swiftmailer": "~2.0.0 || ~2.1.0",
         "php-amqplib/php-amqplib": "2.6.*",
-        "yiisoft/yii2-redis": "^2.0"
+        "yiisoft/yii2-redis": "^2.0",
+        "e282486518/yii2-console-migration": "*"
     },
     "require-dev": {
         "yiisoft/yii2-debug": "~2.0.0",

+ 0 - 3342
composer.lock

@@ -1,3342 +0,0 @@
-{
-    "_readme": [
-        "This file locks the dependencies of your project to a known state",
-        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
-        "This file is @generated automatically"
-    ],
-    "hash": "a7befa8ee039746425073d8946258e80",
-    "content-hash": "09cf6664195ab89b0ab4159ac984513f",
-    "packages": [
-        {
-            "name": "bower-asset/bootstrap",
-            "version": "v3.3.7",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/twbs/bootstrap.git",
-                "reference": "0b9c4a4007c44201dce9a6cc1a38407005c26c86"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/twbs/bootstrap/zipball/0b9c4a4007c44201dce9a6cc1a38407005c26c86",
-                "reference": "0b9c4a4007c44201dce9a6cc1a38407005c26c86",
-                "shasum": null
-            },
-            "require": {
-                "bower-asset/jquery": ">=1.9.1,<4.0"
-            },
-            "type": "bower-asset",
-            "license": [
-                "MIT"
-            ]
-        },
-        {
-            "name": "bower-asset/inputmask",
-            "version": "3.3.11",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/RobinHerbots/Inputmask.git",
-                "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/RobinHerbots/Inputmask/zipball/5e670ad62f50c738388d4dcec78d2888505ad77b",
-                "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b",
-                "shasum": null
-            },
-            "require": {
-                "bower-asset/jquery": ">=1.7"
-            },
-            "type": "bower-asset",
-            "license": [
-                "http://opensource.org/licenses/mit-license.php"
-            ]
-        },
-        {
-            "name": "bower-asset/jquery",
-            "version": "3.2.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/jquery/jquery-dist.git",
-                "reference": "77d2a51d0520d2ee44173afdf4e40a9201f5964e"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/77d2a51d0520d2ee44173afdf4e40a9201f5964e",
-                "reference": "77d2a51d0520d2ee44173afdf4e40a9201f5964e",
-                "shasum": null
-            },
-            "type": "bower-asset",
-            "license": [
-                "MIT"
-            ]
-        },
-        {
-            "name": "bower-asset/punycode",
-            "version": "v1.3.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/bestiejs/punycode.js.git",
-                "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3",
-                "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3",
-                "shasum": null
-            },
-            "type": "bower-asset"
-        },
-        {
-            "name": "bower-asset/yii2-pjax",
-            "version": "2.0.7.1",
-            "source": {
-                "type": "git",
-                "url": "git@github.com:yiisoft/jquery-pjax.git",
-                "reference": "aef7b953107264f00234902a3880eb50dafc48be"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/aef7b953107264f00234902a3880eb50dafc48be",
-                "reference": "aef7b953107264f00234902a3880eb50dafc48be",
-                "shasum": null
-            },
-            "require": {
-                "bower-asset/jquery": ">=1.8"
-            },
-            "type": "bower-asset",
-            "license": [
-                "MIT"
-            ]
-        },
-        {
-            "name": "cebe/markdown",
-            "version": "1.1.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/cebe/markdown.git",
-                "reference": "25b28bae8a6f185b5030673af77b32e1163d5c6e"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/cebe/markdown/25b28bae8a6f185b5030673af77b32e1163d5c6e.zip",
-                "reference": "25b28bae8a6f185b5030673af77b32e1163d5c6e",
-                "shasum": ""
-            },
-            "require": {
-                "lib-pcre": "*",
-                "php": ">=5.4.0"
-            },
-            "require-dev": {
-                "cebe/indent": "*",
-                "facebook/xhprof": "*@dev",
-                "phpunit/phpunit": "4.1.*"
-            },
-            "bin": [
-                "bin/markdown"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.1.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "cebe\\markdown\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Carsten Brandt",
-                    "email": "mail@cebe.cc",
-                    "homepage": "http://cebe.cc/",
-                    "role": "Creator"
-                }
-            ],
-            "description": "A super fast, highly extensible markdown parser for PHP",
-            "homepage": "https://github.com/cebe/markdown#readme",
-            "keywords": [
-                "extensible",
-                "fast",
-                "gfm",
-                "markdown",
-                "markdown-extra"
-            ],
-            "time": "2017-07-16 21:13:23"
-        },
-        {
-            "name": "doctrine/lexer",
-            "version": "v1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/doctrine/lexer.git",
-                "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/doctrine/lexer/83893c552fd2045dd78aef794c31e694c37c0b8c.zip",
-                "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.2"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Doctrine\\Common\\Lexer\\": "lib/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Roman Borschel",
-                    "email": "roman@code-factory.org"
-                },
-                {
-                    "name": "Guilherme Blanco",
-                    "email": "guilhermeblanco@gmail.com"
-                },
-                {
-                    "name": "Johannes Schmitt",
-                    "email": "schmittjoh@gmail.com"
-                }
-            ],
-            "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
-            "homepage": "http://www.doctrine-project.org",
-            "keywords": [
-                "lexer",
-                "parser"
-            ],
-            "time": "2014-09-09 13:34:57"
-        },
-        {
-            "name": "egulias/email-validator",
-            "version": "2.1.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/egulias/EmailValidator.git",
-                "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/egulias/EmailValidator/1bec00a10039b823cc94eef4eddd47dcd3b2ca04.zip",
-                "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04",
-                "shasum": ""
-            },
-            "require": {
-                "doctrine/lexer": "^1.0.1",
-                "php": ">= 5.5"
-            },
-            "require-dev": {
-                "dominicsayers/isemail": "dev-master",
-                "phpunit/phpunit": "^4.8.35",
-                "satooshi/php-coveralls": "^1.0.1"
-            },
-            "suggest": {
-                "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Egulias\\EmailValidator\\": "EmailValidator"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Eduardo Gulias Davis"
-                }
-            ],
-            "description": "A library for validating emails against several RFCs",
-            "homepage": "https://github.com/egulias/EmailValidator",
-            "keywords": [
-                "email",
-                "emailvalidation",
-                "emailvalidator",
-                "validation",
-                "validator"
-            ],
-            "time": "2017-11-15 23:40:40"
-        },
-        {
-            "name": "ezyang/htmlpurifier",
-            "version": "v4.9.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/ezyang/htmlpurifier.git",
-                "reference": "95e1bae3182efc0f3422896a3236e991049dac69"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/ezyang/htmlpurifier/95e1bae3182efc0f3422896a3236e991049dac69.zip",
-                "reference": "95e1bae3182efc0f3422896a3236e991049dac69",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.2"
-            },
-            "require-dev": {
-                "simpletest/simpletest": "^1.1"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-0": {
-                    "HTMLPurifier": "library/"
-                },
-                "files": [
-                    "library/HTMLPurifier.composer.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "LGPL"
-            ],
-            "authors": [
-                {
-                    "name": "Edward Z. Yang",
-                    "email": "admin@htmlpurifier.org",
-                    "homepage": "http://ezyang.com"
-                }
-            ],
-            "description": "Standards compliant HTML filter written in PHP",
-            "homepage": "http://htmlpurifier.org/",
-            "keywords": [
-                "html"
-            ],
-            "time": "2017-06-03 02:28:16"
-        },
-        {
-            "name": "php-amqplib/php-amqplib",
-            "version": "v2.6.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-amqplib/php-amqplib.git",
-                "reference": "fa2f0d4410a11008cb36b379177291be7ee9e4f6"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/php-amqplib/php-amqplib/fa2f0d4410a11008cb36b379177291be7ee9e4f6.zip",
-                "reference": "fa2f0d4410a11008cb36b379177291be7ee9e4f6",
-                "shasum": ""
-            },
-            "require": {
-                "ext-bcmath": "*",
-                "ext-mbstring": "*",
-                "php": ">=5.3.0"
-            },
-            "replace": {
-                "videlalvaro/php-amqplib": "self.version"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.8",
-                "scrutinizer/ocular": "^1.1",
-                "squizlabs/php_codesniffer": "^2.5"
-            },
-            "suggest": {
-                "ext-sockets": "Use AMQPSocketConnection"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.7-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "PhpAmqpLib\\": "PhpAmqpLib/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "LGPL-2.1"
-            ],
-            "authors": [
-                {
-                    "name": "Alvaro Videla",
-                    "role": "Original Maintainer"
-                },
-                {
-                    "name": "John Kelly",
-                    "email": "johnmkelly86@gmail.com",
-                    "role": "Maintainer"
-                },
-                {
-                    "name": "Raúl Araya",
-                    "email": "nubeiro@gmail.com",
-                    "role": "Maintainer"
-                }
-            ],
-            "description": "Formerly videlalvaro/php-amqplib.  This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.",
-            "homepage": "https://github.com/php-amqplib/php-amqplib/",
-            "keywords": [
-                "message",
-                "queue",
-                "rabbitmq"
-            ],
-            "time": "2016-04-11 14:30:01"
-        },
-        {
-            "name": "swiftmailer/swiftmailer",
-            "version": "v6.0.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/swiftmailer/swiftmailer.git",
-                "reference": "412333372fb6c8ffb65496a2bbd7321af75733fc"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/swiftmailer/swiftmailer/412333372fb6c8ffb65496a2bbd7321af75733fc.zip",
-                "reference": "412333372fb6c8ffb65496a2bbd7321af75733fc",
-                "shasum": ""
-            },
-            "require": {
-                "egulias/email-validator": "~2.0",
-                "php": ">=7.0.0"
-            },
-            "require-dev": {
-                "mockery/mockery": "~0.9.1",
-                "symfony/phpunit-bridge": "~3.3@dev"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "6.0-dev"
-                }
-            },
-            "autoload": {
-                "files": [
-                    "lib/swift_required.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Chris Corbyn"
-                },
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                }
-            ],
-            "description": "Swiftmailer, free feature-rich PHP mailer",
-            "homepage": "http://swiftmailer.symfony.com",
-            "keywords": [
-                "email",
-                "mail",
-                "mailer"
-            ],
-            "time": "2017-09-30 22:39:41"
-        },
-        {
-            "name": "yiisoft/yii2",
-            "version": "2.0.13.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/yiisoft/yii2-framework.git",
-                "reference": "7af96d8da5ea3e9a5dd05d0e734b21c5726a6ddf"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/yiisoft/yii2-framework/7af96d8da5ea3e9a5dd05d0e734b21c5726a6ddf.zip",
-                "reference": "7af96d8da5ea3e9a5dd05d0e734b21c5726a6ddf",
-                "shasum": ""
-            },
-            "require": {
-                "bower-asset/inputmask": "~3.2.2 | ~3.3.5",
-                "bower-asset/jquery": "3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
-                "bower-asset/punycode": "1.3.*",
-                "bower-asset/yii2-pjax": "~2.0.1",
-                "cebe/markdown": "~1.0.0 | ~1.1.0",
-                "ext-ctype": "*",
-                "ext-mbstring": "*",
-                "ezyang/htmlpurifier": "~4.6",
-                "lib-pcre": "*",
-                "php": ">=5.4.0",
-                "yiisoft/yii2-composer": "~2.0.4"
-            },
-            "bin": [
-                "yii"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "yii\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Qiang Xue",
-                    "email": "qiang.xue@gmail.com",
-                    "homepage": "http://www.yiiframework.com/",
-                    "role": "Founder and project lead"
-                },
-                {
-                    "name": "Alexander Makarov",
-                    "email": "sam@rmcreative.ru",
-                    "homepage": "http://rmcreative.ru/",
-                    "role": "Core framework development"
-                },
-                {
-                    "name": "Maurizio Domba",
-                    "homepage": "http://mdomba.info/",
-                    "role": "Core framework development"
-                },
-                {
-                    "name": "Carsten Brandt",
-                    "email": "mail@cebe.cc",
-                    "homepage": "http://cebe.cc/",
-                    "role": "Core framework development"
-                },
-                {
-                    "name": "Timur Ruziev",
-                    "email": "resurtm@gmail.com",
-                    "homepage": "http://resurtm.com/",
-                    "role": "Core framework development"
-                },
-                {
-                    "name": "Paul Klimov",
-                    "email": "klimov.paul@gmail.com",
-                    "role": "Core framework development"
-                },
-                {
-                    "name": "Dmitry Naumenko",
-                    "email": "d.naumenko.a@gmail.com",
-                    "role": "Core framework development"
-                },
-                {
-                    "name": "Boudewijn Vahrmeijer",
-                    "email": "info@dynasource.eu",
-                    "homepage": "http://dynasource.eu",
-                    "role": "Core framework development"
-                }
-            ],
-            "description": "Yii PHP Framework Version 2",
-            "homepage": "http://www.yiiframework.com/",
-            "keywords": [
-                "framework",
-                "yii2"
-            ],
-            "time": "2017-11-14 11:08:21"
-        },
-        {
-            "name": "yiisoft/yii2-bootstrap",
-            "version": "2.0.7",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/yiisoft/yii2-bootstrap.git",
-                "reference": "02a54d868343ed11d02f0f0f8cbbecb590e0cb3f"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/yiisoft/yii2-bootstrap/02a54d868343ed11d02f0f0f8cbbecb590e0cb3f.zip",
-                "reference": "02a54d868343ed11d02f0f0f8cbbecb590e0cb3f",
-                "shasum": ""
-            },
-            "require": {
-                "bower-asset/bootstrap": "3.3.* | 3.2.* | 3.1.*",
-                "yiisoft/yii2": "~2.0.6"
-            },
-            "type": "yii2-extension",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "yii\\bootstrap\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Qiang Xue",
-                    "email": "qiang.xue@gmail.com"
-                }
-            ],
-            "description": "The Twitter Bootstrap extension for the Yii framework",
-            "keywords": [
-                "bootstrap",
-                "yii2"
-            ],
-            "time": "2017-10-09 19:48:22"
-        },
-        {
-            "name": "yiisoft/yii2-composer",
-            "version": "2.0.5",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/yiisoft/yii2-composer.git",
-                "reference": "3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/yiisoft/yii2-composer/3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2.zip",
-                "reference": "3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2",
-                "shasum": ""
-            },
-            "require": {
-                "composer-plugin-api": "^1.0"
-            },
-            "require-dev": {
-                "composer/composer": "^1.0"
-            },
-            "type": "composer-plugin",
-            "extra": {
-                "class": "yii\\composer\\Plugin",
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "yii\\composer\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Qiang Xue",
-                    "email": "qiang.xue@gmail.com"
-                }
-            ],
-            "description": "The composer plugin for Yii extension installer",
-            "keywords": [
-                "composer",
-                "extension installer",
-                "yii2"
-            ],
-            "time": "2016-12-20 13:26:02"
-        },
-        {
-            "name": "yiisoft/yii2-redis",
-            "version": "2.0.7",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/yiisoft/yii2-redis.git",
-                "reference": "3891bb19f3ddc7ad744b439fe1d656ebb5b60a99"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/yiisoft/yii2-redis/3891bb19f3ddc7ad744b439fe1d656ebb5b60a99.zip",
-                "reference": "3891bb19f3ddc7ad744b439fe1d656ebb5b60a99",
-                "shasum": ""
-            },
-            "require": {
-                "yiisoft/yii2": "~2.0.13"
-            },
-            "type": "yii2-extension",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "yii\\redis\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Carsten Brandt",
-                    "email": "mail@cebe.cc"
-                }
-            ],
-            "description": "Redis Cache, Session and ActiveRecord for the Yii framework",
-            "keywords": [
-                "active-record",
-                "cache",
-                "redis",
-                "session",
-                "yii2"
-            ],
-            "time": "2017-12-11T21:17:34+00:00"
-        },
-        {
-            "name": "yiisoft/yii2-swiftmailer",
-            "version": "2.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/yiisoft/yii2-swiftmailer.git",
-                "reference": "563570c9aa19ca47c1b22e3032983229378e9274"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/yiisoft/yii2-swiftmailer/563570c9aa19ca47c1b22e3032983229378e9274.zip",
-                "reference": "563570c9aa19ca47c1b22e3032983229378e9274",
-                "shasum": ""
-            },
-            "require": {
-                "swiftmailer/swiftmailer": "~6.0",
-                "yiisoft/yii2": "~2.0.4"
-            },
-            "type": "yii2-extension",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "yii\\swiftmailer\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Paul Klimov",
-                    "email": "klimov.paul@gmail.com"
-                }
-            ],
-            "description": "The SwiftMailer integration for the Yii framework",
-            "keywords": [
-                "email",
-                "mail",
-                "mailer",
-                "swift",
-                "swiftmailer",
-                "yii2"
-            ],
-            "time": "2017-08-04 10:48:17"
-        }
-    ],
-    "packages-dev": [
-        {
-            "name": "behat/gherkin",
-            "version": "v4.4.5",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/Behat/Gherkin.git",
-                "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/Behat/Gherkin/5c14cff4f955b17d20d088dec1bde61c0539ec74.zip",
-                "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.1"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.5|~5",
-                "symfony/phpunit-bridge": "~2.7|~3",
-                "symfony/yaml": "~2.3|~3"
-            },
-            "suggest": {
-                "symfony/yaml": "If you want to parse features, represented in YAML files"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Behat\\Gherkin": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Konstantin Kudryashov",
-                    "email": "ever.zet@gmail.com",
-                    "homepage": "http://everzet.com"
-                }
-            ],
-            "description": "Gherkin DSL parser for PHP 5.3",
-            "homepage": "http://behat.org/",
-            "keywords": [
-                "BDD",
-                "Behat",
-                "Cucumber",
-                "DSL",
-                "gherkin",
-                "parser"
-            ],
-            "time": "2016-10-30 11:50:56"
-        },
-        {
-            "name": "bower-asset/typeahead.js",
-            "version": "v0.11.1",
-            "source": {
-                "type": "git",
-                "url": "git@github.com:twitter/typeahead.js.git",
-                "reference": "588440f66559714280628a4f9799f0c4eb880a4a"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/twitter/typeahead.js/zipball/588440f66559714280628a4f9799f0c4eb880a4a",
-                "reference": "588440f66559714280628a4f9799f0c4eb880a4a",
-                "shasum": null
-            },
-            "require": {
-                "bower-asset/jquery": ">=1.7"
-            },
-            "type": "bower-asset"
-        },
-        {
-            "name": "codeception/base",
-            "version": "2.3.7",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/Codeception/base.git",
-                "reference": "c3fcea61525e62361ecc45aea1837f225ba73b4f"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/Codeception/base/c3fcea61525e62361ecc45aea1837f225ba73b4f.zip",
-                "reference": "c3fcea61525e62361ecc45aea1837f225ba73b4f",
-                "shasum": ""
-            },
-            "require": {
-                "behat/gherkin": "~4.4.0",
-                "ext-json": "*",
-                "ext-mbstring": "*",
-                "guzzlehttp/psr7": "~1.0",
-                "php": ">=5.4.0 <8.0",
-                "phpunit/php-code-coverage": ">=2.2.4 <6.0",
-                "phpunit/phpunit": ">=4.8.28 <5.0.0 || >=5.6.3 <7.0",
-                "phpunit/phpunit-mock-objects": ">2.3 <5.0",
-                "sebastian/comparator": ">1.1 <3.0",
-                "sebastian/diff": ">=1.4 <3.0",
-                "symfony/browser-kit": ">=2.7 <5.0",
-                "symfony/console": ">=2.7 <5.0",
-                "symfony/css-selector": ">=2.7 <5.0",
-                "symfony/dom-crawler": ">=2.7 <5.0",
-                "symfony/event-dispatcher": ">=2.7 <5.0",
-                "symfony/finder": ">=2.7 <5.0",
-                "symfony/yaml": ">=2.7 <5.0"
-            },
-            "require-dev": {
-                "codeception/specify": "~0.3",
-                "facebook/graph-sdk": "~5.3",
-                "flow/jsonpath": "~0.2",
-                "league/factory-muffin": "^3.0",
-                "league/factory-muffin-faker": "^1.0",
-                "monolog/monolog": "~1.8",
-                "pda/pheanstalk": "~3.0",
-                "php-amqplib/php-amqplib": "~2.4",
-                "predis/predis": "^1.0",
-                "squizlabs/php_codesniffer": "~2.0",
-                "symfony/process": ">=2.7 <5.0",
-                "vlucas/phpdotenv": "^2.4.0"
-            },
-            "suggest": {
-                "aws/aws-sdk-php": "For using AWS Auth in REST module and Queue module",
-                "codeception/phpbuiltinserver": "Start and stop PHP built-in web server for your tests",
-                "codeception/specify": "BDD-style code blocks",
-                "codeception/verify": "BDD-style assertions",
-                "flow/jsonpath": "For using JSONPath in REST module",
-                "league/factory-muffin": "For DataFactory module",
-                "league/factory-muffin-faker": "For Faker support in DataFactory module",
-                "phpseclib/phpseclib": "for SFTP option in FTP Module",
-                "stecman/symfony-console-completion": "For BASH autocompletion",
-                "symfony/phpunit-bridge": "For phpunit-bridge support"
-            },
-            "bin": [
-                "codecept"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": []
-            },
-            "autoload": {
-                "psr-4": {
-                    "Codeception\\": "src\\Codeception",
-                    "Codeception\\Extension\\": "ext"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Michael Bodnarchuk",
-                    "email": "davert@mail.ua",
-                    "homepage": "http://codegyre.com"
-                }
-            ],
-            "description": "BDD-style testing framework",
-            "homepage": "http://codeception.com/",
-            "keywords": [
-                "BDD",
-                "TDD",
-                "acceptance testing",
-                "functional testing",
-                "unit testing"
-            ],
-            "time": "2017-12-12 04:54:15"
-        },
-        {
-            "name": "codeception/verify",
-            "version": "0.3.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/Codeception/Verify.git",
-                "reference": "5d649dda453cd814dadc4bb053060cd2c6bb4b4c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/Codeception/Verify/5d649dda453cd814dadc4bb053060cd2c6bb4b4c.zip",
-                "reference": "5d649dda453cd814dadc4bb053060cd2c6bb4b4c",
-                "shasum": ""
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.0"
-            },
-            "type": "library",
-            "autoload": {
-                "files": [
-                    "src/Codeception/function.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Michael Bodnarchuk",
-                    "email": "davert.php@mailican.com"
-                }
-            ],
-            "description": "BDD assertion library for PHPUnit",
-            "time": "2017-01-09 10:58:51"
-        },
-        {
-            "name": "doctrine/instantiator",
-            "version": "1.0.5",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/doctrine/instantiator.git",
-                "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/doctrine/instantiator/8e884e78f9f0eb1329e445619e04456e64d8051d.zip",
-                "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3,<8.0-DEV"
-            },
-            "require-dev": {
-                "athletic/athletic": "~0.1.8",
-                "ext-pdo": "*",
-                "ext-phar": "*",
-                "phpunit/phpunit": "~4.0",
-                "squizlabs/php_codesniffer": "~2.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Marco Pivetta",
-                    "email": "ocramius@gmail.com",
-                    "homepage": "http://ocramius.github.com/"
-                }
-            ],
-            "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
-            "homepage": "https://github.com/doctrine/instantiator",
-            "keywords": [
-                "constructor",
-                "instantiate"
-            ],
-            "time": "2015-06-14 21:17:01"
-        },
-        {
-            "name": "fzaninotto/faker",
-            "version": "v1.7.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/fzaninotto/Faker.git",
-                "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/fzaninotto/Faker/d3ed4cc37051c1ca52d22d76b437d14809fc7e0d.zip",
-                "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.3.3 || ^7.0"
-            },
-            "require-dev": {
-                "ext-intl": "*",
-                "phpunit/phpunit": "^4.0 || ^5.0",
-                "squizlabs/php_codesniffer": "^1.5"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.8-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Faker\\": "src/Faker/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "François Zaninotto"
-                }
-            ],
-            "description": "Faker is a PHP library that generates fake data for you.",
-            "keywords": [
-                "data",
-                "faker",
-                "fixtures"
-            ],
-            "time": "2017-08-15 16:48:10"
-        },
-        {
-            "name": "guzzlehttp/psr7",
-            "version": "1.4.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/guzzle/psr7.git",
-                "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/guzzle/psr7/f5b8a8512e2b58b0071a7280e39f14f72e05d87c.zip",
-                "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.4.0",
-                "psr/http-message": "~1.0"
-            },
-            "provide": {
-                "psr/http-message-implementation": "1.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "GuzzleHttp\\Psr7\\": "src/"
-                },
-                "files": [
-                    "src/functions_include.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Michael Dowling",
-                    "email": "mtdowling@gmail.com",
-                    "homepage": "https://github.com/mtdowling"
-                },
-                {
-                    "name": "Tobias Schultze",
-                    "homepage": "https://github.com/Tobion"
-                }
-            ],
-            "description": "PSR-7 message implementation that also provides common utility methods",
-            "keywords": [
-                "http",
-                "message",
-                "request",
-                "response",
-                "stream",
-                "uri",
-                "url"
-            ],
-            "time": "2017-03-20 17:10:46"
-        },
-        {
-            "name": "myclabs/deep-copy",
-            "version": "1.7.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/myclabs/DeepCopy.git",
-                "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/myclabs/DeepCopy/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e.zip",
-                "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.6 || ^7.0"
-            },
-            "require-dev": {
-                "doctrine/collections": "^1.0",
-                "doctrine/common": "^2.6",
-                "phpunit/phpunit": "^4.1"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "DeepCopy\\": "src/DeepCopy/"
-                },
-                "files": [
-                    "src/DeepCopy/deep_copy.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "description": "Create deep copies (clones) of your objects",
-            "keywords": [
-                "clone",
-                "copy",
-                "duplicate",
-                "object",
-                "object graph"
-            ],
-            "time": "2017-10-19 19:58:43"
-        },
-        {
-            "name": "phar-io/manifest",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phar-io/manifest.git",
-                "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/phar-io/manifest/2df402786ab5368a0169091f61a7c1e0eb6852d0.zip",
-                "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0",
-                "shasum": ""
-            },
-            "require": {
-                "ext-dom": "*",
-                "ext-phar": "*",
-                "phar-io/version": "^1.0.1",
-                "php": "^5.6 || ^7.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Arne Blankerts",
-                    "email": "arne@blankerts.de",
-                    "role": "Developer"
-                },
-                {
-                    "name": "Sebastian Heuer",
-                    "email": "sebastian@phpeople.de",
-                    "role": "Developer"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "Developer"
-                }
-            ],
-            "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
-            "time": "2017-03-05 18:14:27"
-        },
-        {
-            "name": "phar-io/version",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phar-io/version.git",
-                "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/phar-io/version/a70c0ced4be299a63d32fa96d9281d03e94041df.zip",
-                "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.6 || ^7.0"
-            },
-            "type": "library",
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Arne Blankerts",
-                    "email": "arne@blankerts.de",
-                    "role": "Developer"
-                },
-                {
-                    "name": "Sebastian Heuer",
-                    "email": "sebastian@phpeople.de",
-                    "role": "Developer"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "Developer"
-                }
-            ],
-            "description": "Library for handling version information and constraints",
-            "time": "2017-03-05 17:38:23"
-        },
-        {
-            "name": "phpdocumentor/reflection-common",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
-                "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/phpDocumentor/ReflectionCommon/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6.zip",
-                "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.5"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.6"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "phpDocumentor\\Reflection\\": [
-                        "src"
-                    ]
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Jaap van Otterdijk",
-                    "email": "opensource@ijaap.nl"
-                }
-            ],
-            "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
-            "homepage": "http://www.phpdoc.org",
-            "keywords": [
-                "FQSEN",
-                "phpDocumentor",
-                "phpdoc",
-                "reflection",
-                "static analysis"
-            ],
-            "time": "2017-09-11 18:02:19"
-        },
-        {
-            "name": "phpdocumentor/reflection-docblock",
-            "version": "4.2.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
-                "reference": "66465776cfc249844bde6d117abff1d22e06c2da"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/phpDocumentor/ReflectionDocBlock/66465776cfc249844bde6d117abff1d22e06c2da.zip",
-                "reference": "66465776cfc249844bde6d117abff1d22e06c2da",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0",
-                "phpdocumentor/reflection-common": "^1.0.0",
-                "phpdocumentor/type-resolver": "^0.4.0",
-                "webmozart/assert": "^1.0"
-            },
-            "require-dev": {
-                "doctrine/instantiator": "~1.0.5",
-                "mockery/mockery": "^1.0",
-                "phpunit/phpunit": "^6.4"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "phpDocumentor\\Reflection\\": [
-                        "src/"
-                    ]
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Mike van Riel",
-                    "email": "me@mikevanriel.com"
-                }
-            ],
-            "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
-            "time": "2017-11-27 17:38:31"
-        },
-        {
-            "name": "phpdocumentor/type-resolver",
-            "version": "0.4.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpDocumentor/TypeResolver.git",
-                "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/phpDocumentor/TypeResolver/9c977708995954784726e25d0cd1dddf4e65b0f7.zip",
-                "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5 || ^7.0",
-                "phpdocumentor/reflection-common": "^1.0"
-            },
-            "require-dev": {
-                "mockery/mockery": "^0.9.4",
-                "phpunit/phpunit": "^5.2||^4.8.24"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "phpDocumentor\\Reflection\\": [
-                        "src/"
-                    ]
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Mike van Riel",
-                    "email": "me@mikevanriel.com"
-                }
-            ],
-            "time": "2017-07-14 14:27:02"
-        },
-        {
-            "name": "phpspec/php-diff",
-            "version": "v1.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpspec/php-diff.git",
-                "reference": "0464787bfa7cd13576c5a1e318709768798bec6a"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/phpspec/php-diff/0464787bfa7cd13576c5a1e318709768798bec6a.zip",
-                "reference": "0464787bfa7cd13576c5a1e318709768798bec6a",
-                "shasum": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Diff": "lib/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Chris Boulton",
-                    "homepage": "http://github.com/chrisboulton"
-                }
-            ],
-            "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).",
-            "time": "2016-04-07 12:29:16"
-        },
-        {
-            "name": "phpspec/prophecy",
-            "version": "1.7.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpspec/prophecy.git",
-                "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/phpspec/prophecy/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf.zip",
-                "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
-                "shasum": ""
-            },
-            "require": {
-                "doctrine/instantiator": "^1.0.2",
-                "php": "^5.3|^7.0",
-                "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
-                "sebastian/comparator": "^1.1|^2.0",
-                "sebastian/recursion-context": "^1.0|^2.0|^3.0"
-            },
-            "require-dev": {
-                "phpspec/phpspec": "^2.5|^3.2",
-                "phpunit/phpunit": "^4.8.35 || ^5.7"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.7.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Prophecy\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Konstantin Kudryashov",
-                    "email": "ever.zet@gmail.com",
-                    "homepage": "http://everzet.com"
-                },
-                {
-                    "name": "Marcello Duarte",
-                    "email": "marcello.duarte@gmail.com"
-                }
-            ],
-            "description": "Highly opinionated mocking framework for PHP 5.3+",
-            "homepage": "https://github.com/phpspec/prophecy",
-            "keywords": [
-                "Double",
-                "Dummy",
-                "fake",
-                "mock",
-                "spy",
-                "stub"
-            ],
-            "time": "2017-11-24 13:59:53"
-        },
-        {
-            "name": "phpunit/php-code-coverage",
-            "version": "5.3.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/php-code-coverage/661f34d0bd3f1a7225ef491a70a020ad23a057a1.zip",
-                "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1",
-                "shasum": ""
-            },
-            "require": {
-                "ext-dom": "*",
-                "ext-xmlwriter": "*",
-                "php": "^7.0",
-                "phpunit/php-file-iterator": "^1.4.2",
-                "phpunit/php-text-template": "^1.2.1",
-                "phpunit/php-token-stream": "^2.0.1",
-                "sebastian/code-unit-reverse-lookup": "^1.0.1",
-                "sebastian/environment": "^3.0",
-                "sebastian/version": "^2.0.1",
-                "theseer/tokenizer": "^1.1"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.0"
-            },
-            "suggest": {
-                "ext-xdebug": "^2.5.5"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "5.3.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
-            "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
-            "keywords": [
-                "coverage",
-                "testing",
-                "xunit"
-            ],
-            "time": "2017-12-06 09:29:45"
-        },
-        {
-            "name": "phpunit/php-file-iterator",
-            "version": "1.4.5",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
-                "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/php-file-iterator/730b01bc3e867237eaac355e06a36b85dd93a8b4.zip",
-                "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.4.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "FilterIterator implementation that filters files based on a list of suffixes.",
-            "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
-            "keywords": [
-                "filesystem",
-                "iterator"
-            ],
-            "time": "2017-11-27 13:52:08"
-        },
-        {
-            "name": "phpunit/php-text-template",
-            "version": "1.2.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-text-template.git",
-                "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/php-text-template/31f8b717e51d9a2afca6c9f046f5d69fc27c8686.zip",
-                "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Simple template engine.",
-            "homepage": "https://github.com/sebastianbergmann/php-text-template/",
-            "keywords": [
-                "template"
-            ],
-            "time": "2015-06-21 13:50:34"
-        },
-        {
-            "name": "phpunit/php-timer",
-            "version": "1.0.9",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-timer.git",
-                "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/php-timer/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f.zip",
-                "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.3.3 || ^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Utility class for timing",
-            "homepage": "https://github.com/sebastianbergmann/php-timer/",
-            "keywords": [
-                "timer"
-            ],
-            "time": "2017-02-26 11:10:40"
-        },
-        {
-            "name": "phpunit/php-token-stream",
-            "version": "2.0.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-token-stream.git",
-                "reference": "791198a2c6254db10131eecfe8c06670700904db"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/php-token-stream/791198a2c6254db10131eecfe8c06670700904db.zip",
-                "reference": "791198a2c6254db10131eecfe8c06670700904db",
-                "shasum": ""
-            },
-            "require": {
-                "ext-tokenizer": "*",
-                "php": "^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.2.4"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Wrapper around PHP's tokenizer extension.",
-            "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
-            "keywords": [
-                "tokenizer"
-            ],
-            "time": "2017-11-27 05:48:46"
-        },
-        {
-            "name": "phpunit/phpunit",
-            "version": "6.4.4",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "562f7dc75d46510a4ed5d16189ae57fbe45a9932"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/phpunit/562f7dc75d46510a4ed5d16189ae57fbe45a9932.zip",
-                "reference": "562f7dc75d46510a4ed5d16189ae57fbe45a9932",
-                "shasum": ""
-            },
-            "require": {
-                "ext-dom": "*",
-                "ext-json": "*",
-                "ext-libxml": "*",
-                "ext-mbstring": "*",
-                "ext-xml": "*",
-                "myclabs/deep-copy": "^1.6.1",
-                "phar-io/manifest": "^1.0.1",
-                "phar-io/version": "^1.0",
-                "php": "^7.0",
-                "phpspec/prophecy": "^1.7",
-                "phpunit/php-code-coverage": "^5.2.2",
-                "phpunit/php-file-iterator": "^1.4.2",
-                "phpunit/php-text-template": "^1.2.1",
-                "phpunit/php-timer": "^1.0.9",
-                "phpunit/phpunit-mock-objects": "^4.0.3",
-                "sebastian/comparator": "^2.0.2",
-                "sebastian/diff": "^2.0",
-                "sebastian/environment": "^3.1",
-                "sebastian/exporter": "^3.1",
-                "sebastian/global-state": "^2.0",
-                "sebastian/object-enumerator": "^3.0.3",
-                "sebastian/resource-operations": "^1.0",
-                "sebastian/version": "^2.0.1"
-            },
-            "conflict": {
-                "phpdocumentor/reflection-docblock": "3.0.2",
-                "phpunit/dbunit": "<3.0"
-            },
-            "require-dev": {
-                "ext-pdo": "*"
-            },
-            "suggest": {
-                "ext-xdebug": "*",
-                "phpunit/php-invoker": "^1.1"
-            },
-            "bin": [
-                "phpunit"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "6.4.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "The PHP Unit Testing framework.",
-            "homepage": "https://phpunit.de/",
-            "keywords": [
-                "phpunit",
-                "testing",
-                "xunit"
-            ],
-            "time": "2017-11-08 11:26:09"
-        },
-        {
-            "name": "phpunit/phpunit-mock-objects",
-            "version": "4.0.4",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
-                "reference": "2f789b59ab89669015ad984afa350c4ec577ade0"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/phpunit-mock-objects/2f789b59ab89669015ad984afa350c4ec577ade0.zip",
-                "reference": "2f789b59ab89669015ad984afa350c4ec577ade0",
-                "shasum": ""
-            },
-            "require": {
-                "doctrine/instantiator": "^1.0.5",
-                "php": "^7.0",
-                "phpunit/php-text-template": "^1.2.1",
-                "sebastian/exporter": "^3.0"
-            },
-            "conflict": {
-                "phpunit/phpunit": "<6.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.0"
-            },
-            "suggest": {
-                "ext-soap": "*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Mock Object library for PHPUnit",
-            "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
-            "keywords": [
-                "mock",
-                "xunit"
-            ],
-            "time": "2017-08-03 14:08:16"
-        },
-        {
-            "name": "psr/http-message",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-fig/http-message.git",
-                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/php-fig/http-message/f6561bf28d520154e4b0ec72be95418abe6d9363.zip",
-                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Psr\\Http\\Message\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
-                }
-            ],
-            "description": "Common interface for HTTP messages",
-            "homepage": "https://github.com/php-fig/http-message",
-            "keywords": [
-                "http",
-                "http-message",
-                "psr",
-                "psr-7",
-                "request",
-                "response"
-            ],
-            "time": "2016-08-06 14:39:51"
-        },
-        {
-            "name": "psr/log",
-            "version": "1.0.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-fig/log.git",
-                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/php-fig/log/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d.zip",
-                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Psr\\Log\\": "Psr/Log/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
-                }
-            ],
-            "description": "Common interface for logging libraries",
-            "homepage": "https://github.com/php-fig/log",
-            "keywords": [
-                "log",
-                "psr",
-                "psr-3"
-            ],
-            "time": "2016-10-10 12:19:37"
-        },
-        {
-            "name": "sebastian/code-unit-reverse-lookup",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
-                "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/code-unit-reverse-lookup/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18.zip",
-                "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.6 || ^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^5.7 || ^6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Looks up which function or method a line of code belongs to",
-            "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
-            "time": "2017-03-04 06:30:41"
-        },
-        {
-            "name": "sebastian/comparator",
-            "version": "2.1.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/comparator.git",
-                "reference": "11c07feade1d65453e06df3b3b90171d6d982087"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/comparator/11c07feade1d65453e06df3b3b90171d6d982087.zip",
-                "reference": "11c07feade1d65453e06df3b3b90171d6d982087",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0",
-                "sebastian/diff": "^2.0",
-                "sebastian/exporter": "^3.1"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.4"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.1.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jeff Welch",
-                    "email": "whatthejeff@gmail.com"
-                },
-                {
-                    "name": "Volker Dusch",
-                    "email": "github@wallbash.com"
-                },
-                {
-                    "name": "Bernhard Schussek",
-                    "email": "bschussek@2bepublished.at"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Provides the functionality to compare PHP values for equality",
-            "homepage": "https://github.com/sebastianbergmann/comparator",
-            "keywords": [
-                "comparator",
-                "compare",
-                "equality"
-            ],
-            "time": "2018-01-12 06:34:42"
-        },
-        {
-            "name": "sebastian/diff",
-            "version": "2.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/diff.git",
-                "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/diff/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd.zip",
-                "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.2"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Kore Nordmann",
-                    "email": "mail@kore-nordmann.de"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Diff implementation",
-            "homepage": "https://github.com/sebastianbergmann/diff",
-            "keywords": [
-                "diff"
-            ],
-            "time": "2017-08-03 08:09:46"
-        },
-        {
-            "name": "sebastian/environment",
-            "version": "3.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/environment.git",
-                "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/environment/cd0871b3975fb7fc44d11314fd1ee20925fce4f5.zip",
-                "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.1"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.1.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Provides functionality to handle HHVM/PHP environments",
-            "homepage": "http://www.github.com/sebastianbergmann/environment",
-            "keywords": [
-                "Xdebug",
-                "environment",
-                "hhvm"
-            ],
-            "time": "2017-07-01 08:51:00"
-        },
-        {
-            "name": "sebastian/exporter",
-            "version": "3.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/exporter.git",
-                "reference": "234199f4528de6d12aaa58b612e98f7d36adb937"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/exporter/234199f4528de6d12aaa58b612e98f7d36adb937.zip",
-                "reference": "234199f4528de6d12aaa58b612e98f7d36adb937",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0",
-                "sebastian/recursion-context": "^3.0"
-            },
-            "require-dev": {
-                "ext-mbstring": "*",
-                "phpunit/phpunit": "^6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.1.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jeff Welch",
-                    "email": "whatthejeff@gmail.com"
-                },
-                {
-                    "name": "Volker Dusch",
-                    "email": "github@wallbash.com"
-                },
-                {
-                    "name": "Bernhard Schussek",
-                    "email": "bschussek@2bepublished.at"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                },
-                {
-                    "name": "Adam Harvey",
-                    "email": "aharvey@php.net"
-                }
-            ],
-            "description": "Provides the functionality to export PHP variables for visualization",
-            "homepage": "http://www.github.com/sebastianbergmann/exporter",
-            "keywords": [
-                "export",
-                "exporter"
-            ],
-            "time": "2017-04-03 13:19:02"
-        },
-        {
-            "name": "sebastian/global-state",
-            "version": "2.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/global-state.git",
-                "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/global-state/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4.zip",
-                "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.0"
-            },
-            "suggest": {
-                "ext-uopz": "*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Snapshotting of global state",
-            "homepage": "http://www.github.com/sebastianbergmann/global-state",
-            "keywords": [
-                "global state"
-            ],
-            "time": "2017-04-27 15:39:26"
-        },
-        {
-            "name": "sebastian/object-enumerator",
-            "version": "3.0.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/object-enumerator.git",
-                "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/object-enumerator/7cfd9e65d11ffb5af41198476395774d4c8a84c5.zip",
-                "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0",
-                "sebastian/object-reflector": "^1.1.1",
-                "sebastian/recursion-context": "^3.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Traverses array structures and object graphs to enumerate all referenced objects",
-            "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
-            "time": "2017-08-03 12:35:26"
-        },
-        {
-            "name": "sebastian/object-reflector",
-            "version": "1.1.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/object-reflector.git",
-                "reference": "773f97c67f28de00d397be301821b06708fca0be"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/object-reflector/773f97c67f28de00d397be301821b06708fca0be.zip",
-                "reference": "773f97c67f28de00d397be301821b06708fca0be",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.1-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Allows reflection of object attributes, including inherited and non-public ones",
-            "homepage": "https://github.com/sebastianbergmann/object-reflector/",
-            "time": "2017-03-29 09:07:27"
-        },
-        {
-            "name": "sebastian/recursion-context",
-            "version": "3.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/recursion-context.git",
-                "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/recursion-context/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8.zip",
-                "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jeff Welch",
-                    "email": "whatthejeff@gmail.com"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                },
-                {
-                    "name": "Adam Harvey",
-                    "email": "aharvey@php.net"
-                }
-            ],
-            "description": "Provides functionality to recursively process PHP variables",
-            "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
-            "time": "2017-03-03 06:23:57"
-        },
-        {
-            "name": "sebastian/resource-operations",
-            "version": "1.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/resource-operations.git",
-                "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/resource-operations/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52.zip",
-                "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Provides a list of PHP built-in functions that operate on resources",
-            "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
-            "time": "2015-07-28 20:34:47"
-        },
-        {
-            "name": "sebastian/version",
-            "version": "2.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/version.git",
-                "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/sebastianbergmann/version/99732be0ddb3361e16ad77b68ba41efc8e979019.zip",
-                "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.6"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Library that helps with managing the version number of Git-hosted PHP projects",
-            "homepage": "https://github.com/sebastianbergmann/version",
-            "time": "2016-10-03 07:35:21"
-        },
-        {
-            "name": "symfony/browser-kit",
-            "version": "v3.4.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/browser-kit.git",
-                "reference": "490f27762705c8489bd042fe3e9377a191dba9b4"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/symfony/browser-kit/490f27762705c8489bd042fe3e9377a191dba9b4.zip",
-                "reference": "490f27762705c8489bd042fe3e9377a191dba9b4",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5.9|>=7.0.8",
-                "symfony/dom-crawler": "~2.8|~3.0|~4.0"
-            },
-            "require-dev": {
-                "symfony/css-selector": "~2.8|~3.0|~4.0",
-                "symfony/process": "~2.8|~3.0|~4.0"
-            },
-            "suggest": {
-                "symfony/process": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\BrowserKit\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony BrowserKit Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-01-03 07:37:34"
-        },
-        {
-            "name": "symfony/console",
-            "version": "v3.4.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/console.git",
-                "reference": "8394c8ef121949e8f858f13bc1e34f05169e4e7d"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/symfony/console/8394c8ef121949e8f858f13bc1e34f05169e4e7d.zip",
-                "reference": "8394c8ef121949e8f858f13bc1e34f05169e4e7d",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5.9|>=7.0.8",
-                "symfony/debug": "~2.8|~3.0|~4.0",
-                "symfony/polyfill-mbstring": "~1.0"
-            },
-            "conflict": {
-                "symfony/dependency-injection": "<3.4",
-                "symfony/process": "<3.3"
-            },
-            "require-dev": {
-                "psr/log": "~1.0",
-                "symfony/config": "~3.3|~4.0",
-                "symfony/dependency-injection": "~3.4|~4.0",
-                "symfony/event-dispatcher": "~2.8|~3.0|~4.0",
-                "symfony/lock": "~3.4|~4.0",
-                "symfony/process": "~3.3|~4.0"
-            },
-            "suggest": {
-                "psr/log": "For using the console logger",
-                "symfony/event-dispatcher": "",
-                "symfony/lock": "",
-                "symfony/process": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Console\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Console Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-01-03 07:37:34"
-        },
-        {
-            "name": "symfony/css-selector",
-            "version": "v3.4.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/css-selector.git",
-                "reference": "e66394bc7610e69279bfdb3ab11b4fe65403f556"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/symfony/css-selector/e66394bc7610e69279bfdb3ab11b4fe65403f556.zip",
-                "reference": "e66394bc7610e69279bfdb3ab11b4fe65403f556",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5.9|>=7.0.8"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\CssSelector\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Jean-François Simon",
-                    "email": "jeanfrancois.simon@sensiolabs.com"
-                },
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony CssSelector Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-01-03 07:37:34"
-        },
-        {
-            "name": "symfony/debug",
-            "version": "v3.4.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/debug.git",
-                "reference": "603b95dda8b00020e4e6e60dc906e7b715b1c245"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/symfony/debug/603b95dda8b00020e4e6e60dc906e7b715b1c245.zip",
-                "reference": "603b95dda8b00020e4e6e60dc906e7b715b1c245",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5.9|>=7.0.8",
-                "psr/log": "~1.0"
-            },
-            "conflict": {
-                "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
-            },
-            "require-dev": {
-                "symfony/http-kernel": "~2.8|~3.0|~4.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Debug\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Debug Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-01-03 17:14:19"
-        },
-        {
-            "name": "symfony/dom-crawler",
-            "version": "v3.4.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/dom-crawler.git",
-                "reference": "09bd97b844b3151fab82f2fdd62db9c464b3910a"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/symfony/dom-crawler/09bd97b844b3151fab82f2fdd62db9c464b3910a.zip",
-                "reference": "09bd97b844b3151fab82f2fdd62db9c464b3910a",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5.9|>=7.0.8",
-                "symfony/polyfill-mbstring": "~1.0"
-            },
-            "require-dev": {
-                "symfony/css-selector": "~2.8|~3.0|~4.0"
-            },
-            "suggest": {
-                "symfony/css-selector": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\DomCrawler\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony DomCrawler Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-01-03 07:37:34"
-        },
-        {
-            "name": "symfony/event-dispatcher",
-            "version": "v3.4.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "26b87b6bca8f8f797331a30b76fdae5342dc26ca"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/symfony/event-dispatcher/26b87b6bca8f8f797331a30b76fdae5342dc26ca.zip",
-                "reference": "26b87b6bca8f8f797331a30b76fdae5342dc26ca",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5.9|>=7.0.8"
-            },
-            "conflict": {
-                "symfony/dependency-injection": "<3.3"
-            },
-            "require-dev": {
-                "psr/log": "~1.0",
-                "symfony/config": "~2.8|~3.0|~4.0",
-                "symfony/dependency-injection": "~3.3|~4.0",
-                "symfony/expression-language": "~2.8|~3.0|~4.0",
-                "symfony/stopwatch": "~2.8|~3.0|~4.0"
-            },
-            "suggest": {
-                "symfony/dependency-injection": "",
-                "symfony/http-kernel": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\EventDispatcher\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony EventDispatcher Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-01-03 07:37:34"
-        },
-        {
-            "name": "symfony/finder",
-            "version": "v3.4.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/finder.git",
-                "reference": "613e26310776f49a1773b6737c6bd554b8bc8c6f"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/symfony/finder/613e26310776f49a1773b6737c6bd554b8bc8c6f.zip",
-                "reference": "613e26310776f49a1773b6737c6bd554b8bc8c6f",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5.9|>=7.0.8"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Finder\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Finder Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-01-03 07:37:34"
-        },
-        {
-            "name": "symfony/polyfill-mbstring",
-            "version": "v1.6.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/symfony/polyfill-mbstring/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296.zip",
-                "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "suggest": {
-                "ext-mbstring": "For best performance"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.6-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Mbstring\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill for the Mbstring extension",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "mbstring",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "time": "2017-10-11 12:05:26"
-        },
-        {
-            "name": "symfony/yaml",
-            "version": "v3.4.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/yaml.git",
-                "reference": "25c192f25721a74084272671f658797d9e0e0146"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/symfony/yaml/25c192f25721a74084272671f658797d9e0e0146.zip",
-                "reference": "25c192f25721a74084272671f658797d9e0e0146",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5.9|>=7.0.8"
-            },
-            "conflict": {
-                "symfony/console": "<3.4"
-            },
-            "require-dev": {
-                "symfony/console": "~3.4|~4.0"
-            },
-            "suggest": {
-                "symfony/console": "For validating YAML files using the lint command"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Yaml\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Yaml Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-01-03 07:37:34"
-        },
-        {
-            "name": "theseer/tokenizer",
-            "version": "1.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/theseer/tokenizer.git",
-                "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/theseer/tokenizer/cb2f008f3f05af2893a87208fe6a6c4985483f8b.zip",
-                "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b",
-                "shasum": ""
-            },
-            "require": {
-                "ext-dom": "*",
-                "ext-tokenizer": "*",
-                "ext-xmlwriter": "*",
-                "php": "^7.0"
-            },
-            "type": "library",
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Arne Blankerts",
-                    "email": "arne@blankerts.de",
-                    "role": "Developer"
-                }
-            ],
-            "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
-            "time": "2017-04-07 12:08:54"
-        },
-        {
-            "name": "webmozart/assert",
-            "version": "1.2.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/webmozart/assert.git",
-                "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/webmozart/assert/2db61e59ff05fe5126d152bd0655c9ea113e550f.zip",
-                "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.3.3 || ^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.6",
-                "sebastian/version": "^1.0.1"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.3-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Webmozart\\Assert\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Bernhard Schussek",
-                    "email": "bschussek@gmail.com"
-                }
-            ],
-            "description": "Assertions to validate method input/output with nice error messages.",
-            "keywords": [
-                "assert",
-                "check",
-                "validate"
-            ],
-            "time": "2016-11-23 20:04:58"
-        },
-        {
-            "name": "yiisoft/yii2-debug",
-            "version": "2.0.13",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/yiisoft/yii2-debug.git",
-                "reference": "b37f414959c2fafefb332020b42037cd17c1cb7f"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/yiisoft/yii2-debug/b37f414959c2fafefb332020b42037cd17c1cb7f.zip",
-                "reference": "b37f414959c2fafefb332020b42037cd17c1cb7f",
-                "shasum": ""
-            },
-            "require": {
-                "yiisoft/yii2": "~2.0.13",
-                "yiisoft/yii2-bootstrap": "~2.0.0"
-            },
-            "type": "yii2-extension",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "yii\\debug\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Qiang Xue",
-                    "email": "qiang.xue@gmail.com"
-                }
-            ],
-            "description": "The debugger extension for the Yii framework",
-            "keywords": [
-                "debug",
-                "debugger",
-                "yii2"
-            ],
-            "time": "2017-12-05 07:36:23"
-        },
-        {
-            "name": "yiisoft/yii2-faker",
-            "version": "2.0.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/yiisoft/yii2-faker.git",
-                "reference": "b88ca69ee226a3610b2c26c026c3203d7ac50f6c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/yiisoft/yii2-faker/b88ca69ee226a3610b2c26c026c3203d7ac50f6c.zip",
-                "reference": "b88ca69ee226a3610b2c26c026c3203d7ac50f6c",
-                "shasum": ""
-            },
-            "require": {
-                "fzaninotto/faker": "*",
-                "yiisoft/yii2": "*"
-            },
-            "type": "yii2-extension",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "yii\\faker\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Mark Jebri",
-                    "email": "mark.github@yandex.ru"
-                }
-            ],
-            "description": "Fixture generator. The Faker integration for the Yii framework.",
-            "keywords": [
-                "Fixture",
-                "faker",
-                "yii2"
-            ],
-            "time": "2015-03-01 06:22:44"
-        },
-        {
-            "name": "yiisoft/yii2-gii",
-            "version": "2.0.6",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/yiisoft/yii2-gii.git",
-                "reference": "db41f647d9b73702ceb6864fdfce827a72b5ce42"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://files.phpcomposer.com/files/yiisoft/yii2-gii/db41f647d9b73702ceb6864fdfce827a72b5ce42.zip",
-                "reference": "db41f647d9b73702ceb6864fdfce827a72b5ce42",
-                "shasum": ""
-            },
-            "require": {
-                "bower-asset/typeahead.js": "0.10.* | ~0.11.0",
-                "phpspec/php-diff": ">=1.0.2",
-                "yiisoft/yii2": "~2.0.13",
-                "yiisoft/yii2-bootstrap": "~2.0.0"
-            },
-            "type": "yii2-extension",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                },
-                "asset-installer-paths": {
-                    "npm-asset-library": "vendor/npm",
-                    "bower-asset-library": "vendor/bower"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "yii\\gii\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Qiang Xue",
-                    "email": "qiang.xue@gmail.com"
-                }
-            ],
-            "description": "The Gii extension for the Yii framework",
-            "keywords": [
-                "code generator",
-                "gii",
-                "yii2"
-            ],
-            "time": "2017-12-22 23:53:06"
-        }
-    ],
-    "aliases": [],
-    "minimum-stability": "stable",
-    "stability-flags": [],
-    "prefer-stable": false,
-    "prefer-lowest": false,
-    "platform": {
-        "php": ">=5.4.0"
-    },
-    "platform-dev": []
-}

+ 24 - 0
console/controllers/BaseController.php

@@ -0,0 +1,24 @@
+<?php
+namespace console\controllers;
+
+use yii\console\Controller;
+
+/**
+ * 继承控制器
+ * Class BaseController
+ * @package console\controllers
+ */
+class BaseController extends Controller
+{
+	/*public function beforeAction($action)
+	{
+		return true;
+		//todo start log
+	}
+
+	public function afterAction($action, $result)
+	{
+		return true;
+		//todo end log
+	}*/
+}

+ 105 - 0
console/controllers/MainController.php

@@ -0,0 +1,105 @@
+<?php
+namespace console\controllers;
+
+use backend\models\WorkerScript;
+use yii\console\Controller;
+
+/**
+ * 主进程:保持运行
+ * Class MainController
+ * @package console\controllers
+ * @author: libingke
+ *
+ * @note 必须将主进程添加到crontab脚本里,最好间隔时间内运行
+ * 如=>  1 * * * *  php /项目路径/yii main >/dev/null 2>&1 &
+ */
+class MainController extends Controller
+{
+	const DURATION = 30;	//主进程检查间隔时间
+
+	/**
+	 * [init]
+	 */
+	public function actionIndex()
+	{
+		//如果Main进程已经在运行了,则不启动,保持主进程只有一个
+		if ($this->checkMainProcess()) {
+			echo "Main process is running. Please check it."; exit;
+		}
+
+		//每N秒检查一次任务列表
+		while (1) {
+			$this->checkTasks();
+			sleep(self::DURATION);
+		};
+	}
+
+	/**
+	 * 扫描所有任务
+	 */
+	public function checkTasks()
+	{
+		echo "\n Checking tasks......";
+		$list = WorkerScript::getRunScriptList();
+		foreach ($list as $task) {
+			if (!is_string($task['controller']) || !is_string($task['action'])) {
+				echo "\n this task has error!";
+				continue;
+			}
+
+			$program = $task['controller'] . '/' . $task['action'];
+			$this->execTask($program);
+		}
+	}
+
+	/**
+	 * 执行任务
+	 * @param $program
+	 * @return bool
+	 */
+	public function execTask($program)
+	{
+		//现在只支持单进程,如果以后支持多个进程同时运行,需要修改这里的逻辑
+		if ($this->checkProcess($program)) {
+			return false;
+		}
+		$dir = dirname(\Yii::$app->getBasePath());
+		//将任务放到后台执行
+		$cmd = "nohup php ".$dir."/yii " . $program." >/dev/null 2>&1 &";
+		echo "\n ".$cmd;
+		exec($cmd);
+	}
+
+	/**
+	 * 杀掉任务
+	 * @param $program
+	 */
+	public function killTask($program)
+	{
+		//避免误杀到其它(短字符的)进程
+		if (strlen($program) < 4)
+			return false;
+		$cmd = "ps -ef | grep " . $program . " | awk '{print $2}' | xargs kill -9";
+		exec($cmd);
+		return !$this->checkProcess($program);
+	}
+
+	/**
+	 * 检查是否进程中已经有别的主进程
+	 * @param $process
+	 * @return bool
+	 */
+	public function checkMainProcess()
+	{
+		$cmd = "ps -ef |grep -v grep|grep -v 'sh -c' | grep main";
+		exec($cmd, $output);
+		return count($output) > 1;
+	}
+
+	public function checkProcess($process)
+	{
+		$cmd = "ps -ef |grep -v grep|grep -v 'sh -c' | grep " . $process;
+		exec($cmd, $output);
+		return count($output) > 0;
+	}
+}

+ 141 - 0
console/controllers/WorkerMsgController.php

@@ -0,0 +1,141 @@
+<?php
+
+namespace console\controllers;
+
+use backend\models\Queue;
+use common\logic\Amqp\Cache;
+use common\logic\Amqp\Connect;
+use components\Curl;
+use Yii;
+
+/**
+ * 消息处理进程
+ * Class MessageController
+ * @package console\controllers
+ */
+class WorkerMsgController extends BaseController
+{
+	/**
+	 * @var null
+	 */
+	private $_conn = null;
+	/**
+	 * @return \PhpAmqpLib\Connection\AMQPStreamConnection
+	 */
+	protected function getConn()
+	{
+		if ($this->_conn == null) {
+			$this->_conn = new \PhpAmqpLib\Connection\AMQPStreamConnection(
+				Connect::HOST,
+				Connect::PORT,
+				Connect::USER,
+				Connect::PASS
+			);
+		}
+		return $this->_conn;
+	}
+
+	/**
+	 * [worker:登录处理]
+	 * @author: libingke
+	 */
+    public function actionLogin()
+    {
+    	$queue = Queue::find()->select('queue')->where(['sign' => 'licai_login'])->scalar();
+    	if (!$queue)
+    		exit("no login queue\r\n");
+
+    	$conn = $this->getConn();
+		$channel = $conn->channel();
+
+        $callback = function ($msg) use($queue) {
+        	$cacheTime = 600;
+			$status = Cache::STATUS_HAND_FAIL;
+			$corr_id = $msg->get('correlation_id');
+
+        	$post = json_decode($msg->body, true);
+        	//todo log
+			if (!is_array($post)) {
+				$data = ['code' => Cache::STATUS_HAND_FAIL, 'message' => '消息格式错误'];
+			} else {
+				//handle
+				if (isset($post['url'])) {
+					$url = $post['url'];
+					unset($post['url']);
+					$post['redirect_uri'] = 'https://zpapi.licai.cn';
+
+					$curl = new Curl();
+					$curl->setPostParams($post);
+					$result = json_decode($curl->post($url), true);
+
+					if (is_array($result) && isset($result['code'])) {
+						$cacheTime = isset($result['data']['expires_in']) ? $result['data']['expires_in'] : 600;
+						$status = Cache::STATUS_HAND_OK;
+						$data = $result;
+
+					} else {
+						$data = ['code' => Cache::STATUS_HAND_FAIL, 'message' => $curl->errorText];
+					}
+
+					echo "Done: " . $corr_id, "\n";
+					$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
+				} else {
+					$data = ['code' => Cache::STATUS_HAND_FAIL, 'message' => '消息格式错误[url error]'];
+				}
+			}
+
+			Cache::setData("{$queue}:mid:{$corr_id}", $status);
+			Cache::setData("result:{$queue}:mid:{$corr_id}", json_encode($data), $cacheTime);
+        };
+
+        $channel->basic_qos(null, 2, null);
+        $channel->basic_consume($queue, '', false, false, false, false, $callback);
+
+        while (count($channel->callbacks)) {
+            $channel->wait();
+        }
+
+        $channel->close();
+        $conn->close();
+    }
+
+    public function callback($msg)
+	{
+		echo "$msg---" . PHP_EOL;
+	}
+
+	public function actionTest()
+	{
+		$connect = new \PhpAmqpLib\Connection\AMQPStreamConnection(
+			'121.196.226.188',
+			'5672',
+			'lbk',
+			'123456',
+			Yii::$app->Amqp->vhost
+		);
+		$channel = $connect->channel();
+		$channel->queue_declare('login', false, true, false, false);
+
+		$callback = function ($msg) {
+			call_user_func_array([$this, 'callback'], ['22']);
+			//$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
+		};
+
+		$channel->basic_qos(0, 10, null);
+		$channel->basic_consume('login', '', false, false, false, false, $callback);
+
+		$i = 0;
+		while (count($channel->callbacks)) {
+			$channel->wait();
+
+			$i++;
+			echo $i . PHP_EOL;
+			list($q_name, $message_count, $t) = $channel->queue_declare('login',
+				false, true, false, false);
+			var_dump($message_count, $t);
+		}
+
+		$channel->close();
+		$connect->close();
+	}
+}

+ 2 - 0
console/migrations/README.md

@@ -0,0 +1,2 @@
+php yii migrate/backup all
+php yii migrate/up

+ 13 - 0
environments/dev/api/config/main-local.php

@@ -0,0 +1,13 @@
+<?php
+
+$config = [
+	'components' => [
+		'db' =>   require __DIR__ . '/../../common/config/db-local.php',
+		'request' => [
+			// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
+			'cookieValidationKey' => '',
+		],
+	]
+];
+
+return $config;

+ 3 - 0
environments/dev/api/config/params-local.php

@@ -0,0 +1,3 @@
+<?php
+return [
+];

+ 18 - 0
environments/dev/api/web/index-test.php

@@ -0,0 +1,18 @@
+<?php
+
+// NOTE: Make sure this file is not accessible when deployed to production
+if (!in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'])) {
+    die('You are not allowed to access this file.');
+}
+
+defined('YII_DEBUG') or define('YII_DEBUG', true);
+defined('YII_ENV') or define('YII_ENV', 'test');
+
+require __DIR__ . '/../../vendor/autoload.php';
+require __DIR__ . '/../../vendor/yiisoft/yii2/Yii.php';
+require __DIR__ . '/../../common/config/bootstrap.php';
+require __DIR__ . '/../config/bootstrap.php';
+
+$config = require __DIR__ . '/../config/test-local.php';
+
+(new yii\web\Application($config))->run();

+ 17 - 0
environments/dev/api/web/index.php

@@ -0,0 +1,17 @@
+<?php
+defined('YII_DEBUG') or define('YII_DEBUG', true);
+defined('YII_ENV') or define('YII_ENV', 'dev');
+
+require __DIR__ . '/../../vendor/autoload.php';
+require __DIR__ . '/../../vendor/yiisoft/yii2/Yii.php';
+require __DIR__ . '/../../common/config/bootstrap.php';
+require __DIR__ . '/../config/bootstrap.php';
+
+$config = yii\helpers\ArrayHelper::merge(
+    require __DIR__ . '/../../common/config/main.php',
+    require __DIR__ . '/../../common/config/main-local.php',
+    require __DIR__ . '/../config/main.php',
+    require __DIR__ . '/../config/main-local.php'
+);
+
+(new yii\web\Application($config))->run();

+ 2 - 0
environments/dev/api/web/robots.txt

@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /

+ 1 - 0
environments/dev/backend/config/main-local.php

@@ -2,6 +2,7 @@
 
 $config = [
     'components' => [
+		'db' =>   require __DIR__ . '/../../common/config/db-local.php',
         'request' => [
             // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
             'cookieValidationKey' => '',

+ 0 - 7
environments/dev/common/config/main-local.php

@@ -1,13 +1,6 @@
 <?php
 return [
     'components' => [
-        'db' => [
-            'class' => 'yii\db\Connection',
-            'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
-            'username' => 'root',
-            'password' => '',
-            'charset' => 'utf8',
-        ],
         'mailer' => [
             'class' => 'yii\swiftmailer\Mailer',
             'viewPath' => '@common/mail',

+ 3 - 0
environments/dev/console/config/main-local.php

@@ -1,5 +1,8 @@
 <?php
 return [
+	'components' => [
+		'db' =>   require __DIR__ . '/../../common/config/db-local.php',
+	],
     'bootstrap' => ['gii'],
     'modules' => [
         'gii' => 'yii\gii\Module',

+ 1 - 0
environments/dev/frontend/config/main-local.php

@@ -2,6 +2,7 @@
 
 $config = [
     'components' => [
+		'db' =>   require __DIR__ . '/../../common/config/db-local.php',
         'request' => [
             // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
             'cookieValidationKey' => '',

+ 6 - 0
environments/index.php

@@ -36,6 +36,8 @@ return [
             'backend/web/assets',
             'frontend/runtime',
             'frontend/web/assets',
+			'api/runtime',
+			'api/web/assets',
         ],
         'setExecutable' => [
             'yii',
@@ -44,6 +46,7 @@ return [
         'setCookieValidationKey' => [
             'backend/config/main-local.php',
             'frontend/config/main-local.php',
+			'api/config/main-local.php',
         ],
     ],
     'Production' => [
@@ -53,6 +56,8 @@ return [
             'backend/web/assets',
             'frontend/runtime',
             'frontend/web/assets',
+			'api/runtime',
+			'api/web/assets',
         ],
         'setExecutable' => [
             'yii',
@@ -60,6 +65,7 @@ return [
         'setCookieValidationKey' => [
             'backend/config/main-local.php',
             'frontend/config/main-local.php',
+			'api/config/main-local.php',
         ],
     ],
 ];

+ 9 - 0
environments/prod/api/config/main-local.php

@@ -0,0 +1,9 @@
+<?php
+return [
+    'components' => [
+        'request' => [
+            // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
+            'cookieValidationKey' => '',
+        ],
+    ],
+];

+ 3 - 0
environments/prod/api/config/params-local.php

@@ -0,0 +1,3 @@
+<?php
+return [
+];

+ 17 - 0
environments/prod/api/web/index.php

@@ -0,0 +1,17 @@
+<?php
+defined('YII_DEBUG') or define('YII_DEBUG', false);
+defined('YII_ENV') or define('YII_ENV', 'prod');
+
+require __DIR__ . '/../../vendor/autoload.php';
+require __DIR__ . '/../../vendor/yiisoft/yii2/Yii.php';
+require __DIR__ . '/../../common/config/bootstrap.php';
+require __DIR__ . '/../config/bootstrap.php';
+
+$config = yii\helpers\ArrayHelper::merge(
+    require __DIR__ . '/../../common/config/main.php',
+    require __DIR__ . '/../../common/config/main-local.php',
+    require __DIR__ . '/../config/main.php',
+    require __DIR__ . '/../config/main-local.php'
+);
+
+(new yii\web\Application($config))->run();

+ 2 - 0
environments/prod/api/web/robots.txt

@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /

+ 0 - 7
environments/prod/common/config/main-local.php

@@ -1,13 +1,6 @@
 <?php
 return [
     'components' => [
-        'db' => [
-            'class' => 'yii\db\Connection',
-            'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
-            'username' => 'root',
-            'password' => '',
-            'charset' => 'utf8',
-        ],
         'mailer' => [
             'class' => 'yii\swiftmailer\Mailer',
             'viewPath' => '@common/mail',

+ 4 - 0
frontend/web/.htaccess

@@ -0,0 +1,4 @@
+RewriteEngine On
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteRule . index.php