diff --git a/addons/weliam_smartcity/vendor/autoload.php b/addons/weliam_smartcity/vendor/autoload.php
new file mode 100644
index 0000000..403194b
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/autoload.php
@@ -0,0 +1,7 @@
+> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`; fi
+
+script:
+ - cd ext/pimple
+ - if [ "$PIMPLE_EXT" == "yes" ]; then yes n | make test | tee output ; grep -E 'Tests failed +. +0' output; fi
+ - if [ "$PIMPLE_EXT" == "yes" ]; then export SYMFONY_DEPRECATIONS_HELPER=weak; fi
+ - cd ../..
+ - ./vendor/bin/simple-phpunit
+
+matrix:
+ include:
+ - php: hhvm
+ dist: trusty
+ env: PIMPLE_EXT=no
+ exclude:
+ - php: 7.0
+ env: PIMPLE_EXT=yes
+ - php: 7.1
+ env: PIMPLE_EXT=yes
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/CHANGELOG b/addons/weliam_smartcity/vendor/pimple/pimple/CHANGELOG
new file mode 100644
index 0000000..ba56760
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/CHANGELOG
@@ -0,0 +1,59 @@
+* 3.2.3 (2017-XX-XX)
+
+ * n/a
+
+* 3.2.2 (2017-07-23)
+
+ * reverted extending a protected closure throws an exception (deprecated it instead)
+
+* 3.2.1 (2017-07-17)
+
+ * fixed PHP error
+
+* 3.2.0 (2017-07-17)
+
+ * added a PSR-11 service locator
+ * added a PSR-11 wrapper
+ * added ServiceIterator
+ * fixed extending a protected closure (now throws InvalidServiceIdentifierException)
+
+* 3.1.0 (2017-07-03)
+
+ * deprecated the C extension
+ * added support for PSR-11 exceptions
+
+* 3.0.2 (2015-09-11)
+
+ * refactored the C extension
+ * minor non-significant changes
+
+* 3.0.1 (2015-07-30)
+
+ * simplified some code
+ * fixed a segfault in the C extension
+
+* 3.0.0 (2014-07-24)
+
+ * removed the Pimple class alias (use Pimple\Container instead)
+
+* 2.1.1 (2014-07-24)
+
+ * fixed compiler warnings for the C extension
+ * fixed code when dealing with circular references
+
+* 2.1.0 (2014-06-24)
+
+ * moved the Pimple to Pimple\Container (with a BC layer -- Pimple is now a
+ deprecated alias which will be removed in Pimple 3.0)
+ * added Pimple\ServiceProviderInterface (and Pimple::register())
+
+* 2.0.0 (2014-02-10)
+
+ * changed extend to automatically re-assign the extended service and keep it as shared or factory
+ (to keep BC, extend still returns the extended service)
+ * changed services to be shared by default (use factory() for factory
+ services)
+
+* 1.0.0
+
+ * initial version
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/LICENSE b/addons/weliam_smartcity/vendor/pimple/pimple/LICENSE
new file mode 100644
index 0000000..e02dc5a
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2009-2017 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/README.rst b/addons/weliam_smartcity/vendor/pimple/pimple/README.rst
new file mode 100644
index 0000000..a03b6d3
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/README.rst
@@ -0,0 +1,326 @@
+Pimple
+======
+
+.. caution::
+
+ This is the documentation for Pimple 3.x. If you are using Pimple 1.x, read
+ the `Pimple 1.x documentation`_. Reading the Pimple 1.x code is also a good
+ way to learn more about how to create a simple Dependency Injection
+ Container (recent versions of Pimple are more focused on performance).
+
+Pimple is a small Dependency Injection Container for PHP.
+
+Installation
+------------
+
+Before using Pimple in your project, add it to your ``composer.json`` file:
+
+.. code-block:: bash
+
+ $ ./composer.phar require pimple/pimple "^3.0"
+
+Usage
+-----
+
+Creating a container is a matter of creating a ``Container`` instance:
+
+.. code-block:: php
+
+ use Pimple\Container;
+
+ $container = new Container();
+
+As many other dependency injection containers, Pimple manages two different
+kind of data: **services** and **parameters**.
+
+Defining Services
+~~~~~~~~~~~~~~~~~
+
+A service is an object that does something as part of a larger system. Examples
+of services: a database connection, a templating engine, or a mailer. Almost
+any **global** object can be a service.
+
+Services are defined by **anonymous functions** that return an instance of an
+object:
+
+.. code-block:: php
+
+ // define some services
+ $container['session_storage'] = function ($c) {
+ return new SessionStorage('SESSION_ID');
+ };
+
+ $container['session'] = function ($c) {
+ return new Session($c['session_storage']);
+ };
+
+Notice that the anonymous function has access to the current container
+instance, allowing references to other services or parameters.
+
+As objects are only created when you get them, the order of the definitions
+does not matter.
+
+Using the defined services is also very easy:
+
+.. code-block:: php
+
+ // get the session object
+ $session = $container['session'];
+
+ // the above call is roughly equivalent to the following code:
+ // $storage = new SessionStorage('SESSION_ID');
+ // $session = new Session($storage);
+
+Defining Factory Services
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default, each time you get a service, Pimple returns the **same instance**
+of it. If you want a different instance to be returned for all calls, wrap your
+anonymous function with the ``factory()`` method
+
+.. code-block:: php
+
+ $container['session'] = $container->factory(function ($c) {
+ return new Session($c['session_storage']);
+ });
+
+Now, each call to ``$container['session']`` returns a new instance of the
+session.
+
+Defining Parameters
+~~~~~~~~~~~~~~~~~~~
+
+Defining a parameter allows to ease the configuration of your container from
+the outside and to store global values:
+
+.. code-block:: php
+
+ // define some parameters
+ $container['cookie_name'] = 'SESSION_ID';
+ $container['session_storage_class'] = 'SessionStorage';
+
+If you change the ``session_storage`` service definition like below:
+
+.. code-block:: php
+
+ $container['session_storage'] = function ($c) {
+ return new $c['session_storage_class']($c['cookie_name']);
+ };
+
+You can now easily change the cookie name by overriding the
+``cookie_name`` parameter instead of redefining the service
+definition.
+
+Protecting Parameters
+~~~~~~~~~~~~~~~~~~~~~
+
+Because Pimple sees anonymous functions as service definitions, you need to
+wrap anonymous functions with the ``protect()`` method to store them as
+parameters:
+
+.. code-block:: php
+
+ $container['random_func'] = $container->protect(function () {
+ return rand();
+ });
+
+Modifying Services after Definition
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In some cases you may want to modify a service definition after it has been
+defined. You can use the ``extend()`` method to define additional code to be
+run on your service just after it is created:
+
+.. code-block:: php
+
+ $container['session_storage'] = function ($c) {
+ return new $c['session_storage_class']($c['cookie_name']);
+ };
+
+ $container->extend('session_storage', function ($storage, $c) {
+ $storage->...();
+
+ return $storage;
+ });
+
+The first argument is the name of the service to extend, the second a function
+that gets access to the object instance and the container.
+
+Extending a Container
+~~~~~~~~~~~~~~~~~~~~~
+
+If you use the same libraries over and over, you might want to reuse some
+services from one project to the next one; package your services into a
+**provider** by implementing ``Pimple\ServiceProviderInterface``:
+
+.. code-block:: php
+
+ use Pimple\Container;
+
+ class FooProvider implements Pimple\ServiceProviderInterface
+ {
+ public function register(Container $pimple)
+ {
+ // register some services and parameters
+ // on $pimple
+ }
+ }
+
+Then, register the provider on a Container:
+
+.. code-block:: php
+
+ $pimple->register(new FooProvider());
+
+Fetching the Service Creation Function
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When you access an object, Pimple automatically calls the anonymous function
+that you defined, which creates the service object for you. If you want to get
+raw access to this function, you can use the ``raw()`` method:
+
+.. code-block:: php
+
+ $container['session'] = function ($c) {
+ return new Session($c['session_storage']);
+ };
+
+ $sessionFunction = $container->raw('session');
+
+PSR-11 compatibility
+--------------------
+
+For historical reasons, the ``Container`` class does not implement the PSR-11
+``ContainerInterface``. However, Pimple provides a helper class that will let
+you decouple your code from the Pimple container class.
+
+The PSR-11 container class
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``Pimple\Psr11\Container`` class lets you access the content of an
+underlying Pimple container using ``Psr\Container\ContainerInterface``
+methods:
+
+.. code-block:: php
+
+ use Pimple\Container;
+ use Pimple\Psr11\Container as PsrContainer;
+
+ $container = new Container();
+ $container['service'] = function ($c) {
+ return new Service();
+ };
+ $psr11 = new PsrContainer($container);
+
+ $controller = function (PsrContainer $container) {
+ $service = $container->get('service');
+ };
+ $controller($psr11);
+
+Using the PSR-11 ServiceLocator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes, a service needs access to several other services without being sure
+that all of them will actually be used. In those cases, you may want the
+instantiation of the services to be lazy.
+
+The traditional solution is to inject the entire service container to get only
+the services really needed. However, this is not recommended because it gives
+services a too broad access to the rest of the application and it hides their
+actual dependencies.
+
+The ``ServiceLocator`` is intended to solve this problem by giving access to a
+set of predefined services while instantiating them only when actually needed.
+
+It also allows you to make your services available under a different name than
+the one used to register them. For instance, you may want to use an object
+that expects an instance of ``EventDispatcherInterface`` to be available under
+the name ``event_dispatcher`` while your event dispatcher has been
+registered under the name ``dispatcher``:
+
+.. code-block:: php
+
+ use Monolog\Logger;
+ use Pimple\Psr11\ServiceLocator;
+ use Psr\Container\ContainerInterface;
+ use Symfony\Component\EventDispatcher\EventDispatcher;
+
+ class MyService
+ {
+ /**
+ * "logger" must be an instance of Psr\Log\LoggerInterface
+ * "event_dispatcher" must be an instance of Symfony\Component\EventDispatcher\EventDispatcherInterface
+ */
+ private $services;
+
+ public function __construct(ContainerInterface $services)
+ {
+ $this->services = $services;
+ }
+ }
+
+ $container['logger'] = function ($c) {
+ return new Monolog\Logger();
+ };
+ $container['dispatcher'] = function () {
+ return new EventDispatcher();
+ };
+
+ $container['service'] = function ($c) {
+ $locator = new ServiceLocator($c, array('logger', 'event_dispatcher' => 'dispatcher'));
+
+ return new MyService($locator);
+ };
+
+Referencing a Collection of Services Lazily
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Passing a collection of services instances in an array may prove inefficient
+if the class that consumes the collection only needs to iterate over it at a
+later stage, when one of its method is called. It can also lead to problems
+if there is a circular dependency between one of the services stored in the
+collection and the class that consumes it.
+
+The ``ServiceIterator`` class helps you solve these issues. It receives a
+list of service names during instantiation and will retrieve the services
+when iterated over:
+
+.. code-block:: php
+
+ use Pimple\Container;
+ use Pimple\ServiceIterator;
+
+ class AuthorizationService
+ {
+ private $voters;
+
+ public function __construct($voters)
+ {
+ $this->voters = $voters;
+ }
+
+ public function canAccess($resource)
+ {
+ foreach ($this->voters as $voter) {
+ if (true === $voter->canAccess($resource) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ $container = new Container();
+
+ $container['voter1'] = function ($c) {
+ return new SomeVoter();
+ }
+ $container['voter2'] = function ($c) {
+ return new SomeOtherVoter($c['auth']);
+ }
+ $container['auth'] = function ($c) {
+ return new AuthorizationService(new ServiceIterator($c, array('voter1', 'voter2'));
+ }
+
+.. _Pimple 1.x documentation: https://github.com/silexphp/Pimple/tree/1.1
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/composer.json b/addons/weliam_smartcity/vendor/pimple/pimple/composer.json
new file mode 100644
index 0000000..dabf190
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "pimple/pimple",
+ "type": "library",
+ "description": "Pimple, a simple Dependency Injection Container",
+ "keywords": ["dependency injection", "container"],
+ "homepage": "http://pimple.sensiolabs.org",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0",
+ "psr/container": "^1.0"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "^3.2"
+ },
+ "autoload": {
+ "psr-0": { "Pimple": "src/" }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.2.x-dev"
+ }
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/.gitignore b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/.gitignore
new file mode 100644
index 0000000..1861088
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/.gitignore
@@ -0,0 +1,30 @@
+*.sw*
+.deps
+Makefile
+Makefile.fragments
+Makefile.global
+Makefile.objects
+acinclude.m4
+aclocal.m4
+build/
+config.cache
+config.guess
+config.h
+config.h.in
+config.log
+config.nice
+config.status
+config.sub
+configure
+configure.in
+install-sh
+libtool
+ltmain.sh
+missing
+mkinstalldirs
+run-tests.php
+*.loT
+.libs/
+modules/
+*.la
+*.lo
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/README.md b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/README.md
new file mode 100644
index 0000000..7b39eb2
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/README.md
@@ -0,0 +1,12 @@
+This is Pimple 2 implemented in C
+
+* PHP >= 5.3
+* Not tested under Windows, might work
+
+Install
+=======
+
+ > phpize
+ > ./configure
+ > make
+ > make install
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/config.m4 b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/config.m4
new file mode 100644
index 0000000..3a6e9aa
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/config.m4
@@ -0,0 +1,63 @@
+dnl $Id$
+dnl config.m4 for extension pimple
+
+dnl Comments in this file start with the string 'dnl'.
+dnl Remove where necessary. This file will not work
+dnl without editing.
+
+dnl If your extension references something external, use with:
+
+dnl PHP_ARG_WITH(pimple, for pimple support,
+dnl Make sure that the comment is aligned:
+dnl [ --with-pimple Include pimple support])
+
+dnl Otherwise use enable:
+
+PHP_ARG_ENABLE(pimple, whether to enable pimple support,
+dnl Make sure that the comment is aligned:
+[ --enable-pimple Enable pimple support])
+
+if test "$PHP_PIMPLE" != "no"; then
+ dnl Write more examples of tests here...
+
+ dnl # --with-pimple -> check with-path
+ dnl SEARCH_PATH="/usr/local /usr" # you might want to change this
+ dnl SEARCH_FOR="/include/pimple.h" # you most likely want to change this
+ dnl if test -r $PHP_PIMPLE/$SEARCH_FOR; then # path given as parameter
+ dnl PIMPLE_DIR=$PHP_PIMPLE
+ dnl else # search default path list
+ dnl AC_MSG_CHECKING([for pimple files in default path])
+ dnl for i in $SEARCH_PATH ; do
+ dnl if test -r $i/$SEARCH_FOR; then
+ dnl PIMPLE_DIR=$i
+ dnl AC_MSG_RESULT(found in $i)
+ dnl fi
+ dnl done
+ dnl fi
+ dnl
+ dnl if test -z "$PIMPLE_DIR"; then
+ dnl AC_MSG_RESULT([not found])
+ dnl AC_MSG_ERROR([Please reinstall the pimple distribution])
+ dnl fi
+
+ dnl # --with-pimple -> add include path
+ dnl PHP_ADD_INCLUDE($PIMPLE_DIR/include)
+
+ dnl # --with-pimple -> check for lib and symbol presence
+ dnl LIBNAME=pimple # you may want to change this
+ dnl LIBSYMBOL=pimple # you most likely want to change this
+
+ dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
+ dnl [
+ dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $PIMPLE_DIR/lib, PIMPLE_SHARED_LIBADD)
+ dnl AC_DEFINE(HAVE_PIMPLELIB,1,[ ])
+ dnl ],[
+ dnl AC_MSG_ERROR([wrong pimple lib version or lib not found])
+ dnl ],[
+ dnl -L$PIMPLE_DIR/lib -lm
+ dnl ])
+ dnl
+ dnl PHP_SUBST(PIMPLE_SHARED_LIBADD)
+
+ PHP_NEW_EXTENSION(pimple, pimple.c, $ext_shared)
+fi
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/config.w32 b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/config.w32
new file mode 100644
index 0000000..39857b3
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/config.w32
@@ -0,0 +1,13 @@
+// $Id$
+// vim:ft=javascript
+
+// If your extension references something external, use ARG_WITH
+// ARG_WITH("pimple", "for pimple support", "no");
+
+// Otherwise, use ARG_ENABLE
+// ARG_ENABLE("pimple", "enable pimple support", "no");
+
+if (PHP_PIMPLE != "no") {
+ EXTENSION("pimple", "pimple.c");
+}
+
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/php_pimple.h b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/php_pimple.h
new file mode 100644
index 0000000..eed7c17
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/php_pimple.h
@@ -0,0 +1,137 @@
+
+/*
+ * This file is part of Pimple.
+ *
+ * Copyright (c) 2014 Fabien Potencier
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef PHP_PIMPLE_H
+#define PHP_PIMPLE_H
+
+extern zend_module_entry pimple_module_entry;
+#define phpext_pimple_ptr &pimple_module_entry
+
+#ifdef PHP_WIN32
+# define PHP_PIMPLE_API __declspec(dllexport)
+#elif defined(__GNUC__) && __GNUC__ >= 4
+# define PHP_PIMPLE_API __attribute__ ((visibility("default")))
+#else
+# define PHP_PIMPLE_API
+#endif
+
+#ifdef ZTS
+#include "TSRM.h"
+#endif
+
+#define PIMPLE_VERSION "3.2.3-DEV"
+
+#define PIMPLE_NS "Pimple"
+#define PSR_CONTAINER_NS "Psr\\Container"
+#define PIMPLE_EXCEPTION_NS "Pimple\\Exception"
+
+#define PIMPLE_DEFAULT_ZVAL_CACHE_NUM 5
+#define PIMPLE_DEFAULT_ZVAL_VALUES_NUM 10
+
+#define PIMPLE_DEPRECATE do { \
+ int er = EG(error_reporting); \
+ EG(error_reporting) = 0;\
+ php_error(E_DEPRECATED, "The Pimple C extension is deprecated since version 3.1 and will be removed in 4.0."); \
+ EG(error_reporting) = er; \
+} while (0);
+
+zend_module_entry *get_module(void);
+
+PHP_MINIT_FUNCTION(pimple);
+PHP_MINFO_FUNCTION(pimple);
+
+PHP_METHOD(FrozenServiceException, __construct);
+PHP_METHOD(InvalidServiceIdentifierException, __construct);
+PHP_METHOD(UnknownIdentifierException, __construct);
+
+PHP_METHOD(Pimple, __construct);
+PHP_METHOD(Pimple, factory);
+PHP_METHOD(Pimple, protect);
+PHP_METHOD(Pimple, raw);
+PHP_METHOD(Pimple, extend);
+PHP_METHOD(Pimple, keys);
+PHP_METHOD(Pimple, register);
+PHP_METHOD(Pimple, offsetSet);
+PHP_METHOD(Pimple, offsetUnset);
+PHP_METHOD(Pimple, offsetGet);
+PHP_METHOD(Pimple, offsetExists);
+
+PHP_METHOD(PimpleClosure, invoker);
+
+typedef struct _pimple_bucket_value {
+ zval *value; /* Must be the first element */
+ zval *raw;
+ zend_object_handle handle_num;
+ enum {
+ PIMPLE_IS_PARAM = 0,
+ PIMPLE_IS_SERVICE = 2
+ } type;
+ zend_bool initialized;
+ zend_fcall_info_cache fcc;
+} pimple_bucket_value;
+
+typedef struct _pimple_object {
+ zend_object zobj;
+ HashTable values;
+ HashTable factories;
+ HashTable protected;
+} pimple_object;
+
+typedef struct _pimple_closure_object {
+ zend_object zobj;
+ zval *callable;
+ zval *factory;
+} pimple_closure_object;
+
+static const char sensiolabs_logo[] = "
";
+
+static void pimple_exception_call_parent_constructor(zval *this_ptr, const char *format, const char *arg1 TSRMLS_DC);
+
+static int pimple_zval_to_pimpleval(zval *_zval, pimple_bucket_value *_pimple_bucket_value TSRMLS_DC);
+static int pimple_zval_is_valid_callback(zval *_zval, pimple_bucket_value *_pimple_bucket_value TSRMLS_DC);
+
+static void pimple_bucket_dtor(pimple_bucket_value *bucket);
+static void pimple_free_bucket(pimple_bucket_value *bucket);
+
+static zval *pimple_object_read_dimension(zval *object, zval *offset, int type TSRMLS_DC);
+static void pimple_object_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC);
+static int pimple_object_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC);
+static void pimple_object_unset_dimension(zval *object, zval *offset TSRMLS_DC);
+static zend_object_value pimple_object_create(zend_class_entry *ce TSRMLS_DC);
+static void pimple_free_object_storage(pimple_object *obj TSRMLS_DC);
+
+static void pimple_closure_free_object_storage(pimple_closure_object *obj TSRMLS_DC);
+static zend_object_value pimple_closure_object_create(zend_class_entry *ce TSRMLS_DC);
+static zend_function *pimple_closure_get_constructor(zval * TSRMLS_DC);
+static int pimple_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, union _zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC);
+
+#ifdef ZTS
+#define PIMPLE_G(v) TSRMG(pimple_globals_id, zend_pimple_globals *, v)
+#else
+#define PIMPLE_G(v) (pimple_globals.v)
+#endif
+
+#endif /* PHP_PIMPLE_H */
+
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/pimple.c b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/pimple.c
new file mode 100644
index 0000000..c80499b
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/pimple.c
@@ -0,0 +1,1114 @@
+
+/*
+ * This file is part of Pimple.
+ *
+ * Copyright (c) 2014 Fabien Potencier
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "php_pimple.h"
+#include "pimple_compat.h"
+#include "zend_interfaces.h"
+#include "zend.h"
+#include "Zend/zend_closures.h"
+#include "ext/spl/spl_exceptions.h"
+#include "Zend/zend_exceptions.h"
+#include "main/php_output.h"
+#include "SAPI.h"
+
+static zend_class_entry *pimple_ce_PsrContainerInterface;
+static zend_class_entry *pimple_ce_PsrContainerExceptionInterface;
+static zend_class_entry *pimple_ce_PsrNotFoundExceptionInterface;
+
+static zend_class_entry *pimple_ce_ExpectedInvokableException;
+static zend_class_entry *pimple_ce_FrozenServiceException;
+static zend_class_entry *pimple_ce_InvalidServiceIdentifierException;
+static zend_class_entry *pimple_ce_UnknownIdentifierException;
+
+static zend_class_entry *pimple_ce;
+static zend_object_handlers pimple_object_handlers;
+static zend_class_entry *pimple_closure_ce;
+static zend_class_entry *pimple_serviceprovider_ce;
+static zend_object_handlers pimple_closure_object_handlers;
+static zend_internal_function pimple_closure_invoker_function;
+
+#define FETCH_DIM_HANDLERS_VARS pimple_object *pimple_obj = NULL; \
+ ulong index; \
+ pimple_obj = (pimple_object *)zend_object_store_get_object(object TSRMLS_CC); \
+
+#define PIMPLE_OBJECT_HANDLE_INHERITANCE_OBJECT_HANDLERS do { \
+ if (ce != pimple_ce) { \
+ zend_hash_find(&ce->function_table, ZEND_STRS("offsetget"), (void **)&function); \
+ if (function->common.scope != ce) { /* if the function is not defined in this actual class */ \
+ pimple_object_handlers.read_dimension = pimple_object_read_dimension; /* then overwrite the handler to use custom one */ \
+ } \
+ zend_hash_find(&ce->function_table, ZEND_STRS("offsetset"), (void **)&function); \
+ if (function->common.scope != ce) { \
+ pimple_object_handlers.write_dimension = pimple_object_write_dimension; \
+ } \
+ zend_hash_find(&ce->function_table, ZEND_STRS("offsetexists"), (void **)&function); \
+ if (function->common.scope != ce) { \
+ pimple_object_handlers.has_dimension = pimple_object_has_dimension; \
+ } \
+ zend_hash_find(&ce->function_table, ZEND_STRS("offsetunset"), (void **)&function); \
+ if (function->common.scope != ce) { \
+ pimple_object_handlers.unset_dimension = pimple_object_unset_dimension; \
+ } \
+ } else { \
+ pimple_object_handlers.read_dimension = pimple_object_read_dimension; \
+ pimple_object_handlers.write_dimension = pimple_object_write_dimension; \
+ pimple_object_handlers.has_dimension = pimple_object_has_dimension; \
+ pimple_object_handlers.unset_dimension = pimple_object_unset_dimension; \
+ }\
+ } while(0);
+
+#define PIMPLE_CALL_CB do { \
+ zend_fcall_info_argn(&fci TSRMLS_CC, 1, &object); \
+ fci.size = sizeof(fci); \
+ fci.object_ptr = retval->fcc.object_ptr; \
+ fci.function_name = retval->value; \
+ fci.no_separation = 1; \
+ fci.retval_ptr_ptr = &retval_ptr_ptr; \
+\
+ zend_call_function(&fci, &retval->fcc TSRMLS_CC); \
+ efree(fci.params); \
+ if (EG(exception)) { \
+ return EG(uninitialized_zval_ptr); \
+ } \
+ } while(0);
+
+
+/* Psr\Container\ContainerInterface */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_pimple_PsrContainerInterface_get, 0, 0, 1)
+ZEND_ARG_INFO(0, id)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_pimple_PsrContainerInterface_has, 0, 0, 1)
+ZEND_ARG_INFO(0, id)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry pimple_ce_PsrContainerInterface_functions[] = {
+ PHP_ABSTRACT_ME(ContainerInterface, get, arginfo_pimple_PsrContainerInterface_get)
+ PHP_ABSTRACT_ME(ContainerInterface, has, arginfo_pimple_PsrContainerInterface_has)
+ PHP_FE_END
+};
+
+/* Psr\Container\ContainerExceptionInterface */
+static const zend_function_entry pimple_ce_PsrContainerExceptionInterface_functions[] = {
+ PHP_FE_END
+};
+
+/* Psr\Container\NotFoundExceptionInterface */
+static const zend_function_entry pimple_ce_PsrNotFoundExceptionInterface_functions[] = {
+ PHP_FE_END
+};
+
+/* Pimple\Exception\FrozenServiceException */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_FrozenServiceException___construct, 0, 0, 1)
+ZEND_ARG_INFO(0, id)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry pimple_ce_FrozenServiceException_functions[] = {
+ PHP_ME(FrozenServiceException, __construct, arginfo_FrozenServiceException___construct, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+/* Pimple\Exception\InvalidServiceIdentifierException */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_InvalidServiceIdentifierException___construct, 0, 0, 1)
+ZEND_ARG_INFO(0, id)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry pimple_ce_InvalidServiceIdentifierException_functions[] = {
+ PHP_ME(InvalidServiceIdentifierException, __construct, arginfo_InvalidServiceIdentifierException___construct, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+/* Pimple\Exception\UnknownIdentifierException */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_UnknownIdentifierException___construct, 0, 0, 1)
+ZEND_ARG_INFO(0, id)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry pimple_ce_UnknownIdentifierException_functions[] = {
+ PHP_ME(UnknownIdentifierException, __construct, arginfo_UnknownIdentifierException___construct, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+/* Pimple\Container */
+ZEND_BEGIN_ARG_INFO_EX(arginfo___construct, 0, 0, 0)
+ZEND_ARG_ARRAY_INFO(0, value, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetset, 0, 0, 2)
+ZEND_ARG_INFO(0, offset)
+ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetget, 0, 0, 1)
+ZEND_ARG_INFO(0, offset)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetexists, 0, 0, 1)
+ZEND_ARG_INFO(0, offset)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetunset, 0, 0, 1)
+ZEND_ARG_INFO(0, offset)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_factory, 0, 0, 1)
+ZEND_ARG_INFO(0, callable)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_protect, 0, 0, 1)
+ZEND_ARG_INFO(0, callable)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_raw, 0, 0, 1)
+ZEND_ARG_INFO(0, id)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_extend, 0, 0, 2)
+ZEND_ARG_INFO(0, id)
+ZEND_ARG_INFO(0, callable)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_keys, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_register, 0, 0, 1)
+ZEND_ARG_OBJ_INFO(0, provider, Pimple\\ServiceProviderInterface, 0)
+ZEND_ARG_ARRAY_INFO(0, values, 1)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry pimple_ce_functions[] = {
+ PHP_ME(Pimple, __construct, arginfo___construct, ZEND_ACC_PUBLIC)
+ PHP_ME(Pimple, factory, arginfo_factory, ZEND_ACC_PUBLIC)
+ PHP_ME(Pimple, protect, arginfo_protect, ZEND_ACC_PUBLIC)
+ PHP_ME(Pimple, raw, arginfo_raw, ZEND_ACC_PUBLIC)
+ PHP_ME(Pimple, extend, arginfo_extend, ZEND_ACC_PUBLIC)
+ PHP_ME(Pimple, keys, arginfo_keys, ZEND_ACC_PUBLIC)
+ PHP_ME(Pimple, register, arginfo_register, ZEND_ACC_PUBLIC)
+
+ PHP_ME(Pimple, offsetSet, arginfo_offsetset, ZEND_ACC_PUBLIC)
+ PHP_ME(Pimple, offsetGet, arginfo_offsetget, ZEND_ACC_PUBLIC)
+ PHP_ME(Pimple, offsetExists, arginfo_offsetexists, ZEND_ACC_PUBLIC)
+ PHP_ME(Pimple, offsetUnset, arginfo_offsetunset, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+/* Pimple\ServiceProviderInterface */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_serviceprovider_register, 0, 0, 1)
+ZEND_ARG_OBJ_INFO(0, pimple, Pimple\\Container, 0)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry pimple_serviceprovider_iface_ce_functions[] = {
+ PHP_ABSTRACT_ME(ServiceProviderInterface, register, arginfo_serviceprovider_register)
+ PHP_FE_END
+};
+
+/* parent::__construct(sprintf("Something with %s", $arg1)) */
+static void pimple_exception_call_parent_constructor(zval *this_ptr, const char *format, const char *arg1 TSRMLS_DC)
+{
+ zend_class_entry *ce = Z_OBJCE_P(this_ptr);
+ char *message = NULL;
+ int message_len;
+ zval *constructor_arg;
+
+ message_len = spprintf(&message, 0, format, arg1);
+ ALLOC_INIT_ZVAL(constructor_arg);
+ ZVAL_STRINGL(constructor_arg, message, message_len, 1);
+
+ zend_call_method_with_1_params(&this_ptr, ce, &ce->parent->constructor, "__construct", NULL, constructor_arg);
+
+ efree(message);
+ zval_ptr_dtor(&constructor_arg);
+}
+
+/**
+ * Pass a single string parameter to exception constructor and throw
+ */
+static void pimple_throw_exception_string(zend_class_entry *ce, const char *message, zend_uint message_len TSRMLS_DC)
+{
+ zval *exception, *param;
+
+ ALLOC_INIT_ZVAL(exception);
+ object_init_ex(exception, ce);
+
+ ALLOC_INIT_ZVAL(param);
+ ZVAL_STRINGL(param, message, message_len, 1);
+
+ zend_call_method_with_1_params(&exception, ce, &ce->constructor, "__construct", NULL, param);
+
+ zend_throw_exception_object(exception TSRMLS_CC);
+
+ zval_ptr_dtor(¶m);
+}
+
+static void pimple_closure_free_object_storage(pimple_closure_object *obj TSRMLS_DC)
+{
+ zend_object_std_dtor(&obj->zobj TSRMLS_CC);
+ if (obj->factory) {
+ zval_ptr_dtor(&obj->factory);
+ }
+ if (obj->callable) {
+ zval_ptr_dtor(&obj->callable);
+ }
+ efree(obj);
+}
+
+static void pimple_free_object_storage(pimple_object *obj TSRMLS_DC)
+{
+ zend_hash_destroy(&obj->factories);
+ zend_hash_destroy(&obj->protected);
+ zend_hash_destroy(&obj->values);
+ zend_object_std_dtor(&obj->zobj TSRMLS_CC);
+ efree(obj);
+}
+
+static void pimple_free_bucket(pimple_bucket_value *bucket)
+{
+ if (bucket->raw) {
+ zval_ptr_dtor(&bucket->raw);
+ }
+}
+
+static zend_object_value pimple_closure_object_create(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value retval;
+ pimple_closure_object *pimple_closure_obj = NULL;
+
+ pimple_closure_obj = ecalloc(1, sizeof(pimple_closure_object));
+ ZEND_OBJ_INIT(&pimple_closure_obj->zobj, ce);
+
+ pimple_closure_object_handlers.get_constructor = pimple_closure_get_constructor;
+ retval.handlers = &pimple_closure_object_handlers;
+ retval.handle = zend_objects_store_put(pimple_closure_obj, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) pimple_closure_free_object_storage, NULL TSRMLS_CC);
+
+ return retval;
+}
+
+static zend_function *pimple_closure_get_constructor(zval *obj TSRMLS_DC)
+{
+ zend_error(E_ERROR, "Pimple\\ContainerClosure is an internal class and cannot be instantiated");
+
+ return NULL;
+}
+
+static int pimple_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, union _zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC)
+{
+ *zobj_ptr = obj;
+ *ce_ptr = Z_OBJCE_P(obj);
+ *fptr_ptr = (zend_function *)&pimple_closure_invoker_function;
+
+ return SUCCESS;
+}
+
+static zend_object_value pimple_object_create(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value retval;
+ pimple_object *pimple_obj = NULL;
+ zend_function *function = NULL;
+
+ pimple_obj = emalloc(sizeof(pimple_object));
+ ZEND_OBJ_INIT(&pimple_obj->zobj, ce);
+
+ PIMPLE_OBJECT_HANDLE_INHERITANCE_OBJECT_HANDLERS
+
+ retval.handlers = &pimple_object_handlers;
+ retval.handle = zend_objects_store_put(pimple_obj, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) pimple_free_object_storage, NULL TSRMLS_CC);
+
+ zend_hash_init(&pimple_obj->factories, PIMPLE_DEFAULT_ZVAL_CACHE_NUM, NULL, (dtor_func_t)pimple_bucket_dtor, 0);
+ zend_hash_init(&pimple_obj->protected, PIMPLE_DEFAULT_ZVAL_CACHE_NUM, NULL, (dtor_func_t)pimple_bucket_dtor, 0);
+ zend_hash_init(&pimple_obj->values, PIMPLE_DEFAULT_ZVAL_VALUES_NUM, NULL, (dtor_func_t)pimple_bucket_dtor, 0);
+
+ return retval;
+}
+
+static void pimple_object_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
+{
+ FETCH_DIM_HANDLERS_VARS
+
+ pimple_bucket_value pimple_value = {0}, *found_value = NULL;
+ ulong hash;
+
+ pimple_zval_to_pimpleval(value, &pimple_value TSRMLS_CC);
+
+ if (!offset) {/* $p[] = 'foo' when not overloaded */
+ zend_hash_next_index_insert(&pimple_obj->values, (void *)&pimple_value, sizeof(pimple_bucket_value), NULL);
+ Z_ADDREF_P(value);
+ return;
+ }
+
+ switch (Z_TYPE_P(offset)) {
+ case IS_STRING:
+ hash = zend_hash_func(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1);
+ zend_hash_quick_find(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, hash, (void **)&found_value);
+ if (found_value && found_value->type == PIMPLE_IS_SERVICE && found_value->initialized == 1) {
+ pimple_free_bucket(&pimple_value);
+ pimple_throw_exception_string(pimple_ce_FrozenServiceException, Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC);
+ return;
+ }
+ if (zend_hash_quick_update(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, hash, (void *)&pimple_value, sizeof(pimple_bucket_value), NULL) == FAILURE) {
+ pimple_free_bucket(&pimple_value);
+ return;
+ }
+ Z_ADDREF_P(value);
+ break;
+ case IS_DOUBLE:
+ case IS_BOOL:
+ case IS_LONG:
+ if (Z_TYPE_P(offset) == IS_DOUBLE) {
+ index = (ulong)Z_DVAL_P(offset);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+ zend_hash_index_find(&pimple_obj->values, index, (void **)&found_value);
+ if (found_value && found_value->type == PIMPLE_IS_SERVICE && found_value->initialized == 1) {
+ pimple_free_bucket(&pimple_value);
+ convert_to_string(offset);
+ pimple_throw_exception_string(pimple_ce_FrozenServiceException, Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC);
+ return;
+ }
+ if (zend_hash_index_update(&pimple_obj->values, index, (void *)&pimple_value, sizeof(pimple_bucket_value), NULL) == FAILURE) {
+ pimple_free_bucket(&pimple_value);
+ return;
+ }
+ Z_ADDREF_P(value);
+ break;
+ case IS_NULL: /* $p[] = 'foo' when overloaded */
+ zend_hash_next_index_insert(&pimple_obj->values, (void *)&pimple_value, sizeof(pimple_bucket_value), NULL);
+ Z_ADDREF_P(value);
+ break;
+ default:
+ pimple_free_bucket(&pimple_value);
+ zend_error(E_WARNING, "Unsupported offset type");
+ }
+}
+
+static void pimple_object_unset_dimension(zval *object, zval *offset TSRMLS_DC)
+{
+ FETCH_DIM_HANDLERS_VARS
+
+ switch (Z_TYPE_P(offset)) {
+ case IS_STRING:
+ zend_symtable_del(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1);
+ zend_symtable_del(&pimple_obj->factories, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1);
+ zend_symtable_del(&pimple_obj->protected, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1);
+ break;
+ case IS_DOUBLE:
+ case IS_BOOL:
+ case IS_LONG:
+ if (Z_TYPE_P(offset) == IS_DOUBLE) {
+ index = (ulong)Z_DVAL_P(offset);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+ zend_hash_index_del(&pimple_obj->values, index);
+ zend_hash_index_del(&pimple_obj->factories, index);
+ zend_hash_index_del(&pimple_obj->protected, index);
+ break;
+ default:
+ zend_error(E_WARNING, "Unsupported offset type");
+ }
+}
+
+static int pimple_object_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC)
+{
+ FETCH_DIM_HANDLERS_VARS
+
+ pimple_bucket_value *retval = NULL;
+
+ switch (Z_TYPE_P(offset)) {
+ case IS_STRING:
+ if (zend_symtable_find(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **)&retval) == SUCCESS) {
+ switch (check_empty) {
+ case 0: /* isset */
+ return 1; /* Differs from PHP behavior (Z_TYPE_P(retval->value) != IS_NULL;) */
+ case 1: /* empty */
+ default:
+ return zend_is_true(retval->value);
+ }
+ }
+ return 0;
+ break;
+ case IS_DOUBLE:
+ case IS_BOOL:
+ case IS_LONG:
+ if (Z_TYPE_P(offset) == IS_DOUBLE) {
+ index = (ulong)Z_DVAL_P(offset);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+ if (zend_hash_index_find(&pimple_obj->values, index, (void **)&retval) == SUCCESS) {
+ switch (check_empty) {
+ case 0: /* isset */
+ return 1; /* Differs from PHP behavior (Z_TYPE_P(retval->value) != IS_NULL;)*/
+ case 1: /* empty */
+ default:
+ return zend_is_true(retval->value);
+ }
+ }
+ return 0;
+ break;
+ default:
+ zend_error(E_WARNING, "Unsupported offset type");
+ return 0;
+ }
+}
+
+static zval *pimple_object_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
+{
+ FETCH_DIM_HANDLERS_VARS
+
+ pimple_bucket_value *retval = NULL;
+ zend_fcall_info fci = {0};
+ zval *retval_ptr_ptr = NULL;
+
+ switch (Z_TYPE_P(offset)) {
+ case IS_STRING:
+ if (zend_symtable_find(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **)&retval) == FAILURE) {
+ pimple_throw_exception_string(pimple_ce_UnknownIdentifierException, Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC);
+
+ return EG(uninitialized_zval_ptr);
+ }
+ break;
+ case IS_DOUBLE:
+ case IS_BOOL:
+ case IS_LONG:
+ if (Z_TYPE_P(offset) == IS_DOUBLE) {
+ index = (ulong)Z_DVAL_P(offset);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+ if (zend_hash_index_find(&pimple_obj->values, index, (void **)&retval) == FAILURE) {
+ return EG(uninitialized_zval_ptr);
+ }
+ break;
+ case IS_NULL: /* $p[][3] = 'foo' first dim access */
+ return EG(uninitialized_zval_ptr);
+ break;
+ default:
+ zend_error(E_WARNING, "Unsupported offset type");
+ return EG(uninitialized_zval_ptr);
+ }
+
+ if(retval->type == PIMPLE_IS_PARAM) {
+ return retval->value;
+ }
+
+ if (zend_hash_index_exists(&pimple_obj->protected, retval->handle_num)) {
+ /* Service is protected, return the value every time */
+ return retval->value;
+ }
+
+ if (zend_hash_index_exists(&pimple_obj->factories, retval->handle_num)) {
+ /* Service is a factory, call it every time and never cache its result */
+ PIMPLE_CALL_CB
+ Z_DELREF_P(retval_ptr_ptr); /* fetch dim addr will increment refcount */
+ return retval_ptr_ptr;
+ }
+
+ if (retval->initialized == 1) {
+ /* Service has already been called, return its cached value */
+ return retval->value;
+ }
+
+ ALLOC_INIT_ZVAL(retval->raw);
+ MAKE_COPY_ZVAL(&retval->value, retval->raw);
+
+ PIMPLE_CALL_CB
+
+ retval->initialized = 1;
+ zval_ptr_dtor(&retval->value);
+ retval->value = retval_ptr_ptr;
+
+ return retval->value;
+}
+
+static int pimple_zval_is_valid_callback(zval *_zval, pimple_bucket_value *_pimple_bucket_value TSRMLS_DC)
+{
+ if (Z_TYPE_P(_zval) != IS_OBJECT) {
+ return FAILURE;
+ }
+
+ if (_pimple_bucket_value->fcc.called_scope) {
+ return SUCCESS;
+ }
+
+ if (Z_OBJ_HANDLER_P(_zval, get_closure) && Z_OBJ_HANDLER_P(_zval, get_closure)(_zval, &_pimple_bucket_value->fcc.calling_scope, &_pimple_bucket_value->fcc.function_handler, &_pimple_bucket_value->fcc.object_ptr TSRMLS_CC) == SUCCESS) {
+ _pimple_bucket_value->fcc.called_scope = _pimple_bucket_value->fcc.calling_scope;
+ return SUCCESS;
+ } else {
+ return FAILURE;
+ }
+}
+
+static int pimple_zval_to_pimpleval(zval *_zval, pimple_bucket_value *_pimple_bucket_value TSRMLS_DC)
+{
+ _pimple_bucket_value->value = _zval;
+
+ if (Z_TYPE_P(_zval) != IS_OBJECT) {
+ return PIMPLE_IS_PARAM;
+ }
+
+ if (pimple_zval_is_valid_callback(_zval, _pimple_bucket_value TSRMLS_CC) == SUCCESS) {
+ _pimple_bucket_value->type = PIMPLE_IS_SERVICE;
+ _pimple_bucket_value->handle_num = Z_OBJ_HANDLE_P(_zval);
+ }
+
+ return PIMPLE_IS_SERVICE;
+}
+
+static void pimple_bucket_dtor(pimple_bucket_value *bucket)
+{
+ zval_ptr_dtor(&bucket->value);
+ pimple_free_bucket(bucket);
+}
+
+PHP_METHOD(FrozenServiceException, __construct)
+{
+ char *id = NULL;
+ int id_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &id, &id_len) == FAILURE) {
+ return;
+ }
+ pimple_exception_call_parent_constructor(getThis(), "Cannot override frozen service \"%s\".", id TSRMLS_CC);
+}
+
+PHP_METHOD(InvalidServiceIdentifierException, __construct)
+{
+ char *id = NULL;
+ int id_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &id, &id_len) == FAILURE) {
+ return;
+ }
+ pimple_exception_call_parent_constructor(getThis(), "Identifier \"%s\" does not contain an object definition.", id TSRMLS_CC);
+}
+
+PHP_METHOD(UnknownIdentifierException, __construct)
+{
+ char *id = NULL;
+ int id_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &id, &id_len) == FAILURE) {
+ return;
+ }
+ pimple_exception_call_parent_constructor(getThis(), "Identifier \"%s\" is not defined.", id TSRMLS_CC);
+}
+
+PHP_METHOD(Pimple, protect)
+{
+ zval *protected = NULL;
+ pimple_object *pobj = NULL;
+ pimple_bucket_value bucket = {0};
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &protected) == FAILURE) {
+ return;
+ }
+
+ if (pimple_zval_is_valid_callback(protected, &bucket TSRMLS_CC) == FAILURE) {
+ pimple_free_bucket(&bucket);
+ zend_throw_exception(pimple_ce_ExpectedInvokableException, "Callable is not a Closure or invokable object.", 0 TSRMLS_CC);
+ return;
+ }
+
+ pimple_zval_to_pimpleval(protected, &bucket TSRMLS_CC);
+ pobj = (pimple_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_hash_index_update(&pobj->protected, bucket.handle_num, (void *)&bucket, sizeof(pimple_bucket_value), NULL) == SUCCESS) {
+ Z_ADDREF_P(protected);
+ RETURN_ZVAL(protected, 1 , 0);
+ } else {
+ pimple_free_bucket(&bucket);
+ }
+ RETURN_FALSE;
+}
+
+PHP_METHOD(Pimple, raw)
+{
+ zval *offset = NULL;
+ pimple_object *pobj = NULL;
+ pimple_bucket_value *value = NULL;
+ ulong index;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &offset) == FAILURE) {
+ return;
+ }
+
+ pobj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ switch (Z_TYPE_P(offset)) {
+ case IS_STRING:
+ if (zend_symtable_find(&pobj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void *)&value) == FAILURE) {
+ pimple_throw_exception_string(pimple_ce_UnknownIdentifierException, Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC);
+ RETURN_NULL();
+ }
+ break;
+ case IS_DOUBLE:
+ case IS_BOOL:
+ case IS_LONG:
+ if (Z_TYPE_P(offset) == IS_DOUBLE) {
+ index = (ulong)Z_DVAL_P(offset);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+ if (zend_hash_index_find(&pobj->values, index, (void *)&value) == FAILURE) {
+ RETURN_NULL();
+ }
+ break;
+ case IS_NULL:
+ default:
+ zend_error(E_WARNING, "Unsupported offset type");
+ }
+
+ if (value->raw) {
+ RETVAL_ZVAL(value->raw, 1, 0);
+ } else {
+ RETVAL_ZVAL(value->value, 1, 0);
+ }
+}
+
+PHP_METHOD(Pimple, extend)
+{
+ zval *offset = NULL, *callable = NULL, *pimple_closure_obj = NULL;
+ pimple_bucket_value bucket = {0}, *value = NULL;
+ pimple_object *pobj = NULL;
+ pimple_closure_object *pcobj = NULL;
+ ulong index;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &offset, &callable) == FAILURE) {
+ return;
+ }
+
+ pobj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ switch (Z_TYPE_P(offset)) {
+ case IS_STRING:
+ if (zend_symtable_find(&pobj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void *)&value) == FAILURE) {
+ pimple_throw_exception_string(pimple_ce_UnknownIdentifierException, Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ if (value->type != PIMPLE_IS_SERVICE) {
+ pimple_throw_exception_string(pimple_ce_InvalidServiceIdentifierException, Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC);
+ RETURN_NULL();
+ }
+ if (zend_hash_index_exists(&pobj->protected, value->handle_num)) {
+ int er = EG(error_reporting);
+ EG(error_reporting) = 0;
+ php_error(E_DEPRECATED, "How Pimple behaves when extending protected closures will be fixed in Pimple 4. Are you sure \"%s\" should be protected?", Z_STRVAL_P(offset));
+ EG(error_reporting) = er;
+ }
+ break;
+ case IS_DOUBLE:
+ case IS_BOOL:
+ case IS_LONG:
+ if (Z_TYPE_P(offset) == IS_DOUBLE) {
+ index = (ulong)Z_DVAL_P(offset);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+ if (zend_hash_index_find(&pobj->values, index, (void *)&value) == FAILURE) {
+ convert_to_string(offset);
+ pimple_throw_exception_string(pimple_ce_UnknownIdentifierException, Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC);
+ RETURN_NULL();
+ }
+ if (value->type != PIMPLE_IS_SERVICE) {
+ convert_to_string(offset);
+ pimple_throw_exception_string(pimple_ce_InvalidServiceIdentifierException, Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC);
+ RETURN_NULL();
+ }
+ if (zend_hash_index_exists(&pobj->protected, value->handle_num)) {
+ int er = EG(error_reporting);
+ EG(error_reporting) = 0;
+ php_error(E_DEPRECATED, "How Pimple behaves when extending protected closures will be fixed in Pimple 4. Are you sure \"%ld\" should be protected?", index);
+ EG(error_reporting) = er;
+ }
+ break;
+ case IS_NULL:
+ default:
+ zend_error(E_WARNING, "Unsupported offset type");
+ }
+
+ if (pimple_zval_is_valid_callback(callable, &bucket TSRMLS_CC) == FAILURE) {
+ pimple_free_bucket(&bucket);
+ zend_throw_exception(pimple_ce_ExpectedInvokableException, "Extension service definition is not a Closure or invokable object.", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+ pimple_free_bucket(&bucket);
+
+ ALLOC_INIT_ZVAL(pimple_closure_obj);
+ object_init_ex(pimple_closure_obj, pimple_closure_ce);
+
+ pcobj = zend_object_store_get_object(pimple_closure_obj TSRMLS_CC);
+ pcobj->callable = callable;
+ pcobj->factory = value->value;
+ Z_ADDREF_P(callable);
+ Z_ADDREF_P(value->value);
+
+ if (zend_hash_index_exists(&pobj->factories, value->handle_num)) {
+ pimple_zval_to_pimpleval(pimple_closure_obj, &bucket TSRMLS_CC);
+ zend_hash_index_del(&pobj->factories, value->handle_num);
+ zend_hash_index_update(&pobj->factories, bucket.handle_num, (void *)&bucket, sizeof(pimple_bucket_value), NULL);
+ Z_ADDREF_P(pimple_closure_obj);
+ }
+
+ pimple_object_write_dimension(getThis(), offset, pimple_closure_obj TSRMLS_CC);
+
+ RETVAL_ZVAL(pimple_closure_obj, 1, 1);
+}
+
+PHP_METHOD(Pimple, keys)
+{
+ HashPosition pos;
+ pimple_object *pobj = NULL;
+ zval **value = NULL;
+ zval *endval = NULL;
+ char *str_index = NULL;
+ int str_len;
+ ulong num_index;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ pobj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ array_init_size(return_value, zend_hash_num_elements(&pobj->values));
+
+ zend_hash_internal_pointer_reset_ex(&pobj->values, &pos);
+
+ while(zend_hash_get_current_data_ex(&pobj->values, (void **)&value, &pos) == SUCCESS) {
+ MAKE_STD_ZVAL(endval);
+ switch (zend_hash_get_current_key_ex(&pobj->values, &str_index, (uint *)&str_len, &num_index, 0, &pos)) {
+ case HASH_KEY_IS_STRING:
+ ZVAL_STRINGL(endval, str_index, str_len - 1, 1);
+ zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &endval, sizeof(zval *), NULL);
+ break;
+ case HASH_KEY_IS_LONG:
+ ZVAL_LONG(endval, num_index);
+ zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &endval, sizeof(zval *), NULL);
+ break;
+ }
+ zend_hash_move_forward_ex(&pobj->values, &pos);
+ }
+}
+
+PHP_METHOD(Pimple, factory)
+{
+ zval *factory = NULL;
+ pimple_object *pobj = NULL;
+ pimple_bucket_value bucket = {0};
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &factory) == FAILURE) {
+ return;
+ }
+
+ if (pimple_zval_is_valid_callback(factory, &bucket TSRMLS_CC) == FAILURE) {
+ pimple_free_bucket(&bucket);
+ zend_throw_exception(pimple_ce_ExpectedInvokableException, "Service definition is not a Closure or invokable object.", 0 TSRMLS_CC);
+ return;
+ }
+
+ pimple_zval_to_pimpleval(factory, &bucket TSRMLS_CC);
+ pobj = (pimple_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_hash_index_update(&pobj->factories, bucket.handle_num, (void *)&bucket, sizeof(pimple_bucket_value), NULL) == SUCCESS) {
+ Z_ADDREF_P(factory);
+ RETURN_ZVAL(factory, 1 , 0);
+ } else {
+ pimple_free_bucket(&bucket);
+ }
+
+ RETURN_FALSE;
+}
+
+PHP_METHOD(Pimple, offsetSet)
+{
+ zval *offset = NULL, *value = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &offset, &value) == FAILURE) {
+ return;
+ }
+
+ pimple_object_write_dimension(getThis(), offset, value TSRMLS_CC);
+}
+
+PHP_METHOD(Pimple, offsetGet)
+{
+ zval *offset = NULL, *retval = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &offset) == FAILURE) {
+ return;
+ }
+
+ retval = pimple_object_read_dimension(getThis(), offset, 0 TSRMLS_CC);
+
+ RETVAL_ZVAL(retval, 1, 0);
+}
+
+PHP_METHOD(Pimple, offsetUnset)
+{
+ zval *offset = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &offset) == FAILURE) {
+ return;
+ }
+
+ pimple_object_unset_dimension(getThis(), offset TSRMLS_CC);
+}
+
+PHP_METHOD(Pimple, offsetExists)
+{
+ zval *offset = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &offset) == FAILURE) {
+ return;
+ }
+
+ RETVAL_BOOL(pimple_object_has_dimension(getThis(), offset, 1 TSRMLS_CC));
+}
+
+PHP_METHOD(Pimple, register)
+{
+ zval *provider;
+ zval **data;
+ zval *retval = NULL;
+ zval key;
+
+ HashTable *array = NULL;
+ HashPosition pos;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|h", &provider, pimple_serviceprovider_ce, &array) == FAILURE) {
+ return;
+ }
+
+ RETVAL_ZVAL(getThis(), 1, 0);
+
+ zend_call_method_with_1_params(&provider, Z_OBJCE_P(provider), NULL, "register", &retval, getThis());
+
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+
+ if (!array) {
+ return;
+ }
+
+ zend_hash_internal_pointer_reset_ex(array, &pos);
+
+ while(zend_hash_get_current_data_ex(array, (void **)&data, &pos) == SUCCESS) {
+ zend_hash_get_current_key_zval_ex(array, &key, &pos);
+ pimple_object_write_dimension(getThis(), &key, *data TSRMLS_CC);
+ zend_hash_move_forward_ex(array, &pos);
+ }
+}
+
+PHP_METHOD(Pimple, __construct)
+{
+ zval *values = NULL, **pData = NULL, offset;
+ HashPosition pos;
+ char *str_index = NULL;
+ zend_uint str_length;
+ ulong num_index;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &values) == FAILURE) {
+ return;
+ }
+
+ PIMPLE_DEPRECATE
+
+ if (!values) {
+ return;
+ }
+
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos);
+ while (zend_hash_has_more_elements_ex(Z_ARRVAL_P(values), &pos) == SUCCESS) {
+ zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&pData, &pos);
+ zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &str_index, &str_length, &num_index, 0, &pos);
+ INIT_ZVAL(offset);
+ if (zend_hash_get_current_key_type_ex(Z_ARRVAL_P(values), &pos) == HASH_KEY_IS_LONG) {
+ ZVAL_LONG(&offset, num_index);
+ } else {
+ ZVAL_STRINGL(&offset, str_index, (str_length - 1), 0);
+ }
+ pimple_object_write_dimension(getThis(), &offset, *pData TSRMLS_CC);
+ zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos);
+ }
+}
+
+/*
+ * This is PHP code snippet handling extend()s calls :
+
+ $extended = function ($c) use ($callable, $factory) {
+ return $callable($factory($c), $c);
+ };
+
+ */
+PHP_METHOD(PimpleClosure, invoker)
+{
+ pimple_closure_object *pcobj = NULL;
+ zval *arg = NULL, *retval = NULL, *newretval = NULL;
+ zend_fcall_info fci = {0};
+ zval **args[2];
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
+ return;
+ }
+
+ pcobj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ fci.function_name = pcobj->factory;
+ args[0] = &arg;
+ zend_fcall_info_argp(&fci TSRMLS_CC, 1, args);
+ fci.retval_ptr_ptr = &retval;
+ fci.size = sizeof(fci);
+
+ if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE || EG(exception)) {
+ efree(fci.params);
+ return; /* Should here return default zval */
+ }
+
+ efree(fci.params);
+ memset(&fci, 0, sizeof(fci));
+ fci.size = sizeof(fci);
+
+ fci.function_name = pcobj->callable;
+ args[0] = &retval;
+ args[1] = &arg;
+ zend_fcall_info_argp(&fci TSRMLS_CC, 2, args);
+ fci.retval_ptr_ptr = &newretval;
+
+ if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE || EG(exception)) {
+ efree(fci.params);
+ zval_ptr_dtor(&retval);
+ return;
+ }
+
+ efree(fci.params);
+ zval_ptr_dtor(&retval);
+
+ RETVAL_ZVAL(newretval, 1 ,1);
+}
+
+PHP_MINIT_FUNCTION(pimple)
+{
+ zend_class_entry tmp_ce_PsrContainerInterface, tmp_ce_PsrContainerExceptionInterface, tmp_ce_PsrNotFoundExceptionInterface;
+ zend_class_entry tmp_ce_ExpectedInvokableException, tmp_ce_FrozenServiceException, tmp_ce_InvalidServiceIdentifierException, tmp_ce_UnknownIdentifierException;
+ zend_class_entry tmp_pimple_ce, tmp_pimple_closure_ce, tmp_pimple_serviceprovider_iface_ce;
+
+ /* Psr\Container namespace */
+ INIT_NS_CLASS_ENTRY(tmp_ce_PsrContainerInterface, PSR_CONTAINER_NS, "ContainerInterface", pimple_ce_PsrContainerInterface_functions);
+ INIT_NS_CLASS_ENTRY(tmp_ce_PsrContainerExceptionInterface, PSR_CONTAINER_NS, "ContainerExceptionInterface", pimple_ce_PsrContainerExceptionInterface_functions);
+ INIT_NS_CLASS_ENTRY(tmp_ce_PsrNotFoundExceptionInterface, PSR_CONTAINER_NS, "NotFoundExceptionInterface", pimple_ce_PsrNotFoundExceptionInterface_functions);
+
+ pimple_ce_PsrContainerInterface = zend_register_internal_interface(&tmp_ce_PsrContainerInterface TSRMLS_CC);
+ pimple_ce_PsrContainerExceptionInterface = zend_register_internal_interface(&tmp_ce_PsrContainerExceptionInterface TSRMLS_CC);
+ pimple_ce_PsrNotFoundExceptionInterface = zend_register_internal_interface(&tmp_ce_PsrNotFoundExceptionInterface TSRMLS_CC);
+
+ zend_class_implements(pimple_ce_PsrNotFoundExceptionInterface TSRMLS_CC, 1, pimple_ce_PsrContainerExceptionInterface);
+
+ /* Pimple\Exception namespace */
+ INIT_NS_CLASS_ENTRY(tmp_ce_ExpectedInvokableException, PIMPLE_EXCEPTION_NS, "ExpectedInvokableException", NULL);
+ INIT_NS_CLASS_ENTRY(tmp_ce_FrozenServiceException, PIMPLE_EXCEPTION_NS, "FrozenServiceException", pimple_ce_FrozenServiceException_functions);
+ INIT_NS_CLASS_ENTRY(tmp_ce_InvalidServiceIdentifierException, PIMPLE_EXCEPTION_NS, "InvalidServiceIdentifierException", pimple_ce_InvalidServiceIdentifierException_functions);
+ INIT_NS_CLASS_ENTRY(tmp_ce_UnknownIdentifierException, PIMPLE_EXCEPTION_NS, "UnknownIdentifierException", pimple_ce_UnknownIdentifierException_functions);
+
+ pimple_ce_ExpectedInvokableException = zend_register_internal_class_ex(&tmp_ce_ExpectedInvokableException, spl_ce_InvalidArgumentException, NULL TSRMLS_CC);
+ pimple_ce_FrozenServiceException = zend_register_internal_class_ex(&tmp_ce_FrozenServiceException, spl_ce_RuntimeException, NULL TSRMLS_CC);
+ pimple_ce_InvalidServiceIdentifierException = zend_register_internal_class_ex(&tmp_ce_InvalidServiceIdentifierException, spl_ce_InvalidArgumentException, NULL TSRMLS_CC);
+ pimple_ce_UnknownIdentifierException = zend_register_internal_class_ex(&tmp_ce_UnknownIdentifierException, spl_ce_InvalidArgumentException, NULL TSRMLS_CC);
+
+ zend_class_implements(pimple_ce_ExpectedInvokableException TSRMLS_CC, 1, pimple_ce_PsrContainerExceptionInterface);
+ zend_class_implements(pimple_ce_FrozenServiceException TSRMLS_CC, 1, pimple_ce_PsrContainerExceptionInterface);
+ zend_class_implements(pimple_ce_InvalidServiceIdentifierException TSRMLS_CC, 1, pimple_ce_PsrContainerExceptionInterface);
+ zend_class_implements(pimple_ce_UnknownIdentifierException TSRMLS_CC, 1, pimple_ce_PsrNotFoundExceptionInterface);
+
+ /* Pimple namespace */
+ INIT_NS_CLASS_ENTRY(tmp_pimple_ce, PIMPLE_NS, "Container", pimple_ce_functions);
+ INIT_NS_CLASS_ENTRY(tmp_pimple_closure_ce, PIMPLE_NS, "ContainerClosure", NULL);
+ INIT_NS_CLASS_ENTRY(tmp_pimple_serviceprovider_iface_ce, PIMPLE_NS, "ServiceProviderInterface", pimple_serviceprovider_iface_ce_functions);
+
+ tmp_pimple_ce.create_object = pimple_object_create;
+ tmp_pimple_closure_ce.create_object = pimple_closure_object_create;
+
+ pimple_ce = zend_register_internal_class(&tmp_pimple_ce TSRMLS_CC);
+ zend_class_implements(pimple_ce TSRMLS_CC, 1, zend_ce_arrayaccess);
+
+ pimple_closure_ce = zend_register_internal_class(&tmp_pimple_closure_ce TSRMLS_CC);
+ pimple_closure_ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
+
+ pimple_serviceprovider_ce = zend_register_internal_interface(&tmp_pimple_serviceprovider_iface_ce TSRMLS_CC);
+
+ memcpy(&pimple_closure_object_handlers, zend_get_std_object_handlers(), sizeof(*zend_get_std_object_handlers()));
+ pimple_object_handlers = std_object_handlers;
+ pimple_closure_object_handlers.get_closure = pimple_closure_get_closure;
+
+ pimple_closure_invoker_function.function_name = "Pimple closure internal invoker";
+ pimple_closure_invoker_function.fn_flags |= ZEND_ACC_CLOSURE;
+ pimple_closure_invoker_function.handler = ZEND_MN(PimpleClosure_invoker);
+ pimple_closure_invoker_function.num_args = 1;
+ pimple_closure_invoker_function.required_num_args = 1;
+ pimple_closure_invoker_function.scope = pimple_closure_ce;
+ pimple_closure_invoker_function.type = ZEND_INTERNAL_FUNCTION;
+ pimple_closure_invoker_function.module = &pimple_module_entry;
+
+ return SUCCESS;
+}
+
+PHP_MINFO_FUNCTION(pimple)
+{
+ php_info_print_table_start();
+ php_info_print_table_header(2, "SensioLabs Pimple C support", "enabled");
+ php_info_print_table_row(2, "Pimple supported version", PIMPLE_VERSION);
+ php_info_print_table_end();
+
+ php_info_print_box_start(0);
+ php_write((void *)ZEND_STRL("SensioLabs Pimple C support developed by Julien Pauli") TSRMLS_CC);
+ if (!sapi_module.phpinfo_as_text) {
+ php_write((void *)ZEND_STRL(sensiolabs_logo) TSRMLS_CC);
+ }
+ php_info_print_box_end();
+}
+
+zend_module_entry pimple_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "pimple",
+ NULL,
+ PHP_MINIT(pimple),
+ NULL,
+ NULL,
+ NULL,
+ PHP_MINFO(pimple),
+ PIMPLE_VERSION,
+ STANDARD_MODULE_PROPERTIES
+};
+
+#ifdef COMPILE_DL_PIMPLE
+ZEND_GET_MODULE(pimple)
+#endif
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/pimple_compat.h b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/pimple_compat.h
new file mode 100644
index 0000000..d234e17
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/pimple_compat.h
@@ -0,0 +1,81 @@
+
+/*
+ * This file is part of Pimple.
+ *
+ * Copyright (c) 2014 Fabien Potencier
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef PIMPLE_COMPAT_H_
+#define PIMPLE_COMPAT_H_
+
+#include "Zend/zend_extensions.h" /* for ZEND_EXTENSION_API_NO */
+
+#define PHP_5_0_X_API_NO 220040412
+#define PHP_5_1_X_API_NO 220051025
+#define PHP_5_2_X_API_NO 220060519
+#define PHP_5_3_X_API_NO 220090626
+#define PHP_5_4_X_API_NO 220100525
+#define PHP_5_5_X_API_NO 220121212
+#define PHP_5_6_X_API_NO 220131226
+
+#define IS_PHP_56 ZEND_EXTENSION_API_NO == PHP_5_6_X_API_NO
+#define IS_AT_LEAST_PHP_56 ZEND_EXTENSION_API_NO >= PHP_5_6_X_API_NO
+
+#define IS_PHP_55 ZEND_EXTENSION_API_NO == PHP_5_5_X_API_NO
+#define IS_AT_LEAST_PHP_55 ZEND_EXTENSION_API_NO >= PHP_5_5_X_API_NO
+
+#define IS_PHP_54 ZEND_EXTENSION_API_NO == PHP_5_4_X_API_NO
+#define IS_AT_LEAST_PHP_54 ZEND_EXTENSION_API_NO >= PHP_5_4_X_API_NO
+
+#define IS_PHP_53 ZEND_EXTENSION_API_NO == PHP_5_3_X_API_NO
+#define IS_AT_LEAST_PHP_53 ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
+
+#if IS_PHP_53
+#define object_properties_init(obj, ce) do { \
+ zend_hash_copy(obj->properties, &ce->default_properties, zval_copy_property_ctor(ce), NULL, sizeof(zval *)); \
+ } while (0);
+#endif
+
+#define ZEND_OBJ_INIT(obj, ce) do { \
+ zend_object_std_init(obj, ce TSRMLS_CC); \
+ object_properties_init((obj), (ce)); \
+ } while(0);
+
+#if IS_PHP_53 || IS_PHP_54
+static void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos) {
+ Bucket *p;
+
+ p = pos ? (*pos) : ht->pInternalPointer;
+
+ if (!p) {
+ Z_TYPE_P(key) = IS_NULL;
+ } else if (p->nKeyLength) {
+ Z_TYPE_P(key) = IS_STRING;
+ Z_STRVAL_P(key) = estrndup(p->arKey, p->nKeyLength - 1);
+ Z_STRLEN_P(key) = p->nKeyLength - 1;
+ } else {
+ Z_TYPE_P(key) = IS_LONG;
+ Z_LVAL_P(key) = p->h;
+ }
+}
+#endif
+
+#endif /* PIMPLE_COMPAT_H_ */
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/001.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/001.phpt
new file mode 100644
index 0000000..0809ea2
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/001.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Test for read_dim/write_dim handlers
+--SKIPIF--
+
+--FILE--
+
+
+--EXPECTF--
+foo
+42
+foo2
+foo99
+baz
+strstr
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/002.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/002.phpt
new file mode 100644
index 0000000..7b56d2c
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/002.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test for constructor
+--SKIPIF--
+
+--FILE--
+'foo'));
+var_dump($p[42]);
+?>
+--EXPECT--
+NULL
+string(3) "foo"
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/003.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/003.phpt
new file mode 100644
index 0000000..a22cfa3
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/003.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Test empty dimensions
+--SKIPIF--
+
+--FILE--
+
+--EXPECT--
+int(42)
+string(3) "bar"
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/004.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/004.phpt
new file mode 100644
index 0000000..1e1d251
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/004.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Test has/unset dim handlers
+--SKIPIF--
+
+--FILE--
+
+--EXPECT--
+int(42)
+NULL
+bool(true)
+bool(false)
+bool(true)
+bool(true)
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/005.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/005.phpt
new file mode 100644
index 0000000..0479ee0
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/005.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Test simple class inheritance
+--SKIPIF--
+
+--FILE--
+someAttr;
+?>
+--EXPECT--
+string(3) "hit"
+foo
+fooAttr
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/006.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/006.phpt
new file mode 100644
index 0000000..cfe8a11
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/006.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Test complex class inheritance
+--SKIPIF--
+
+--FILE--
+ 'bar', 88 => 'baz');
+
+$p = new TestPimple($defaultValues);
+$p[42] = 'foo';
+var_dump($p[42]);
+var_dump($p[0]);
+?>
+--EXPECT--
+string(13) "hit offsetset"
+string(27) "hit offsetget in TestPimple"
+string(25) "hit offsetget in MyPimple"
+string(3) "foo"
+string(27) "hit offsetget in TestPimple"
+string(25) "hit offsetget in MyPimple"
+string(3) "baz"
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/007.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/007.phpt
new file mode 100644
index 0000000..5aac683
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/007.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Test for read_dim/write_dim handlers
+--SKIPIF--
+
+--FILE--
+
+--EXPECTF--
+foo
+42
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/008.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/008.phpt
new file mode 100644
index 0000000..db7eeec
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/008.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Test frozen services
+--SKIPIF--
+
+--FILE--
+
+--EXPECTF--
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/009.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/009.phpt
new file mode 100644
index 0000000..bb05ea2
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/009.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Test service is called as callback, and only once
+--SKIPIF--
+
+--FILE--
+
+--EXPECTF--
+bool(true)
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/010.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/010.phpt
new file mode 100644
index 0000000..badce01
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/010.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Test service is called as callback for every callback type
+--SKIPIF--
+
+--FILE--
+
+--EXPECTF--
+callme
+called
+Foo::bar
+array(2) {
+ [0]=>
+ string(3) "Foo"
+ [1]=>
+ string(3) "bar"
+}
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/011.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/011.phpt
new file mode 100644
index 0000000..6682ab8
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/011.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Test service callback throwing an exception
+--SKIPIF--
+
+--FILE--
+
+--EXPECTF--
+all right!
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/012.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/012.phpt
new file mode 100644
index 0000000..4c6ac48
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/012.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Test service factory
+--SKIPIF--
+
+--FILE--
+factory($f = function() { var_dump('called-1'); return 'ret-1';});
+
+$p[] = $f;
+
+$p[] = function () { var_dump('called-2'); return 'ret-2'; };
+
+var_dump($p[0]);
+var_dump($p[0]);
+var_dump($p[1]);
+var_dump($p[1]);
+?>
+--EXPECTF--
+string(8) "called-1"
+string(5) "ret-1"
+string(8) "called-1"
+string(5) "ret-1"
+string(8) "called-2"
+string(5) "ret-2"
+string(5) "ret-2"
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/013.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/013.phpt
new file mode 100644
index 0000000..f419958
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/013.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Test keys()
+--SKIPIF--
+
+--FILE--
+keys());
+
+$p['foo'] = 'bar';
+$p[] = 'foo';
+
+var_dump($p->keys());
+
+unset($p['foo']);
+
+var_dump($p->keys());
+?>
+--EXPECTF--
+array(0) {
+}
+array(2) {
+ [0]=>
+ string(3) "foo"
+ [1]=>
+ int(0)
+}
+array(1) {
+ [0]=>
+ int(0)
+}
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/014.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/014.phpt
new file mode 100644
index 0000000..ac93721
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/014.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Test raw()
+--SKIPIF--
+
+--FILE--
+raw('foo'));
+var_dump($p[42]);
+
+unset($p['foo']);
+
+try {
+ $p->raw('foo');
+ echo "expected exception";
+} catch (InvalidArgumentException $e) { }
+--EXPECTF--
+string(8) "called-2"
+string(5) "ret-2"
+object(Closure)#%i (0) {
+}
+string(8) "called-2"
+string(5) "ret-2"
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/015.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/015.phpt
new file mode 100644
index 0000000..314f008
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/015.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test protect()
+--SKIPIF--
+
+--FILE--
+protect($f);
+
+var_dump($p['foo']);
+--EXPECTF--
+object(Closure)#%i (0) {
+}
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/016.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/016.phpt
new file mode 100644
index 0000000..e55edb0
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/016.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Test extend()
+--SKIPIF--
+
+--FILE--
+extend(12, function ($w) { var_dump($w); return 'bar'; }); /* $callable in code above */
+
+var_dump($c('param'));
+--EXPECTF--
+string(5) "param"
+string(3) "foo"
+string(3) "bar"
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/017.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/017.phpt
new file mode 100644
index 0000000..bac23ce
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/017.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test extend() with exception in service extension
+--SKIPIF--
+
+--FILE--
+extend(12, function ($w) { throw new BadMethodCallException; });
+
+try {
+ $p[12];
+ echo "Exception expected";
+} catch (BadMethodCallException $e) { }
+--EXPECTF--
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/017_1.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/017_1.phpt
new file mode 100644
index 0000000..8f881d6
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/017_1.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test extend() with exception in service factory
+--SKIPIF--
+
+--FILE--
+extend(12, function ($w) { return 'foobar'; });
+
+try {
+ $p[12];
+ echo "Exception expected";
+} catch (BadMethodCallException $e) { }
+--EXPECTF--
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/018.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/018.phpt
new file mode 100644
index 0000000..27c12a1
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/018.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Test register()
+--SKIPIF--
+
+--FILE--
+register(new Foo, array(42 => 'bar'));
+
+var_dump($p[42]);
+--EXPECTF--
+object(Pimple\Container)#1 (0) {
+}
+string(3) "bar"
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/019.phpt b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/019.phpt
new file mode 100644
index 0000000..28a9aec
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/019.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test register() returns static and is a fluent interface
+--SKIPIF--
+
+--FILE--
+register(new Foo));
+--EXPECTF--
+bool(true)
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/bench.phpb b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/bench.phpb
new file mode 100644
index 0000000..8f983e6
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/bench.phpb
@@ -0,0 +1,51 @@
+factory($factory);
+
+$p['factory'] = $factory;
+
+echo $p['factory'];
+echo $p['factory'];
+echo $p['factory'];
+
+}
+
+echo microtime(true) - $time;
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/bench_shared.phpb b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/bench_shared.phpb
new file mode 100644
index 0000000..aec541f
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/ext/pimple/tests/bench_shared.phpb
@@ -0,0 +1,25 @@
+
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/phpunit.xml.dist b/addons/weliam_smartcity/vendor/pimple/pimple/phpunit.xml.dist
new file mode 100644
index 0000000..5c8d487
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/phpunit.xml.dist
@@ -0,0 +1,14 @@
+
+
+
+
+
+ ./src/Pimple/Tests
+
+
+
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Container.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Container.php
new file mode 100644
index 0000000..707b92b
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Container.php
@@ -0,0 +1,298 @@
+factories = new \SplObjectStorage();
+ $this->protected = new \SplObjectStorage();
+
+ foreach ($values as $key => $value) {
+ $this->offsetSet($key, $value);
+ }
+ }
+
+ /**
+ * Sets a parameter or an object.
+ *
+ * Objects must be defined as Closures.
+ *
+ * Allowing any PHP callable leads to difficult to debug problems
+ * as function names (strings) are callable (creating a function with
+ * the same name as an existing parameter would break your container).
+ *
+ * @param string $id The unique identifier for the parameter or object
+ * @param mixed $value The value of the parameter or a closure to define an object
+ *
+ * @throws FrozenServiceException Prevent override of a frozen service
+ */
+ public function offsetSet($id, $value)
+ {
+ if (isset($this->frozen[$id])) {
+ throw new FrozenServiceException($id);
+ }
+
+ $this->values[$id] = $value;
+ $this->keys[$id] = true;
+ }
+
+ /**
+ * Gets a parameter or an object.
+ *
+ * @param string $id The unique identifier for the parameter or object
+ *
+ * @return mixed The value of the parameter or an object
+ *
+ * @throws UnknownIdentifierException If the identifier is not defined
+ */
+ public function offsetGet($id)
+ {
+ if (!isset($this->keys[$id])) {
+ throw new UnknownIdentifierException($id);
+ }
+
+ if (
+ isset($this->raw[$id])
+ || !\is_object($this->values[$id])
+ || isset($this->protected[$this->values[$id]])
+ || !\method_exists($this->values[$id], '__invoke')
+ ) {
+ return $this->values[$id];
+ }
+
+ if (isset($this->factories[$this->values[$id]])) {
+ return $this->values[$id]($this);
+ }
+
+ $raw = $this->values[$id];
+ $val = $this->values[$id] = $raw($this);
+ $this->raw[$id] = $raw;
+
+ $this->frozen[$id] = true;
+
+ return $val;
+ }
+
+ /**
+ * Checks if a parameter or an object is set.
+ *
+ * @param string $id The unique identifier for the parameter or object
+ *
+ * @return bool
+ */
+ public function offsetExists($id)
+ {
+ return isset($this->keys[$id]);
+ }
+
+ /**
+ * Unsets a parameter or an object.
+ *
+ * @param string $id The unique identifier for the parameter or object
+ */
+ public function offsetUnset($id)
+ {
+ if (isset($this->keys[$id])) {
+ if (\is_object($this->values[$id])) {
+ unset($this->factories[$this->values[$id]], $this->protected[$this->values[$id]]);
+ }
+
+ unset($this->values[$id], $this->frozen[$id], $this->raw[$id], $this->keys[$id]);
+ }
+ }
+
+ /**
+ * Marks a callable as being a factory service.
+ *
+ * @param callable $callable A service definition to be used as a factory
+ *
+ * @return callable The passed callable
+ *
+ * @throws ExpectedInvokableException Service definition has to be a closure or an invokable object
+ */
+ public function factory($callable)
+ {
+ if (!\method_exists($callable, '__invoke')) {
+ throw new ExpectedInvokableException('Service definition is not a Closure or invokable object.');
+ }
+
+ $this->factories->attach($callable);
+
+ return $callable;
+ }
+
+ /**
+ * Protects a callable from being interpreted as a service.
+ *
+ * This is useful when you want to store a callable as a parameter.
+ *
+ * @param callable $callable A callable to protect from being evaluated
+ *
+ * @return callable The passed callable
+ *
+ * @throws ExpectedInvokableException Service definition has to be a closure or an invokable object
+ */
+ public function protect($callable)
+ {
+ if (!\method_exists($callable, '__invoke')) {
+ throw new ExpectedInvokableException('Callable is not a Closure or invokable object.');
+ }
+
+ $this->protected->attach($callable);
+
+ return $callable;
+ }
+
+ /**
+ * Gets a parameter or the closure defining an object.
+ *
+ * @param string $id The unique identifier for the parameter or object
+ *
+ * @return mixed The value of the parameter or the closure defining an object
+ *
+ * @throws UnknownIdentifierException If the identifier is not defined
+ */
+ public function raw($id)
+ {
+ if (!isset($this->keys[$id])) {
+ throw new UnknownIdentifierException($id);
+ }
+
+ if (isset($this->raw[$id])) {
+ return $this->raw[$id];
+ }
+
+ return $this->values[$id];
+ }
+
+ /**
+ * Extends an object definition.
+ *
+ * Useful when you want to extend an existing object definition,
+ * without necessarily loading that object.
+ *
+ * @param string $id The unique identifier for the object
+ * @param callable $callable A service definition to extend the original
+ *
+ * @return callable The wrapped callable
+ *
+ * @throws UnknownIdentifierException If the identifier is not defined
+ * @throws FrozenServiceException If the service is frozen
+ * @throws InvalidServiceIdentifierException If the identifier belongs to a parameter
+ * @throws ExpectedInvokableException If the extension callable is not a closure or an invokable object
+ */
+ public function extend($id, $callable)
+ {
+ if (!isset($this->keys[$id])) {
+ throw new UnknownIdentifierException($id);
+ }
+
+ if (isset($this->frozen[$id])) {
+ throw new FrozenServiceException($id);
+ }
+
+ if (!\is_object($this->values[$id]) || !\method_exists($this->values[$id], '__invoke')) {
+ throw new InvalidServiceIdentifierException($id);
+ }
+
+ if (isset($this->protected[$this->values[$id]])) {
+ @\trigger_error(\sprintf('How Pimple behaves when extending protected closures will be fixed in Pimple 4. Are you sure "%s" should be protected?', $id), \E_USER_DEPRECATED);
+ }
+
+ if (!\is_object($callable) || !\method_exists($callable, '__invoke')) {
+ throw new ExpectedInvokableException('Extension service definition is not a Closure or invokable object.');
+ }
+
+ $factory = $this->values[$id];
+
+ $extended = function ($c) use ($callable, $factory) {
+ return $callable($factory($c), $c);
+ };
+
+ if (isset($this->factories[$factory])) {
+ $this->factories->detach($factory);
+ $this->factories->attach($extended);
+ }
+
+ return $this[$id] = $extended;
+ }
+
+ /**
+ * Returns all defined value names.
+ *
+ * @return array An array of value names
+ */
+ public function keys()
+ {
+ return \array_keys($this->values);
+ }
+
+ /**
+ * Registers a service provider.
+ *
+ * @param ServiceProviderInterface $provider A ServiceProviderInterface instance
+ * @param array $values An array of values that customizes the provider
+ *
+ * @return static
+ */
+ public function register(ServiceProviderInterface $provider, array $values = array())
+ {
+ $provider->register($this);
+
+ foreach ($values as $key => $value) {
+ $this[$key] = $value;
+ }
+
+ return $this;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Exception/ExpectedInvokableException.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Exception/ExpectedInvokableException.php
new file mode 100644
index 0000000..7228421
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Exception/ExpectedInvokableException.php
@@ -0,0 +1,38 @@
+
+ */
+class ExpectedInvokableException extends \InvalidArgumentException implements ContainerExceptionInterface
+{
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Exception/FrozenServiceException.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Exception/FrozenServiceException.php
new file mode 100644
index 0000000..e4d2f6d
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Exception/FrozenServiceException.php
@@ -0,0 +1,45 @@
+
+ */
+class FrozenServiceException extends \RuntimeException implements ContainerExceptionInterface
+{
+ /**
+ * @param string $id Identifier of the frozen service
+ */
+ public function __construct($id)
+ {
+ parent::__construct(\sprintf('Cannot override frozen service "%s".', $id));
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Exception/InvalidServiceIdentifierException.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Exception/InvalidServiceIdentifierException.php
new file mode 100644
index 0000000..91e82f9
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Exception/InvalidServiceIdentifierException.php
@@ -0,0 +1,45 @@
+
+ */
+class InvalidServiceIdentifierException extends \InvalidArgumentException implements NotFoundExceptionInterface
+{
+ /**
+ * @param string $id The invalid identifier
+ */
+ public function __construct($id)
+ {
+ parent::__construct(\sprintf('Identifier "%s" does not contain an object definition.', $id));
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Exception/UnknownIdentifierException.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Exception/UnknownIdentifierException.php
new file mode 100644
index 0000000..fb6b626
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Exception/UnknownIdentifierException.php
@@ -0,0 +1,45 @@
+
+ */
+class UnknownIdentifierException extends \InvalidArgumentException implements NotFoundExceptionInterface
+{
+ /**
+ * @param string $id The unknown identifier
+ */
+ public function __construct($id)
+ {
+ parent::__construct(\sprintf('Identifier "%s" is not defined.', $id));
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Psr11/Container.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Psr11/Container.php
new file mode 100644
index 0000000..cadbfff
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Psr11/Container.php
@@ -0,0 +1,55 @@
+
+ */
+final class Container implements ContainerInterface
+{
+ private $pimple;
+
+ public function __construct(PimpleContainer $pimple)
+ {
+ $this->pimple = $pimple;
+ }
+
+ public function get($id)
+ {
+ return $this->pimple[$id];
+ }
+
+ public function has($id)
+ {
+ return isset($this->pimple[$id]);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Psr11/ServiceLocator.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Psr11/ServiceLocator.php
new file mode 100644
index 0000000..3361c6f
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Psr11/ServiceLocator.php
@@ -0,0 +1,75 @@
+
+ */
+class ServiceLocator implements ContainerInterface
+{
+ private $container;
+ private $aliases = array();
+
+ /**
+ * @param PimpleContainer $container The Container instance used to locate services
+ * @param array $ids Array of service ids that can be located. String keys can be used to define aliases
+ */
+ public function __construct(PimpleContainer $container, array $ids)
+ {
+ $this->container = $container;
+
+ foreach ($ids as $key => $id) {
+ $this->aliases[\is_int($key) ? $id : $key] = $id;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($id)
+ {
+ if (!isset($this->aliases[$id])) {
+ throw new UnknownIdentifierException($id);
+ }
+
+ return $this->container[$this->aliases[$id]];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function has($id)
+ {
+ return isset($this->aliases[$id]) && isset($this->container[$this->aliases[$id]]);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/ServiceIterator.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/ServiceIterator.php
new file mode 100644
index 0000000..5cde518
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/ServiceIterator.php
@@ -0,0 +1,69 @@
+
+ */
+final class ServiceIterator implements \Iterator
+{
+ private $container;
+ private $ids;
+
+ public function __construct(Container $container, array $ids)
+ {
+ $this->container = $container;
+ $this->ids = $ids;
+ }
+
+ public function rewind()
+ {
+ \reset($this->ids);
+ }
+
+ public function current()
+ {
+ return $this->container[\current($this->ids)];
+ }
+
+ public function key()
+ {
+ return \current($this->ids);
+ }
+
+ public function next()
+ {
+ \next($this->ids);
+ }
+
+ public function valid()
+ {
+ return null !== \key($this->ids);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/ServiceProviderInterface.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/ServiceProviderInterface.php
new file mode 100644
index 0000000..c004594
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/ServiceProviderInterface.php
@@ -0,0 +1,46 @@
+value = $value;
+
+ return $service;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/Fixtures/NonInvokable.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/Fixtures/NonInvokable.php
new file mode 100644
index 0000000..33cd4e5
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/Fixtures/NonInvokable.php
@@ -0,0 +1,34 @@
+factory(function () {
+ return new Service();
+ });
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/Fixtures/Service.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/Fixtures/Service.php
new file mode 100644
index 0000000..d71b184
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/Fixtures/Service.php
@@ -0,0 +1,35 @@
+
+ */
+class Service
+{
+ public $value;
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/PimpleServiceProviderInterfaceTest.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/PimpleServiceProviderInterfaceTest.php
new file mode 100644
index 0000000..8e5c4c7
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/PimpleServiceProviderInterfaceTest.php
@@ -0,0 +1,76 @@
+
+ */
+class PimpleServiceProviderInterfaceTest extends \PHPUnit_Framework_TestCase
+{
+ public function testProvider()
+ {
+ $pimple = new Container();
+
+ $pimpleServiceProvider = new Fixtures\PimpleServiceProvider();
+ $pimpleServiceProvider->register($pimple);
+
+ $this->assertEquals('value', $pimple['param']);
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $pimple['service']);
+
+ $serviceOne = $pimple['factory'];
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne);
+
+ $serviceTwo = $pimple['factory'];
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo);
+
+ $this->assertNotSame($serviceOne, $serviceTwo);
+ }
+
+ public function testProviderWithRegisterMethod()
+ {
+ $pimple = new Container();
+
+ $pimple->register(new Fixtures\PimpleServiceProvider(), array(
+ 'anotherParameter' => 'anotherValue',
+ ));
+
+ $this->assertEquals('value', $pimple['param']);
+ $this->assertEquals('anotherValue', $pimple['anotherParameter']);
+
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $pimple['service']);
+
+ $serviceOne = $pimple['factory'];
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne);
+
+ $serviceTwo = $pimple['factory'];
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo);
+
+ $this->assertNotSame($serviceOne, $serviceTwo);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/PimpleTest.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/PimpleTest.php
new file mode 100644
index 0000000..acb66e0
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/PimpleTest.php
@@ -0,0 +1,589 @@
+
+ */
+class PimpleTest extends \PHPUnit_Framework_TestCase
+{
+ public function testWithString()
+ {
+ $pimple = new Container();
+ $pimple['param'] = 'value';
+
+ $this->assertEquals('value', $pimple['param']);
+ }
+
+ public function testWithClosure()
+ {
+ $pimple = new Container();
+ $pimple['service'] = function () {
+ return new Fixtures\Service();
+ };
+
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $pimple['service']);
+ }
+
+ public function testServicesShouldBeDifferent()
+ {
+ $pimple = new Container();
+ $pimple['service'] = $pimple->factory(function () {
+ return new Fixtures\Service();
+ });
+
+ $serviceOne = $pimple['service'];
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne);
+
+ $serviceTwo = $pimple['service'];
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo);
+
+ $this->assertNotSame($serviceOne, $serviceTwo);
+ }
+
+ public function testShouldPassContainerAsParameter()
+ {
+ $pimple = new Container();
+ $pimple['service'] = function () {
+ return new Fixtures\Service();
+ };
+ $pimple['container'] = function ($container) {
+ return $container;
+ };
+
+ $this->assertNotSame($pimple, $pimple['service']);
+ $this->assertSame($pimple, $pimple['container']);
+ }
+
+ public function testIsset()
+ {
+ $pimple = new Container();
+ $pimple['param'] = 'value';
+ $pimple['service'] = function () {
+ return new Fixtures\Service();
+ };
+
+ $pimple['null'] = null;
+
+ $this->assertTrue(isset($pimple['param']));
+ $this->assertTrue(isset($pimple['service']));
+ $this->assertTrue(isset($pimple['null']));
+ $this->assertFalse(isset($pimple['non_existent']));
+ }
+
+ public function testConstructorInjection()
+ {
+ $params = array('param' => 'value');
+ $pimple = new Container($params);
+
+ $this->assertSame($params['param'], $pimple['param']);
+ }
+
+ /**
+ * @expectedException \Pimple\Exception\UnknownIdentifierException
+ * @expectedExceptionMessage Identifier "foo" is not defined.
+ */
+ public function testOffsetGetValidatesKeyIsPresent()
+ {
+ $pimple = new Container();
+ echo $pimple['foo'];
+ }
+
+ /**
+ * @group legacy
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Identifier "foo" is not defined.
+ */
+ public function testLegacyOffsetGetValidatesKeyIsPresent()
+ {
+ $pimple = new Container();
+ echo $pimple['foo'];
+ }
+
+ public function testOffsetGetHonorsNullValues()
+ {
+ $pimple = new Container();
+ $pimple['foo'] = null;
+ $this->assertNull($pimple['foo']);
+ }
+
+ public function testUnset()
+ {
+ $pimple = new Container();
+ $pimple['param'] = 'value';
+ $pimple['service'] = function () {
+ return new Fixtures\Service();
+ };
+
+ unset($pimple['param'], $pimple['service']);
+ $this->assertFalse(isset($pimple['param']));
+ $this->assertFalse(isset($pimple['service']));
+ }
+
+ /**
+ * @dataProvider serviceDefinitionProvider
+ */
+ public function testShare($service)
+ {
+ $pimple = new Container();
+ $pimple['shared_service'] = $service;
+
+ $serviceOne = $pimple['shared_service'];
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne);
+
+ $serviceTwo = $pimple['shared_service'];
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo);
+
+ $this->assertSame($serviceOne, $serviceTwo);
+ }
+
+ /**
+ * @dataProvider serviceDefinitionProvider
+ */
+ public function testProtect($service)
+ {
+ $pimple = new Container();
+ $pimple['protected'] = $pimple->protect($service);
+
+ $this->assertSame($service, $pimple['protected']);
+ }
+
+ public function testGlobalFunctionNameAsParameterValue()
+ {
+ $pimple = new Container();
+ $pimple['global_function'] = 'strlen';
+ $this->assertSame('strlen', $pimple['global_function']);
+ }
+
+ public function testRaw()
+ {
+ $pimple = new Container();
+ $pimple['service'] = $definition = $pimple->factory(function () { return 'foo'; });
+ $this->assertSame($definition, $pimple->raw('service'));
+ }
+
+ public function testRawHonorsNullValues()
+ {
+ $pimple = new Container();
+ $pimple['foo'] = null;
+ $this->assertNull($pimple->raw('foo'));
+ }
+
+ public function testFluentRegister()
+ {
+ $pimple = new Container();
+ $this->assertSame($pimple, $pimple->register($this->getMockBuilder('Pimple\ServiceProviderInterface')->getMock()));
+ }
+
+ /**
+ * @expectedException \Pimple\Exception\UnknownIdentifierException
+ * @expectedExceptionMessage Identifier "foo" is not defined.
+ */
+ public function testRawValidatesKeyIsPresent()
+ {
+ $pimple = new Container();
+ $pimple->raw('foo');
+ }
+
+ /**
+ * @group legacy
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Identifier "foo" is not defined.
+ */
+ public function testLegacyRawValidatesKeyIsPresent()
+ {
+ $pimple = new Container();
+ $pimple->raw('foo');
+ }
+
+ /**
+ * @dataProvider serviceDefinitionProvider
+ */
+ public function testExtend($service)
+ {
+ $pimple = new Container();
+ $pimple['shared_service'] = function () {
+ return new Fixtures\Service();
+ };
+ $pimple['factory_service'] = $pimple->factory(function () {
+ return new Fixtures\Service();
+ });
+
+ $pimple->extend('shared_service', $service);
+ $serviceOne = $pimple['shared_service'];
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne);
+ $serviceTwo = $pimple['shared_service'];
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo);
+ $this->assertSame($serviceOne, $serviceTwo);
+ $this->assertSame($serviceOne->value, $serviceTwo->value);
+
+ $pimple->extend('factory_service', $service);
+ $serviceOne = $pimple['factory_service'];
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne);
+ $serviceTwo = $pimple['factory_service'];
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo);
+ $this->assertNotSame($serviceOne, $serviceTwo);
+ $this->assertNotSame($serviceOne->value, $serviceTwo->value);
+ }
+
+ public function testExtendDoesNotLeakWithFactories()
+ {
+ if (extension_loaded('pimple')) {
+ $this->markTestSkipped('Pimple extension does not support this test');
+ }
+ $pimple = new Container();
+
+ $pimple['foo'] = $pimple->factory(function () { return; });
+ $pimple['foo'] = $pimple->extend('foo', function ($foo, $pimple) { return; });
+ unset($pimple['foo']);
+
+ $p = new \ReflectionProperty($pimple, 'values');
+ $p->setAccessible(true);
+ $this->assertEmpty($p->getValue($pimple));
+
+ $p = new \ReflectionProperty($pimple, 'factories');
+ $p->setAccessible(true);
+ $this->assertCount(0, $p->getValue($pimple));
+ }
+
+ /**
+ * @expectedException \Pimple\Exception\UnknownIdentifierException
+ * @expectedExceptionMessage Identifier "foo" is not defined.
+ */
+ public function testExtendValidatesKeyIsPresent()
+ {
+ $pimple = new Container();
+ $pimple->extend('foo', function () {});
+ }
+
+ /**
+ * @group legacy
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Identifier "foo" is not defined.
+ */
+ public function testLegacyExtendValidatesKeyIsPresent()
+ {
+ $pimple = new Container();
+ $pimple->extend('foo', function () {});
+ }
+
+ public function testKeys()
+ {
+ $pimple = new Container();
+ $pimple['foo'] = 123;
+ $pimple['bar'] = 123;
+
+ $this->assertEquals(array('foo', 'bar'), $pimple->keys());
+ }
+
+ /** @test */
+ public function settingAnInvokableObjectShouldTreatItAsFactory()
+ {
+ $pimple = new Container();
+ $pimple['invokable'] = new Fixtures\Invokable();
+
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $pimple['invokable']);
+ }
+
+ /** @test */
+ public function settingNonInvokableObjectShouldTreatItAsParameter()
+ {
+ $pimple = new Container();
+ $pimple['non_invokable'] = new Fixtures\NonInvokable();
+
+ $this->assertInstanceOf('Pimple\Tests\Fixtures\NonInvokable', $pimple['non_invokable']);
+ }
+
+ /**
+ * @dataProvider badServiceDefinitionProvider
+ * @expectedException \Pimple\Exception\ExpectedInvokableException
+ * @expectedExceptionMessage Service definition is not a Closure or invokable object.
+ */
+ public function testFactoryFailsForInvalidServiceDefinitions($service)
+ {
+ $pimple = new Container();
+ $pimple->factory($service);
+ }
+
+ /**
+ * @group legacy
+ * @dataProvider badServiceDefinitionProvider
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Service definition is not a Closure or invokable object.
+ */
+ public function testLegacyFactoryFailsForInvalidServiceDefinitions($service)
+ {
+ $pimple = new Container();
+ $pimple->factory($service);
+ }
+
+ /**
+ * @dataProvider badServiceDefinitionProvider
+ * @expectedException \Pimple\Exception\ExpectedInvokableException
+ * @expectedExceptionMessage Callable is not a Closure or invokable object.
+ */
+ public function testProtectFailsForInvalidServiceDefinitions($service)
+ {
+ $pimple = new Container();
+ $pimple->protect($service);
+ }
+
+ /**
+ * @group legacy
+ * @dataProvider badServiceDefinitionProvider
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Callable is not a Closure or invokable object.
+ */
+ public function testLegacyProtectFailsForInvalidServiceDefinitions($service)
+ {
+ $pimple = new Container();
+ $pimple->protect($service);
+ }
+
+ /**
+ * @dataProvider badServiceDefinitionProvider
+ * @expectedException \Pimple\Exception\InvalidServiceIdentifierException
+ * @expectedExceptionMessage Identifier "foo" does not contain an object definition.
+ */
+ public function testExtendFailsForKeysNotContainingServiceDefinitions($service)
+ {
+ $pimple = new Container();
+ $pimple['foo'] = $service;
+ $pimple->extend('foo', function () {});
+ }
+
+ /**
+ * @group legacy
+ * @dataProvider badServiceDefinitionProvider
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Identifier "foo" does not contain an object definition.
+ */
+ public function testLegacyExtendFailsForKeysNotContainingServiceDefinitions($service)
+ {
+ $pimple = new Container();
+ $pimple['foo'] = $service;
+ $pimple->extend('foo', function () {});
+ }
+
+ /**
+ * @group legacy
+ * @expectedDeprecation How Pimple behaves when extending protected closures will be fixed in Pimple 4. Are you sure "foo" should be protected?
+ */
+ public function testExtendingProtectedClosureDeprecation()
+ {
+ $pimple = new Container();
+ $pimple['foo'] = $pimple->protect(function () {
+ return 'bar';
+ });
+
+ $pimple->extend('foo', function ($value) {
+ return $value.'-baz';
+ });
+
+ $this->assertSame('bar-baz', $pimple['foo']);
+ }
+
+ /**
+ * @dataProvider badServiceDefinitionProvider
+ * @expectedException \Pimple\Exception\ExpectedInvokableException
+ * @expectedExceptionMessage Extension service definition is not a Closure or invokable object.
+ */
+ public function testExtendFailsForInvalidServiceDefinitions($service)
+ {
+ $pimple = new Container();
+ $pimple['foo'] = function () {};
+ $pimple->extend('foo', $service);
+ }
+
+ /**
+ * @group legacy
+ * @dataProvider badServiceDefinitionProvider
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Extension service definition is not a Closure or invokable object.
+ */
+ public function testLegacyExtendFailsForInvalidServiceDefinitions($service)
+ {
+ $pimple = new Container();
+ $pimple['foo'] = function () {};
+ $pimple->extend('foo', $service);
+ }
+
+ /**
+ * @expectedException \Pimple\Exception\FrozenServiceException
+ * @expectedExceptionMessage Cannot override frozen service "foo".
+ */
+ public function testExtendFailsIfFrozenServiceIsNonInvokable()
+ {
+ $pimple = new Container();
+ $pimple['foo'] = function () {
+ return new Fixtures\NonInvokable();
+ };
+ $foo = $pimple['foo'];
+
+ $pimple->extend('foo', function () {});
+ }
+
+ /**
+ * @expectedException \Pimple\Exception\FrozenServiceException
+ * @expectedExceptionMessage Cannot override frozen service "foo".
+ */
+ public function testExtendFailsIfFrozenServiceIsInvokable()
+ {
+ $pimple = new Container();
+ $pimple['foo'] = function () {
+ return new Fixtures\Invokable();
+ };
+ $foo = $pimple['foo'];
+
+ $pimple->extend('foo', function () {});
+ }
+
+ /**
+ * Provider for invalid service definitions.
+ */
+ public function badServiceDefinitionProvider()
+ {
+ return array(
+ array(123),
+ array(new Fixtures\NonInvokable()),
+ );
+ }
+
+ /**
+ * Provider for service definitions.
+ */
+ public function serviceDefinitionProvider()
+ {
+ return array(
+ array(function ($value) {
+ $service = new Fixtures\Service();
+ $service->value = $value;
+
+ return $service;
+ }),
+ array(new Fixtures\Invokable()),
+ );
+ }
+
+ public function testDefiningNewServiceAfterFreeze()
+ {
+ $pimple = new Container();
+ $pimple['foo'] = function () {
+ return 'foo';
+ };
+ $foo = $pimple['foo'];
+
+ $pimple['bar'] = function () {
+ return 'bar';
+ };
+ $this->assertSame('bar', $pimple['bar']);
+ }
+
+ /**
+ * @expectedException \Pimple\Exception\FrozenServiceException
+ * @expectedExceptionMessage Cannot override frozen service "foo".
+ */
+ public function testOverridingServiceAfterFreeze()
+ {
+ $pimple = new Container();
+ $pimple['foo'] = function () {
+ return 'foo';
+ };
+ $foo = $pimple['foo'];
+
+ $pimple['foo'] = function () {
+ return 'bar';
+ };
+ }
+
+ /**
+ * @group legacy
+ * @expectedException \RuntimeException
+ * @expectedExceptionMessage Cannot override frozen service "foo".
+ */
+ public function testLegacyOverridingServiceAfterFreeze()
+ {
+ $pimple = new Container();
+ $pimple['foo'] = function () {
+ return 'foo';
+ };
+ $foo = $pimple['foo'];
+
+ $pimple['foo'] = function () {
+ return 'bar';
+ };
+ }
+
+ public function testRemovingServiceAfterFreeze()
+ {
+ $pimple = new Container();
+ $pimple['foo'] = function () {
+ return 'foo';
+ };
+ $foo = $pimple['foo'];
+
+ unset($pimple['foo']);
+ $pimple['foo'] = function () {
+ return 'bar';
+ };
+ $this->assertSame('bar', $pimple['foo']);
+ }
+
+ public function testExtendingService()
+ {
+ $pimple = new Container();
+ $pimple['foo'] = function () {
+ return 'foo';
+ };
+ $pimple['foo'] = $pimple->extend('foo', function ($foo, $app) {
+ return "$foo.bar";
+ });
+ $pimple['foo'] = $pimple->extend('foo', function ($foo, $app) {
+ return "$foo.baz";
+ });
+ $this->assertSame('foo.bar.baz', $pimple['foo']);
+ }
+
+ public function testExtendingServiceAfterOtherServiceFreeze()
+ {
+ $pimple = new Container();
+ $pimple['foo'] = function () {
+ return 'foo';
+ };
+ $pimple['bar'] = function () {
+ return 'bar';
+ };
+ $foo = $pimple['foo'];
+
+ $pimple['bar'] = $pimple->extend('bar', function ($bar, $app) {
+ return "$bar.baz";
+ });
+ $this->assertSame('bar.baz', $pimple['bar']);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/Psr11/ContainerTest.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/Psr11/ContainerTest.php
new file mode 100644
index 0000000..7ca2d7f
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/Psr11/ContainerTest.php
@@ -0,0 +1,77 @@
+assertSame($pimple['service'], $psr->get('service'));
+ }
+
+ /**
+ * @expectedException \Psr\Container\NotFoundExceptionInterface
+ * @expectedExceptionMessage Identifier "service" is not defined.
+ */
+ public function testGetThrowsExceptionIfServiceIsNotFound()
+ {
+ $pimple = new Container();
+ $psr = new PsrContainer($pimple);
+
+ $psr->get('service');
+ }
+
+ public function testHasReturnsTrueIfServiceExists()
+ {
+ $pimple = new Container();
+ $pimple['service'] = function () {
+ return new Service();
+ };
+ $psr = new PsrContainer($pimple);
+
+ $this->assertTrue($psr->has('service'));
+ }
+
+ public function testHasReturnsFalseIfServiceDoesNotExist()
+ {
+ $pimple = new Container();
+ $psr = new PsrContainer($pimple);
+
+ $this->assertFalse($psr->has('service'));
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/Psr11/ServiceLocatorTest.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/Psr11/ServiceLocatorTest.php
new file mode 100644
index 0000000..c9a0812
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/Psr11/ServiceLocatorTest.php
@@ -0,0 +1,134 @@
+
+ */
+class ServiceLocatorTest extends TestCase
+{
+ public function testCanAccessServices()
+ {
+ $pimple = new Container();
+ $pimple['service'] = function () {
+ return new Fixtures\Service();
+ };
+ $locator = new ServiceLocator($pimple, array('service'));
+
+ $this->assertSame($pimple['service'], $locator->get('service'));
+ }
+
+ public function testCanAccessAliasedServices()
+ {
+ $pimple = new Container();
+ $pimple['service'] = function () {
+ return new Fixtures\Service();
+ };
+ $locator = new ServiceLocator($pimple, array('alias' => 'service'));
+
+ $this->assertSame($pimple['service'], $locator->get('alias'));
+ }
+
+ /**
+ * @expectedException \Pimple\Exception\UnknownIdentifierException
+ * @expectedExceptionMessage Identifier "service" is not defined.
+ */
+ public function testCannotAccessAliasedServiceUsingRealIdentifier()
+ {
+ $pimple = new Container();
+ $pimple['service'] = function () {
+ return new Fixtures\Service();
+ };
+ $locator = new ServiceLocator($pimple, array('alias' => 'service'));
+
+ $service = $locator->get('service');
+ }
+
+ /**
+ * @expectedException \Pimple\Exception\UnknownIdentifierException
+ * @expectedExceptionMessage Identifier "foo" is not defined.
+ */
+ public function testGetValidatesServiceCanBeLocated()
+ {
+ $pimple = new Container();
+ $pimple['service'] = function () {
+ return new Fixtures\Service();
+ };
+ $locator = new ServiceLocator($pimple, array('alias' => 'service'));
+
+ $service = $locator->get('foo');
+ }
+
+ /**
+ * @expectedException \Pimple\Exception\UnknownIdentifierException
+ * @expectedExceptionMessage Identifier "invalid" is not defined.
+ */
+ public function testGetValidatesTargetServiceExists()
+ {
+ $pimple = new Container();
+ $pimple['service'] = function () {
+ return new Fixtures\Service();
+ };
+ $locator = new ServiceLocator($pimple, array('alias' => 'invalid'));
+
+ $service = $locator->get('alias');
+ }
+
+ public function testHasValidatesServiceCanBeLocated()
+ {
+ $pimple = new Container();
+ $pimple['service1'] = function () {
+ return new Fixtures\Service();
+ };
+ $pimple['service2'] = function () {
+ return new Fixtures\Service();
+ };
+ $locator = new ServiceLocator($pimple, array('service1'));
+
+ $this->assertTrue($locator->has('service1'));
+ $this->assertFalse($locator->has('service2'));
+ }
+
+ public function testHasChecksIfTargetServiceExists()
+ {
+ $pimple = new Container();
+ $pimple['service'] = function () {
+ return new Fixtures\Service();
+ };
+ $locator = new ServiceLocator($pimple, array('foo' => 'service', 'bar' => 'invalid'));
+
+ $this->assertTrue($locator->has('foo'));
+ $this->assertFalse($locator->has('bar'));
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/ServiceIteratorTest.php b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/ServiceIteratorTest.php
new file mode 100644
index 0000000..5dd52f0
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/pimple/pimple/src/Pimple/Tests/ServiceIteratorTest.php
@@ -0,0 +1,52 @@
+assertSame(array('service1' => $pimple['service1'], 'service2' => $pimple['service2']), iterator_to_array($iterator));
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/mysql/README.md b/addons/weliam_smartcity/vendor/workerman/mysql/README.md
new file mode 100644
index 0000000..a8b3edb
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/mysql/README.md
@@ -0,0 +1,78 @@
+# Workerman\Mysql\Connection
+
+Long-living MySQL connection for daemon.
+
+# Install
+```composer require workerman/mysql```
+
+# Usage
+```php
+$db = new Workerman\MySQL\Connection($mysql_host, $mysql_port, $user, $password, $db_bname);
+
+// Get all rows.
+$db1->select('ID,Sex')->from('Persons')->where('sex= :sex')->bindValues(array('sex'=>'M'))->query();
+// Equivalent to.
+$db1->select('ID,Sex')->from('Persons')->where("sex='F'")->query();
+// Equivalent to.
+$db->query("SELECT ID,Sex FROM `Persons` WHERE sex='M'");
+
+
+// Get one row.
+$db->select('ID,Sex')->from('Persons')->where('sex= :sex')->bindValues(array('sex'=>'M'))->row();
+// Equivalent to.
+$db->select('ID,Sex')->from('Persons')->where("sex= 'F' ")->row();
+// Equivalent to.
+$db->row("SELECT ID,Sex FROM `Persons` WHERE sex='M'");
+
+
+// Get a column.
+$db->select('ID')->from('Persons')->where('sex= :sex')->bindValues(array('sex'=>'M'))->column();
+// Equivalent to.
+$db->select('ID')->from('Persons')->where("sex= 'F' ")->column();
+// Equivalent to.
+$db->column("SELECT `ID` FROM `Persons` WHERE sex='M'");
+
+// Get single.
+$db->select('ID,Sex')->from('Persons')->where('sex= :sex')->bindValues(array('sex'=>'M'))->single();
+// Equivalent to.
+$db->select('ID,Sex')->from('Persons')->where("sex= 'F' ")->single();
+// Equivalent to.
+$db->single("SELECT ID,Sex FROM `Persons` WHERE sex='M'");
+
+// Complex query.
+$db->select('*')->from('table1')->innerJoin('table2','table1.uid = table2.uid')->where('age > :age')
+->groupBy(array('aid'))->having('foo="foo"')->orderByASC/*orderByDESC*/(array('did'))
+->limit(10)->offset(20)->bindValues(array('age' => 13));
+// Equivalent to.
+$db->query(SELECT * FROM `table1` INNER JOIN `table2` ON `table1`.`uid` = `table2`.`uid` WHERE age > 13
+GROUP BY aid HAVING foo="foo" ORDER BY did LIMIT 10 OFFSET 20“);
+
+// Insert.
+$insert_id = $db->insert('Persons')->cols(array(
+ 'Firstname'=>'abc',
+ 'Lastname'=>'efg',
+ 'Sex'=>'M',
+ 'Age'=>13))->query();
+// Equivalent to.
+$insert_id = $db->query("INSERT INTO `Persons` ( `Firstname`,`Lastname`,`Sex`,`Age`)
+VALUES ( 'abc', 'efg', 'M', 13)");
+
+// Updagte.
+$row_count = $db->update('Persons')->cols(array('sex'))->where('ID=1')
+->bindValue('sex', 'F')->query();
+// Equivalent to.
+$row_count = $db->update('Persons')->cols(array('sex'=>'F'))->where('ID=1')->query();
+// Equivalent to.
+$row_count = $db->query("UPDATE `Persons` SET `sex` = 'F' WHERE ID=1");
+
+// Delete.
+$row_count = $db->delete('Persons')->where('ID=9')->query();
+// Equivalent to.
+$row_count = $db->query("DELETE FROM `Persons` WHERE ID=9");
+
+// Transaction.
+$db1->beginTrans();
+....
+$db1->commitTrans(); // or $db1->rollBackTrans();
+
+```
diff --git a/addons/weliam_smartcity/vendor/workerman/mysql/composer.json b/addons/weliam_smartcity/vendor/workerman/mysql/composer.json
new file mode 100644
index 0000000..51c0328
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/mysql/composer.json
@@ -0,0 +1,16 @@
+{
+ "name" : "workerman/mysql",
+ "type" : "library",
+ "keywords": ["mysql", "pdo", "pdo_mysql"],
+ "homepage": "http://www.workerman.net",
+ "license" : "MIT",
+ "description": "Long-living MySQL connection for daemon.",
+ "require": {
+ "php": ">=5.3",
+ "ext-pdo": "*",
+ "ext-pdo_mysql": "*"
+ },
+ "autoload": {
+ "psr-4": {"Workerman\\MySQL\\": "./src"}
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/mysql/src/Connection.php b/addons/weliam_smartcity/vendor/workerman/mysql/src/Connection.php
new file mode 100644
index 0000000..69ff499
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/mysql/src/Connection.php
@@ -0,0 +1,1986 @@
+type = 'SELECT';
+ if (!is_array($cols)) {
+ $cols = explode(',', $cols);
+ }
+ $this->cols($cols);
+ return $this;
+ }
+
+ /**
+ * 从哪个表删除
+ *
+ * @param string $table
+ * @return self
+ */
+ public function delete($table)
+ {
+ $this->type = 'DELETE';
+ $this->table = $this->quoteName($table);
+ $this->fromRaw($this->quoteName($table));
+ return $this;
+ }
+
+ /**
+ * 更新哪个表
+ *
+ * @param string $table
+ * @return self
+ */
+ public function update($table)
+ {
+ $this->type = 'UPDATE';
+ $this->table = $this->quoteName($table);
+ return $this;
+ }
+
+ /**
+ * 向哪个表插入
+ *
+ * @param string $table
+ * @return self
+ */
+ public function insert($table)
+ {
+ $this->type = 'INSERT';
+ $this->table = $this->quoteName($table);
+ return $this;
+ }
+
+ /**
+ *
+ * 设置 SQL_CALC_FOUND_ROWS 标记.
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function calcFoundRows($enable = true)
+ {
+ $this->setFlag('SQL_CALC_FOUND_ROWS', $enable);
+ return $this;
+ }
+
+ /**
+ * 设置 SQL_CACHE 标记
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function cache($enable = true)
+ {
+ $this->setFlag('SQL_CACHE', $enable);
+ return $this;
+ }
+
+ /**
+ * 设置 SQL_NO_CACHE 标记
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function noCache($enable = true)
+ {
+ $this->setFlag('SQL_NO_CACHE', $enable);
+ return $this;
+ }
+
+ /**
+ * 设置 STRAIGHT_JOIN 标记.
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function straightJoin($enable = true)
+ {
+ $this->setFlag('STRAIGHT_JOIN', $enable);
+ return $this;
+ }
+
+ /**
+ * 设置 HIGH_PRIORITY 标记
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function highPriority($enable = true)
+ {
+ $this->setFlag('HIGH_PRIORITY', $enable);
+ return $this;
+ }
+
+ /**
+ * 设置 SQL_SMALL_RESULT 标记
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function smallResult($enable = true)
+ {
+ $this->setFlag('SQL_SMALL_RESULT', $enable);
+ return $this;
+ }
+
+ /**
+ * 设置 SQL_BIG_RESULT 标记
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function bigResult($enable = true)
+ {
+ $this->setFlag('SQL_BIG_RESULT', $enable);
+ return $this;
+ }
+
+ /**
+ * 设置 SQL_BUFFER_RESULT 标记
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function bufferResult($enable = true)
+ {
+ $this->setFlag('SQL_BUFFER_RESULT', $enable);
+ return $this;
+ }
+
+ /**
+ * 设置 FOR UPDATE 标记
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function forUpdate($enable = true)
+ {
+ $this->for_update = (bool)$enable;
+ return $this;
+ }
+
+ /**
+ * 设置 DISTINCT 标记
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function distinct($enable = true)
+ {
+ $this->setFlag('DISTINCT', $enable);
+ return $this;
+ }
+
+ /**
+ * 设置 LOW_PRIORITY 标记
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function lowPriority($enable = true)
+ {
+ $this->setFlag('LOW_PRIORITY', $enable);
+ return $this;
+ }
+
+ /**
+ * 设置 IGNORE 标记
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function ignore($enable = true)
+ {
+ $this->setFlag('IGNORE', $enable);
+ return $this;
+ }
+
+ /**
+ * 设置 QUICK 标记
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function quick($enable = true)
+ {
+ $this->setFlag('QUICK', $enable);
+ return $this;
+ }
+
+ /**
+ * 设置 DELAYED 标记
+ *
+ * @param bool $enable
+ * @return self
+ */
+ public function delayed($enable = true)
+ {
+ $this->setFlag('DELAYED', $enable);
+ return $this;
+ }
+
+ /**
+ * 序列化
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $union = '';
+ if ($this->union) {
+ $union = implode(' ', $this->union) . ' ';
+ }
+ return $union . $this->build();
+ }
+
+ /**
+ * 设置每页多少条记录
+ *
+ * @param int $paging
+ * @return self
+ */
+ public function setPaging($paging)
+ {
+ $this->paging = (int)$paging;
+ return $this;
+ }
+
+ /**
+ * 获取每页多少条记录
+ *
+ * @return int
+ */
+ public function getPaging()
+ {
+ return $this->paging;
+ }
+
+ /**
+ * 获取绑定在占位符上的值
+ */
+ public function getBindValues()
+ {
+ switch ($this->type) {
+ case 'SELECT':
+ return $this->getBindValuesSELECT();
+ case 'DELETE':
+ case 'UPDATE':
+ case 'INSERT':
+ return $this->getBindValuesCOMMON();
+ default :
+ throw new Exception("type err");
+ }
+ }
+
+ /**
+ * 获取绑定在占位符上的值
+ *
+ * @return array
+ */
+ public function getBindValuesSELECT()
+ {
+ $bind_values = $this->bind_values;
+ $i = 1;
+ foreach ($this->bind_where as $val) {
+ $bind_values[$i] = $val;
+ $i++;
+ }
+ foreach ($this->bind_having as $val) {
+ $bind_values[$i] = $val;
+ $i++;
+ }
+ return $bind_values;
+ }
+
+ /**
+ *
+ * SELECT选择哪些列
+ *
+ * @param mixed $key
+ * @param string $val
+ * @return void
+ */
+ protected function addColSELECT($key, $val)
+ {
+ if (is_string($key)) {
+ $this->cols[$val] = $key;
+ } else {
+ $this->addColWithAlias($val);
+ }
+ }
+
+ /**
+ * SELECT 增加选择的列
+ *
+ * @param string $spec
+ */
+ protected function addColWithAlias($spec)
+ {
+ $parts = explode(' ', $spec);
+ $count = count($parts);
+ if ($count == 2 && trim($parts[0]) != '' && trim($parts[1]) != '') {
+ $this->cols[$parts[1]] = $parts[0];
+ } elseif ($count == 3 && strtoupper($parts[1]) == 'AS') {
+ $this->cols[$parts[2]] = $parts[0];
+ } else {
+ $this->cols[] = trim($spec);
+ }
+ }
+
+ /**
+ * from 哪个表
+ *
+ * @param string $table
+ * @return self
+ */
+ public function from($table)
+ {
+ return $this->fromRaw($this->quoteName($table));
+ }
+
+ /**
+ * from的表
+ *
+ * @param string $table
+ * @return self
+ */
+ public function fromRaw($table)
+ {
+ $this->from[] = array($table);
+ $this->from_key++;
+ return $this;
+ }
+
+ /**
+ *
+ * 子查询
+ *
+ * @param string $table
+ * @param string $name The alias name for the sub-select.
+ * @return self
+ */
+ public function fromSubSelect($table, $name)
+ {
+ $this->from[] = array("($table) AS " . $this->quoteName($name));
+ $this->from_key++;
+ return $this;
+ }
+
+
+ /**
+ * 增加 join 语句
+ *
+ * @param string $table
+ * @param string $cond
+ * @param string $type
+ * @return self
+ * @throws Exception
+ */
+ public function join($table, $cond = null, $type = '')
+ {
+ return $this->joinInternal($type, $table, $cond);
+ }
+
+ /**
+ * 增加 join 语句
+ *
+ * @param string $join inner, left, natural
+ * @param string $table
+ * @param string $cond
+ * @return self
+ * @throws Exception
+ */
+ protected function joinInternal($join, $table, $cond = null)
+ {
+ if (!$this->from) {
+ throw new Exception('Cannot join() without from()');
+ }
+
+ $join = strtoupper(ltrim("$join JOIN"));
+ $table = $this->quoteName($table);
+ $cond = $this->fixJoinCondition($cond);
+ $this->from[$this->from_key][] = rtrim("$join $table $cond");
+ return $this;
+ }
+
+ /**
+ * quote
+ *
+ * @param string $cond
+ * @return string
+ *
+ */
+ protected function fixJoinCondition($cond)
+ {
+ if (!$cond) {
+ return '';
+ }
+
+ $cond = $this->quoteNamesIn($cond);
+
+ if (strtoupper(substr(ltrim($cond), 0, 3)) == 'ON ') {
+ return $cond;
+ }
+
+ if (strtoupper(substr(ltrim($cond), 0, 6)) == 'USING ') {
+ return $cond;
+ }
+
+ return 'ON ' . $cond;
+ }
+
+ /**
+ * inner join
+ *
+ * @param string $table
+ * @param string $cond
+ * @return self
+ * @throws Exception
+ */
+ public function innerJoin($table, $cond = null)
+ {
+ return $this->joinInternal('INNER', $table, $cond);
+ }
+
+ /**
+ * left join
+ *
+ * @param string $table
+ * @param string $cond
+ * @return self
+ * @throws Exception
+ */
+ public function leftJoin($table, $cond = null)
+ {
+ return $this->joinInternal('LEFT', $table, $cond);
+ }
+
+ /**
+ * right join
+ *
+ * @param string $table
+ * @param string $cond
+ * @return self
+ * @throws Exception
+ */
+ public function rightJoin($table, $cond = null)
+ {
+ return $this->joinInternal('RIGHT', $table, $cond);
+ }
+
+ /**
+ * joinSubSelect
+ *
+ * @param string $join inner, left, natural
+ * @param string $spec
+ * @param string $name sub-select 的别名
+ * @param string $cond
+ * @return self
+ * @throws Exception
+ */
+ public function joinSubSelect($join, $spec, $name, $cond = null)
+ {
+ if (!$this->from) {
+ throw new \Exception('Cannot join() without from() first.');
+ }
+
+ $join = strtoupper(ltrim("$join JOIN"));
+ $name = $this->quoteName($name);
+ $cond = $this->fixJoinCondition($cond);
+ $this->from[$this->from_key][] = rtrim("$join ($spec) AS $name $cond");
+ return $this;
+ }
+
+ /**
+ * group by 语句
+ *
+ * @param array $cols
+ * @return self
+ */
+ public function groupBy(array $cols)
+ {
+ foreach ($cols as $col) {
+ $this->group_by[] = $this->quoteNamesIn($col);
+ }
+ return $this;
+ }
+
+ /**
+ * having 语句
+ *
+ * @param string $cond
+ * @return self
+ */
+ public function having($cond)
+ {
+ $this->addClauseCondWithBind('having', 'AND', func_get_args());
+ return $this;
+ }
+
+ /**
+ * or having 语句
+ *
+ * @param string $cond The HAVING condition.
+ * @return self
+ */
+ public function orHaving($cond)
+ {
+ $this->addClauseCondWithBind('having', 'OR', func_get_args());
+ return $this;
+ }
+
+ /**
+ * 设置每页的记录数量
+ *
+ * @param int $page
+ * @return self
+ */
+ public function page($page)
+ {
+ $this->limit = 0;
+ $this->offset = 0;
+
+ $page = (int)$page;
+ if ($page > 0) {
+ $this->limit = $this->paging;
+ $this->offset = $this->paging * ($page - 1);
+ }
+ return $this;
+ }
+
+ /**
+ * union
+ *
+ * @return self
+ */
+ public function union()
+ {
+ $this->union[] = $this->build() . ' UNION';
+ $this->reset();
+ return $this;
+ }
+
+ /**
+ * unionAll
+ *
+ * @return self
+ */
+ public function unionAll()
+ {
+ $this->union[] = $this->build() . ' UNION ALL';
+ $this->reset();
+ return $this;
+ }
+
+ /**
+ * 重置
+ */
+ protected function reset()
+ {
+ $this->resetFlags();
+ $this->cols = array();
+ $this->from = array();
+ $this->from_key = -1;
+ $this->where = array();
+ $this->group_by = array();
+ $this->having = array();
+ $this->order_by = array();
+ $this->limit = 0;
+ $this->offset = 0;
+ $this->for_update = false;
+ }
+
+ /**
+ * 清除所有数据
+ */
+ protected function resetAll()
+ {
+ $this->union = array();
+ $this->for_update = false;
+ $this->cols = array();
+ $this->from = array();
+ $this->from_key = -1;
+ $this->group_by = array();
+ $this->having = array();
+ $this->bind_having = array();
+ $this->paging = 10;
+ $this->bind_values = array();
+ $this->where = array();
+ $this->bind_where = array();
+ $this->order_by = array();
+ $this->limit = 0;
+ $this->offset = 0;
+ $this->flags = array();
+ $this->table = '';
+ $this->last_insert_id_names = array();
+ $this->col_values = array();
+ $this->returning = array();
+ $this->parameters = array();
+ }
+
+ /**
+ * 创建 SELECT SQL
+ *
+ * @return string
+ */
+ protected function buildSELECT()
+ {
+ return 'SELECT'
+ . $this->buildFlags()
+ . $this->buildCols()
+ . $this->buildFrom()
+ . $this->buildWhere()
+ . $this->buildGroupBy()
+ . $this->buildHaving()
+ . $this->buildOrderBy()
+ . $this->buildLimit()
+ . $this->buildForUpdate();
+ }
+
+ /**
+ * 创建 DELETE SQL
+ */
+ protected function buildDELETE()
+ {
+ return 'DELETE'
+ . $this->buildFlags()
+ . $this->buildFrom()
+ . $this->buildWhere()
+ . $this->buildOrderBy()
+ . $this->buildLimit()
+ . $this->buildReturning();
+ }
+
+ /**
+ * 生成 SELECT 列语句
+ *
+ * @return string
+ * @throws Exception
+ */
+ protected function buildCols()
+ {
+ if (!$this->cols) {
+ throw new Exception('No columns in the SELECT.');
+ }
+
+ $cols = array();
+ foreach ($this->cols as $key => $val) {
+ if (is_int($key)) {
+ $cols[] = $this->quoteNamesIn($val);
+ } else {
+ $cols[] = $this->quoteNamesIn("$val AS $key");
+ }
+ }
+
+ return $this->indentCsv($cols);
+ }
+
+ /**
+ * 生成 FROM 语句.
+ *
+ * @return string
+ */
+ protected function buildFrom()
+ {
+ if (!$this->from) {
+ return '';
+ }
+
+ $refs = array();
+ foreach ($this->from as $from) {
+ $refs[] = implode(' ', $from);
+ }
+ return ' FROM' . $this->indentCsv($refs);
+ }
+
+ /**
+ * 生成 GROUP BY 语句.
+ *
+ * @return string
+ */
+ protected function buildGroupBy()
+ {
+ if (!$this->group_by) {
+ return '';
+ }
+ return ' GROUP BY' . $this->indentCsv($this->group_by);
+ }
+
+ /**
+ * 生成 HAVING 语句.
+ *
+ * @return string
+ */
+ protected function buildHaving()
+ {
+ if (!$this->having) {
+ return '';
+ }
+ return ' HAVING' . $this->indent($this->having);
+ }
+
+ /**
+ * 生成 FOR UPDATE 语句
+ *
+ * @return string
+ */
+ protected function buildForUpdate()
+ {
+ if (!$this->for_update) {
+ return '';
+ }
+ return ' FOR UPDATE';
+ }
+
+ /**
+ * where
+ *
+ * @param string|array $cond
+ * @return self
+ */
+ public function where($cond)
+ {
+ if (is_array($cond)) {
+ foreach ($cond as $key => $val) {
+ if (is_string($key)) {
+ $this->addWhere('AND', array($key, $val));
+ } else {
+ $this->addWhere('AND', array($val));
+ }
+ }
+ } else {
+ $this->addWhere('AND', func_get_args());
+ }
+ return $this;
+ }
+
+ /**
+ * or where
+ *
+ * @param string|array $cond
+ * @return self
+ */
+ public function orWhere($cond)
+ {
+ if (is_array($cond)) {
+ foreach ($cond as $key => $val) {
+ if (is_string($key)) {
+ $this->addWhere('OR', array($key, $val));
+ } else {
+ $this->addWhere('OR', array($val));
+ }
+ }
+ } else {
+ $this->addWhere('OR', func_get_args());
+ }
+ return $this;
+ }
+
+ /**
+ * limit
+ *
+ * @param int $limit
+ * @return self
+ */
+ public function limit($limit)
+ {
+ $this->limit = (int)$limit;
+ return $this;
+ }
+
+ /**
+ * limit offset
+ *
+ * @param int $offset
+ * @return self
+ */
+ public function offset($offset)
+ {
+ $this->offset = (int)$offset;
+ return $this;
+ }
+
+ /**
+ * orderby.
+ *
+ * @param array $cols
+ * @return self
+ */
+ public function orderBy(array $cols)
+ {
+ return $this->addOrderBy($cols);
+ }
+
+ /**
+ * order by ASC OR DESC
+ *
+ * @param array $cols
+ * @param bool $order_asc
+ * @return self
+ */
+ public function orderByASC(array $cols, $order_asc = true)
+ {
+ $this->order_asc = $order_asc;
+ return $this->addOrderBy($cols);
+ }
+
+ /**
+ * order by DESC
+ *
+ * @param array $cols
+ * @return self
+ */
+ public function orderByDESC(array $cols)
+ {
+ $this->order_asc = false;
+ return $this->addOrderBy($cols);
+ }
+
+ // -------------abstractquery----------
+ /**
+ * 返回逗号分隔的字符串
+ *
+ * @param array $list
+ * @return string
+ */
+ protected function indentCsv(array $list)
+ {
+ return ' ' . implode(',', $list);
+ }
+
+ /**
+ * 返回空格分隔的字符串
+ *
+ * @param array $list
+ * @return string
+ */
+ protected function indent(array $list)
+ {
+ return ' ' . implode(' ', $list);
+ }
+
+ /**
+ * 批量为占位符绑定值
+ *
+ * @param array $bind_values
+ * @return self
+ *
+ */
+ public function bindValues(array $bind_values)
+ {
+ foreach ($bind_values as $key => $val) {
+ $this->bindValue($key, $val);
+ }
+ return $this;
+ }
+
+ /**
+ * 单个为占位符绑定值
+ *
+ * @param string $name
+ * @param mixed $value
+ * @return self
+ */
+ public function bindValue($name, $value)
+ {
+ $this->bind_values[$name] = $value;
+ return $this;
+ }
+
+ /**
+ * 生成 flag
+ *
+ * @return string
+ */
+ protected function buildFlags()
+ {
+ if (!$this->flags) {
+ return '';
+ }
+ return ' ' . implode(' ', array_keys($this->flags));
+ }
+
+ /**
+ * 设置 flag.
+ *
+ * @param string $flag
+ * @param bool $enable
+ */
+ protected function setFlag($flag, $enable = true)
+ {
+ if ($enable) {
+ $this->flags[$flag] = true;
+ } else {
+ unset($this->flags[$flag]);
+ }
+ }
+
+ /**
+ * 重置 flag
+ */
+ protected function resetFlags()
+ {
+ $this->flags = array();
+ }
+
+ /**
+ *
+ * 添加 where 语句
+ *
+ * @param string $andor 'AND' or 'OR
+ * @param array $conditions
+ * @return self
+ *
+ */
+ protected function addWhere($andor, $conditions)
+ {
+ $this->addClauseCondWithBind('where', $andor, $conditions);
+ return $this;
+ }
+
+ /**
+ * 添加条件和绑定值
+ *
+ * @param string $clause where 、having等
+ * @param string $andor AND、OR等
+ * @param array $conditions
+ */
+ protected function addClauseCondWithBind($clause, $andor, $conditions)
+ {
+ $cond = array_shift($conditions);
+ $cond = $this->quoteNamesIn($cond);
+
+ $bind =& $this->{"bind_{$clause}"};
+ foreach ($conditions as $value) {
+ $bind[] = $value;
+ }
+
+ $clause =& $this->$clause;
+ if ($clause) {
+ $clause[] = "$andor $cond";
+ } else {
+ $clause[] = $cond;
+ }
+ }
+
+ /**
+ * 生成 where 语句
+ *
+ * @return string
+ */
+ protected function buildWhere()
+ {
+ if (!$this->where) {
+ return '';
+ }
+ return ' WHERE' . $this->indent($this->where);
+ }
+
+ /**
+ * 增加 order by
+ *
+ * @param array $spec The columns and direction to order by.
+ * @return self
+ */
+ protected function addOrderBy(array $spec)
+ {
+ foreach ($spec as $col) {
+ $this->order_by[] = $this->quoteNamesIn($col);
+ }
+ return $this;
+ }
+
+ /**
+ * 生成 order by 语句
+ *
+ * @return string
+ */
+ protected function buildOrderBy()
+ {
+ if (!$this->order_by) {
+ return '';
+ }
+
+ if ($this->order_asc) {
+ return ' ORDER BY' . $this->indentCsv($this->order_by) . ' ASC';
+ } else {
+ return ' ORDER BY' . $this->indentCsv($this->order_by) . ' DESC';
+ }
+ }
+
+ /**
+ * 生成 limit 语句
+ *
+ * @return string
+ */
+ protected function buildLimit()
+ {
+ $has_limit = $this->type == 'DELETE' || $this->type == 'UPDATE';
+ $has_offset = $this->type == 'SELECT';
+
+ if ($has_offset && $this->limit) {
+ $clause = " LIMIT {$this->limit}";
+ if ($this->offset) {
+ $clause .= " OFFSET {$this->offset}";
+ }
+ return $clause;
+ } elseif ($has_limit && $this->limit) {
+ return " LIMIT {$this->limit}";
+ }
+ return '';
+ }
+
+ /**
+ * Quotes
+ *
+ * @param string $spec
+ * @return string|array
+ */
+ public function quoteName($spec)
+ {
+ $spec = trim($spec);
+ $seps = array(' AS ', ' ', '.');
+ foreach ($seps as $sep) {
+ $pos = strripos($spec, $sep);
+ if ($pos) {
+ return $this->quoteNameWithSeparator($spec, $sep, $pos);
+ }
+ }
+ return $this->replaceName($spec);
+ }
+
+ /**
+ * 指定分隔符的 Quotes
+ *
+ * @param string $spec
+ * @param string $sep
+ * @param int $pos
+ * @return string
+ */
+ protected function quoteNameWithSeparator($spec, $sep, $pos)
+ {
+ $len = strlen($sep);
+ $part1 = $this->quoteName(substr($spec, 0, $pos));
+ $part2 = $this->replaceName(substr($spec, $pos + $len));
+ return "{$part1}{$sep}{$part2}";
+ }
+
+ /**
+ * Quotes "table.col" 格式的字符串
+ *
+ * @param string $text
+ * @return string|array
+ */
+ public function quoteNamesIn($text)
+ {
+ $list = $this->getListForQuoteNamesIn($text);
+ $last = count($list) - 1;
+ $text = null;
+ foreach ($list as $key => $val) {
+ if (($key + 1) % 3) {
+ $text .= $this->quoteNamesInLoop($val, $key == $last);
+ }
+ }
+ return $text;
+ }
+
+ /**
+ * 返回 quote 元素列表
+ *
+ * @param string $text
+ * @return array
+ */
+ protected function getListForQuoteNamesIn($text)
+ {
+ $apos = "'";
+ $quot = '"';
+ return preg_split(
+ "/(($apos+|$quot+|\\$apos+|\\$quot+).*?\\2)/",
+ $text,
+ -1,
+ PREG_SPLIT_DELIM_CAPTURE
+ );
+ }
+
+ /**
+ * 循环 quote
+ *
+ * @param string $val
+ * @param bool $is_last
+ * @return string
+ */
+ protected function quoteNamesInLoop($val, $is_last)
+ {
+ if ($is_last) {
+ return $this->replaceNamesAndAliasIn($val);
+ }
+ return $this->replaceNamesIn($val);
+ }
+
+ /**
+ * 替换成别名
+ *
+ * @param string $val
+ * @return string
+ */
+ protected function replaceNamesAndAliasIn($val)
+ {
+ $quoted = $this->replaceNamesIn($val);
+ $pos = strripos($quoted, ' AS ');
+ if ($pos !== false) {
+ $bracket = strripos($quoted, ')');
+ if ($bracket === false) {
+ $alias = $this->replaceName(substr($quoted, $pos + 4));
+ $quoted = substr($quoted, 0, $pos) . " AS $alias";
+ }
+ }
+ return $quoted;
+ }
+
+ /**
+ * Quotes name
+ *
+ * @param string $name
+ * @return string
+ */
+ protected function replaceName($name)
+ {
+ $name = trim($name);
+ if ($name == '*') {
+ return $name;
+ }
+ return '`' . $name . '`';
+ }
+
+ /**
+ * Quotes
+ *
+ * @param string $text
+ * @return string|array
+ */
+ protected function replaceNamesIn($text)
+ {
+ $is_string_literal = strpos($text, "'") !== false
+ || strpos($text, '"') !== false;
+ if ($is_string_literal) {
+ return $text;
+ }
+
+ $word = '[a-z_][a-z0-9_]*';
+
+ $find = "/(\\b)($word)\\.($word)(\\b)/i";
+
+ $repl = '$1`$2`.`$3`$4';
+
+ $text = preg_replace($find, $repl, $text);
+
+ return $text;
+ }
+
+ // ---------- insert --------------
+ /**
+ * 设置 `table.column` 与 last-insert-id 的映射
+ *
+ * @param array $last_insert_id_names
+ */
+ public function setLastInsertIdNames(array $last_insert_id_names)
+ {
+ $this->last_insert_id_names = $last_insert_id_names;
+ }
+
+ /**
+ * insert into.
+ *
+ * @param string $table
+ * @return self
+ */
+ public function into($table)
+ {
+ $this->table = $this->quoteName($table);
+ return $this;
+ }
+
+ /**
+ * 生成 INSERT 语句
+ *
+ * @return string
+ */
+ protected function buildINSERT()
+ {
+ return 'INSERT'
+ . $this->buildFlags()
+ . $this->buildInto()
+ . $this->buildValuesForInsert()
+ . $this->buildReturning();
+ }
+
+ /**
+ * 生成 INTO 语句
+ *
+ * @return string
+ */
+ protected function buildInto()
+ {
+ return " INTO " . $this->table;
+ }
+
+ /**
+ * PDO::lastInsertId()
+ *
+ * @param string $col
+ * @return mixed
+ */
+ public function getLastInsertIdName($col)
+ {
+ $key = str_replace('`', '', $this->table) . '.' . $col;
+ if (isset($this->last_insert_id_names[$key])) {
+ return $this->last_insert_id_names[$key];
+ }
+
+ return null;
+ }
+
+ /**
+ * 设置一列,如果有第二各参数,则把第二个参数绑定在占位符上
+ *
+ * @param string $col
+ * @return self
+ */
+ public function col($col)
+ {
+ return call_user_func_array(array($this, 'addCol'), func_get_args());
+ }
+
+ /**
+ * 设置多列
+ *
+ * @param array $cols
+ * @return self
+ */
+ public function cols(array $cols)
+ {
+ if ($this->type == 'SELECT') {
+ foreach ($cols as $key => $val) {
+ $this->addColSELECT($key, $val);
+ }
+ return $this;
+ }
+ return $this->addCols($cols);
+ }
+
+ /**
+ * 直接设置列的值
+ *
+ * @param string $col
+ * @param string $value
+ * @return self
+ */
+ public function set($col, $value)
+ {
+ return $this->setCol($col, $value);
+ }
+
+ /**
+ * 为 INSERT 语句绑定值
+ *
+ * @return string
+ */
+ protected function buildValuesForInsert()
+ {
+ return ' (' . $this->indentCsv(array_keys($this->col_values)) . ') VALUES (' .
+ $this->indentCsv(array_values($this->col_values)) . ')';
+ }
+
+ // ------update-------
+ /**
+ * 更新哪个表
+ *
+ * @param string $table
+ * @return self
+ */
+ public function table($table)
+ {
+ $this->table = $this->quoteName($table);
+ return $this;
+ }
+
+ /**
+ * 生成完整 SQL 语句
+ *
+ * @return string
+ * @throws Exception
+ */
+ protected function build()
+ {
+ switch ($this->type) {
+ case 'DELETE':
+ return $this->buildDELETE();
+ case 'INSERT':
+ return $this->buildINSERT();
+ case 'UPDATE':
+ return $this->buildUPDATE();
+ case 'SELECT':
+ return $this->buildSELECT();
+ }
+ throw new Exception("type empty");
+ }
+
+ /**
+ * 生成更新的 SQL 语句
+ */
+ protected function buildUPDATE()
+ {
+ return 'UPDATE'
+ . $this->buildFlags()
+ . $this->buildTable()
+ . $this->buildValuesForUpdate()
+ . $this->buildWhere()
+ . $this->buildOrderBy()
+ . $this->buildLimit()
+ . $this->buildReturning();
+ }
+
+ /**
+ * 哪个表
+ *
+ * @return string
+ */
+ protected function buildTable()
+ {
+ return " {$this->table}";
+ }
+
+ /**
+ * 为更新语句绑定值
+ *
+ * @return string
+ */
+ protected function buildValuesForUpdate()
+ {
+ $values = array();
+ foreach ($this->col_values as $col => $value) {
+ $values[] = "{$col} = {$value}";
+ }
+ return ' SET' . $this->indentCsv($values);
+ }
+
+ // ----------Dml---------------
+ /**
+ * 获取绑定的值
+ *
+ * @return array
+ */
+ public function getBindValuesCOMMON()
+ {
+ $bind_values = $this->bind_values;
+ $i = 1;
+ foreach ($this->bind_where as $val) {
+ $bind_values[$i] = $val;
+ $i++;
+ }
+ return $bind_values;
+ }
+
+ /**
+ * 设置列
+ *
+ * @param string $col
+ * @return self
+ */
+ protected function addCol($col)
+ {
+ $key = $this->quoteName($col);
+ $this->col_values[$key] = ":$col";
+ $args = func_get_args();
+ if (count($args) > 1) {
+ $this->bindValue($col, $args[1]);
+ }
+ return $this;
+ }
+
+ /**
+ * 设置多个列
+ *
+ * @param array $cols
+ * @return self
+ */
+ protected function addCols(array $cols)
+ {
+ foreach ($cols as $key => $val) {
+ if (is_int($key)) {
+ $this->addCol($val);
+ } else {
+ $this->addCol($key, $val);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * 设置单列的值
+ *
+ * @param string $col .
+ * @param string $value
+ * @return self
+ */
+ protected function setCol($col, $value)
+ {
+ if ($value === null) {
+ $value = 'NULL';
+ }
+
+ $key = $this->quoteName($col);
+ $value = $this->quoteNamesIn($value);
+ $this->col_values[$key] = $value;
+ return $this;
+ }
+
+ /**
+ * 增加返回的列
+ *
+ * @param array $cols
+ * @return self
+ *
+ */
+ protected function addReturning(array $cols)
+ {
+ foreach ($cols as $col) {
+ $this->returning[] = $this->quoteNamesIn($col);
+ }
+ return $this;
+ }
+
+ /**
+ * 生成 RETURNING 语句
+ *
+ * @return string
+ */
+ protected function buildReturning()
+ {
+ if (!$this->returning) {
+ return '';
+ }
+ return ' RETURNING' . $this->indentCsv($this->returning);
+ }
+
+ /**
+ * 构造函数
+ *
+ * @param string $host
+ * @param int $port
+ * @param string $user
+ * @param string $password
+ * @param string $db_name
+ * @param string $charset
+ */
+ public function __construct($host, $port, $user, $password, $db_name, $charset = 'utf8')
+ {
+ $this->settings = array(
+ 'host' => $host,
+ 'port' => $port,
+ 'user' => $user,
+ 'password' => $password,
+ 'dbname' => $db_name,
+ 'charset' => $charset,
+ );
+ $this->connect();
+ }
+
+ /**
+ * 创建 PDO 实例
+ */
+ protected function connect()
+ {
+ $dsn = 'mysql:dbname=' . $this->settings["dbname"] . ';host=' .
+ $this->settings["host"] . ';port=' . $this->settings['port'];
+ $this->pdo = new PDO($dsn, $this->settings["user"], $this->settings["password"],
+ array(
+ PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . (!empty($this->settings['charset']) ?
+ $this->settings['charset'] : 'utf8')
+ ));
+ $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ $this->pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
+ $this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
+ }
+
+ /**
+ * 关闭连接
+ */
+ public function closeConnection()
+ {
+ $this->pdo = null;
+ }
+
+ /**
+ * 执行
+ *
+ * @param string $query
+ * @param string $parameters
+ * @throws PDOException
+ */
+ protected function execute($query, $parameters = "")
+ {
+ try {
+ if (is_null($this->pdo)) {
+ $this->connect();
+ }
+ $this->sQuery = @$this->pdo->prepare($query);
+ $this->bindMore($parameters);
+ if (!empty($this->parameters)) {
+ foreach ($this->parameters as $param) {
+ $this->sQuery->bindParam($param[0], $param[1]);
+ }
+ }
+ $this->success = $this->sQuery->execute();
+ } catch (PDOException $e) {
+ // 服务端断开时重连一次
+ if ($e->errorInfo[1] == 2006 || $e->errorInfo[1] == 2013) {
+ $this->closeConnection();
+ $this->connect();
+
+ try {
+ $this->sQuery = $this->pdo->prepare($query);
+ $this->bindMore($parameters);
+ if (!empty($this->parameters)) {
+ foreach ($this->parameters as $param) {
+ $this->sQuery->bindParam($param[0], $param[1]);
+ }
+ }
+ $this->success = $this->sQuery->execute();
+ } catch (PDOException $ex) {
+ $this->rollBackTrans();
+ throw $ex;
+ }
+ } else {
+ $this->rollBackTrans();
+ $msg = $e->getMessage();
+ $err_msg = "SQL:".$this->lastSQL()." ".$msg;
+ $exception = new \PDOException($err_msg, (int)$e->getCode());
+ throw $exception;
+ }
+ }
+ $this->parameters = array();
+ }
+
+ /**
+ * 绑定
+ *
+ * @param string $para
+ * @param string $value
+ */
+ public function bind($para, $value)
+ {
+ if (is_string($para)) {
+ $this->parameters[sizeof($this->parameters)] = array(":" . $para, $value);
+ } else {
+ $this->parameters[sizeof($this->parameters)] = array($para, $value);
+ }
+ }
+
+ /**
+ * 绑定多个
+ *
+ * @param array $parray
+ */
+ public function bindMore($parray)
+ {
+ if (empty($this->parameters) && is_array($parray)) {
+ $columns = array_keys($parray);
+ foreach ($columns as $i => &$column) {
+ $this->bind($column, $parray[$column]);
+ }
+ }
+ }
+
+ /**
+ * 执行 SQL
+ *
+ * @param string $query
+ * @param array $params
+ * @param int $fetchmode
+ * @return mixed
+ */
+ public function query($query = '', $params = null, $fetchmode = PDO::FETCH_ASSOC)
+ {
+ $query = trim($query);
+ if (empty($query)) {
+ $query = $this->build();
+ if (!$params) {
+ $params = $this->getBindValues();
+ }
+ }
+
+ $this->resetAll();
+ $this->lastSql = $query;
+
+ $this->execute($query, $params);
+
+ $rawStatement = explode(" ", $query);
+
+ $statement = strtolower(trim($rawStatement[0]));
+ if ($statement === 'select' || $statement === 'show') {
+ return $this->sQuery->fetchAll($fetchmode);
+ } elseif ($statement === 'update' || $statement === 'delete' || $statement === 'replace') {
+ return $this->sQuery->rowCount();
+ } elseif ($statement === 'insert') {
+ if ($this->sQuery->rowCount() > 0) {
+ return $this->lastInsertId();
+ }
+ } else {
+ return null;
+ }
+
+ return null;
+ }
+
+ /**
+ * 返回一列
+ *
+ * @param string $query
+ * @param array $params
+ * @return array
+ */
+ public function column($query = '', $params = null)
+ {
+ $query = trim($query);
+ if (empty($query)) {
+ $query = $this->build();
+ if (!$params) {
+ $params = $this->getBindValues();
+ }
+ }
+
+ $this->resetAll();
+ $this->lastSql = $query;
+
+ $this->execute($query, $params);
+ $columns = $this->sQuery->fetchAll(PDO::FETCH_NUM);
+ $column = null;
+ foreach ($columns as $cells) {
+ $column[] = $cells[0];
+ }
+ return $column;
+ }
+
+ /**
+ * 返回一行
+ *
+ * @param string $query
+ * @param array $params
+ * @param int $fetchmode
+ * @return array
+ */
+ public function row($query = '', $params = null, $fetchmode = PDO::FETCH_ASSOC)
+ {
+ $query = trim($query);
+ if (empty($query)) {
+ $query = $this->build();
+ if (!$params) {
+ $params = $this->getBindValues();
+ }
+ }
+
+ $this->resetAll();
+ $this->lastSql = $query;
+
+ $this->execute($query, $params);
+ return $this->sQuery->fetch($fetchmode);
+ }
+
+ /**
+ * 返回单个值
+ *
+ * @param string $query
+ * @param array $params
+ * @return string
+ */
+ public function single($query = '', $params = null)
+ {
+ $query = trim($query);
+ if (empty($query)) {
+ $query = $this->build();
+ if (!$params) {
+ $params = $this->getBindValues();
+ }
+ }
+
+ $this->resetAll();
+ $this->lastSql = $query;
+
+ $this->execute($query, $params);
+ return $this->sQuery->fetchColumn();
+ }
+
+ /**
+ * 返回 lastInsertId
+ *
+ * @return string
+ */
+ public function lastInsertId()
+ {
+ return $this->pdo->lastInsertId();
+ }
+
+ /**
+ * 返回最后一条执行的 sql
+ *
+ * @return string
+ */
+ public function lastSQL()
+ {
+ return $this->lastSql;
+ }
+
+ /**
+ * 开始事务
+ */
+ public function beginTrans()
+ {
+ try {
+ if (is_null($this->pdo)) {
+ $this->connect();
+ }
+ return $this->pdo->beginTransaction();
+ } catch (PDOException $e) {
+ // 服务端断开时重连一次
+ if ($e->errorInfo[1] == 2006 || $e->errorInfo[1] == 2013) {
+ $this->closeConnection();
+ $this->connect();
+ return $this->pdo->beginTransaction();
+ } else {
+ throw $e;
+ }
+ }
+ }
+
+ /**
+ * 提交事务
+ */
+ public function commitTrans()
+ {
+ return $this->pdo->commit();
+ }
+
+ /**
+ * 事务回滚
+ */
+ public function rollBackTrans()
+ {
+ if ($this->pdo->inTransaction()) {
+ return $this->pdo->rollBack();
+ }
+ return true;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman.log b/addons/weliam_smartcity/vendor/workerman/workerman.log
new file mode 100644
index 0000000..3aab14a
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman.log
@@ -0,0 +1,649 @@
+2021-03-05 14:58:33 pid:1 Error: Class 'Im' not found in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\api\Im.php:32
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #18)
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\api\Im.php(36): Workerman\Worker::runAll()
+#7 {main}
+2021-03-05 14:58:33 pid:1 Worker process terminated
+2021-03-05 14:59:04 pid:1 Error: Class 'Im' not found in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\api\Im.php:32
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #18)
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\api\Im.php(36): Workerman\Worker::runAll()
+#7 {main}
+2021-03-05 14:59:04 pid:1 Worker process terminated
+2021-03-05 15:32:32 pid:1 Error: Class 'Im' not found in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\api\Im.php:32
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #18)
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\api\Im.php(36): Workerman\Worker::runAll()
+#7 {main}
+2021-03-05 15:32:32 pid:1 Worker process terminated
+2021-03-05 15:32:55 pid:1 Error: Class 'Im' not found in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\api\Im.php:32
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #18)
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\api\Im.php(36): Workerman\Worker::runAll()
+#7 {main}
+2021-03-05 15:32:55 pid:1 Worker process terminated
+2021-03-05 15:34:26 pid:1 Error: Class 'ImModuleUniapp' not found in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\api\Im.php:32
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #18)
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\api\Im.php(36): Workerman\Worker::runAll()
+#7 {main}
+2021-03-05 15:34:26 pid:1 Worker process terminated
+2021-03-05 17:20:53 pid:1 ArgumentCountError: Too few arguments to function {closure}(), 1 passed in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php on line 931 and exactly 2 expected in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:58
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(931): {closure}(Object(Workerman\Connection\TcpConnection))
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(755): Workerman\Connection\TcpConnection->destroy()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(561): Workerman\Connection\TcpConnection->doSslHandshake(Resource id #64)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #64)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(168): Workerman\Worker::runAll()
+#9 {main}
+2021-03-05 17:20:53 pid:1 Worker process terminated
+2021-03-09 16:34:34 pid:1 Error: Access to undeclared static property: handle::$table in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:139
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(40): handle->handleData()
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #67)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(204): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 16:34:34 pid:1 Worker process terminated
+2021-03-09 16:34:52 pid:1 Error: Access to undeclared static property: handle::$table in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:139
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(40): handle->handleData()
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #67)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(204): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 16:34:52 pid:1 Worker process terminated
+2021-03-09 16:35:46 pid:1 Error: Access to undeclared static property: handle::$table in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:141
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(40): handle->handleData()
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #67)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(206): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 16:35:46 pid:1 Worker process terminated
+2021-03-09 16:37:03 pid:1 Error: Access to undeclared static property: handle::$table in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:141
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(40): handle->handleData()
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #67)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(206): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 16:37:03 pid:1 Worker process terminated
+2021-03-09 16:37:46 pid:1 Error: Access to undeclared static property: handle::$table in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:142
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(41): handle->handleData()
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #68)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(207): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 16:37:46 pid:1 Worker process terminated
+2021-03-09 16:38:01 pid:1 Error: Access to undeclared static property: handle::$table in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:143
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(41): handle->handleData()
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #68)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(208): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 16:38:01 pid:1 Worker process terminated
+2021-03-09 16:53:16 pid:1 PDOException: SQLSTATE[HY000] [1045] Access denied for user ''@'localhost' (using password: NO) in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1711
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1711): PDO->__construct('mysql:dbname=;h...', NULL, NULL, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1698): Workerman\MySQL\Connection->connect()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(41): Workerman\MySQL\Connection->__construct(NULL, NULL, NULL, NULL, NULL)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2415): {closure}(Object(Workerman\Worker))
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(171): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 16:53:17 pid:1 Worker process terminated
+2021-03-09 16:54:22 pid:1 PDOException: SQLSTATE[HY000] [1045] Access denied for user ''@'localhost' (using password: NO) in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1711
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1711): PDO->__construct('mysql:dbname=;h...', NULL, NULL, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1698): Workerman\MySQL\Connection->connect()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(41): Workerman\MySQL\Connection->__construct(NULL, NULL, NULL, NULL, NULL)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2415): {closure}(Object(Workerman\Worker))
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(171): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 16:54:23 pid:1 Worker process terminated
+2021-03-09 16:55:24 pid:1 PDOException: SQLSTATE[HY000] [1045] Access denied for user ''@'localhost' (using password: NO) in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1711
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1711): PDO->__construct('mysql:dbname=;h...', NULL, NULL, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1698): Workerman\MySQL\Connection->connect()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(42): Workerman\MySQL\Connection->__construct(NULL, NULL, NULL, NULL, NULL)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2415): {closure}(Object(Workerman\Worker))
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(172): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 16:55:25 pid:1 Worker process terminated
+2021-03-09 16:55:35 pid:1 PDOException: SQLSTATE[HY000] [1045] Access denied for user ''@'localhost' (using password: NO) in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1711
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1711): PDO->__construct('mysql:dbname=;h...', NULL, NULL, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1698): Workerman\MySQL\Connection->connect()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(42): Workerman\MySQL\Connection->__construct(NULL, NULL, NULL, NULL, NULL)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2415): {closure}(Object(Workerman\Worker))
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(172): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 16:55:36 pid:1 Worker process terminated
+2021-03-09 16:55:52 pid:1 PDOException: SQLSTATE[HY000] [1045] Access denied for user ''@'localhost' (using password: NO) in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1711
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1711): PDO->__construct('mysql:dbname=;h...', NULL, NULL, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1698): Workerman\MySQL\Connection->connect()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(42): Workerman\MySQL\Connection->__construct(NULL, NULL, NULL, NULL, NULL)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2415): {closure}(Object(Workerman\Worker))
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(172): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 16:55:53 pid:1 Worker process terminated
+2021-03-09 16:59:18 pid:1 Error: Access to undeclared static property: handle::$table in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:143
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(219): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 16:59:18 pid:1 Worker process terminated
+2021-03-09 17:05:09 pid:1 Error: Access to undeclared static property: handle::$table in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:139
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(205): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 17:05:09 pid:1 Worker process terminated
+2021-03-09 17:05:13 pid:1 Error: Access to undeclared static property: handle::$table in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:139
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(205): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 17:05:13 pid:1 Worker process terminated
+2021-03-09 17:05:18 pid:1 Error: Access to undeclared static property: handle::$table in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:139
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(205): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 17:05:18 pid:1 Worker process terminated
+2021-03-09 17:05:30 pid:1 Error: Access to undeclared static property: handle::$table in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:139
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(205): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 17:05:30 pid:1 Worker process terminated
+2021-03-09 17:06:02 pid:1 Error: Access to undeclared static property: handle::$table in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:139
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(206): Workerman\Worker::runAll()
+#8 {main}
+2021-03-09 17:06:02 pid:1 Worker process terminated
+2021-03-09 17:20:39 pid:1 PDOException: SQL:INSERT INTO ``ims_wlmerchant_im`` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ims_wlmerchant_im`` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type' at line 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO ``i...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(100): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(222): Workerman\Worker::runAll()
+#10 {main}
+2021-03-09 17:20:39 pid:1 Worker process terminated
+2021-03-09 17:21:21 pid:1 PDOException: SQL:INSERT INTO ``ims_wlmerchant_im`` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ims_wlmerchant_im`` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type' at line 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO ``i...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(101): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(223): Workerman\Worker::runAll()
+#10 {main}
+2021-03-09 17:21:21 pid:1 Worker process terminated
+2021-03-12 10:02:19 pid:1 Error: Call to a member function send() on int in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:203
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(178): handle->socketSend(3, '\xE9\x80\x9A\xE8\xAE\xAF\xE8\xAE\xB0\xE5\xBD\x95', 4, 5, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(222): Workerman\Worker::runAll()
+#9 {main}
+2021-03-12 10:02:19 pid:1 Worker process terminated
+2021-03-12 10:02:52 pid:1 Error: Call to a member function send() on int in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:203
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(178): handle->socketSend(24, '\xE9\x80\x9A\xE8\xAE\xAF\xE8\xAE\xB0\xE5\xBD\x95', 4, 5, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(222): Workerman\Worker::runAll()
+#9 {main}
+2021-03-12 10:02:52 pid:1 Worker process terminated
+2021-03-12 11:16:54 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:200
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(173): handle->socketSend(3, '\xE9\x80\x9A\xE8\xAE\xAF\xE8\xAE\xB0\xE5\xBD\x95', 4, 5, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(292): Workerman\Worker::runAll()
+#9 {main}
+2021-03-12 11:16:54 pid:1 Worker process terminated
+2021-03-12 11:17:20 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:200
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(173): handle->socketSend(3, '\xE9\x80\x9A\xE8\xAE\xAF\xE8\xAE\xB0\xE5\xBD\x95', 4, 5, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(292): Workerman\Worker::runAll()
+#9 {main}
+2021-03-12 11:17:20 pid:1 Worker process terminated
+2021-03-12 11:18:23 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:200
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(173): handle->socketSend(3, '\xE9\x80\x9A\xE8\xAE\xAF\xE8\xAE\xB0\xE5\xBD\x95', 4, 5, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":4,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(292): Workerman\Worker::runAll()
+#9 {main}
+2021-03-12 11:18:23 pid:1 Worker process terminated
+2021-03-12 11:18:57 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:200
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(103): handle->socketSend(24, '\xE8\xBF\x99\xE9\x87\x8C\xE6\x98\xAF\xE5\x8F\x91\xE9\x80\x81...', 2, 0)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(296): Workerman\Worker::runAll()
+#9 {main}
+2021-03-12 11:18:57 pid:1 Worker process terminated
+2021-03-12 11:19:18 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:200
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(103): handle->socketSend(24, '\xE8\xBF\x99\xE9\x87\x8C\xE6\x98\xAF\xE5\x8F\x91\xE9\x80\x81...', 2, 0)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(296): Workerman\Worker::runAll()
+#9 {main}
+2021-03-12 11:19:18 pid:1 Worker process terminated
+2021-03-12 11:20:17 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:204
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(103): handle->socketSend(24, '\xE8\xBF\x99\xE9\x87\x8C\xE6\x98\xAF\xE5\x8F\x91\xE9\x80\x81...', 2, 0)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(249): Workerman\Worker::runAll()
+#9 {main}
+2021-03-12 11:20:17 pid:1 Worker process terminated
+2021-03-18 11:02:30 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:218
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(119): handle->socketSend(24, '\xE5\x8D\xB3\xE6\x97\xB6\xE9\x80\x9A\xE8\xAE\xAF\xE4\xBF\xA1...', 2, 0, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(265): Workerman\Worker::runAll()
+#9 {main}
+2021-03-18 11:02:30 pid:1 Worker process terminated
+2021-03-18 11:03:16 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:218
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(119): handle->socketSend(24, '\xE5\x8D\xB3\xE6\x97\xB6\xE9\x80\x9A\xE8\xAE\xAF\xE4\xBF\xA1...', 2, 0, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(265): Workerman\Worker::runAll()
+#9 {main}
+2021-03-18 11:03:16 pid:1 Worker process terminated
+2021-03-18 11:05:22 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:219
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(120): handle->socketSend(24, '\xE5\x8D\xB3\xE6\x97\xB6\xE9\x80\x9A\xE8\xAE\xAF\xE4\xBF\xA1...', 2, 0, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(266): Workerman\Worker::runAll()
+#9 {main}
+2021-03-18 11:05:22 pid:1 Worker process terminated
+2021-03-18 11:05:54 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:217
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(118): handle->socketSend(24, '\xE5\x8D\xB3\xE6\x97\xB6\xE9\x80\x9A\xE8\xAE\xAF\xE4\xBF\xA1...', 2, 0, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(264): Workerman\Worker::runAll()
+#9 {main}
+2021-03-18 11:05:54 pid:1 Worker process terminated
+2021-03-18 11:06:19 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:217
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(118): handle->socketSend(24, '\xE5\x8D\xB3\xE6\x97\xB6\xE9\x80\x9A\xE8\xAE\xAF\xE4\xBF\xA1...', 2, 0, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(264): Workerman\Worker::runAll()
+#9 {main}
+2021-03-18 11:06:19 pid:1 Worker process terminated
+2021-03-18 11:06:37 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:216
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(118): handle->socketSend(24, '\xE5\x8D\xB3\xE6\x97\xB6\xE9\x80\x9A\xE8\xAE\xAF\xE4\xBF\xA1...', 2, 0, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(263): Workerman\Worker::runAll()
+#9 {main}
+2021-03-18 11:06:37 pid:1 Worker process terminated
+2021-03-18 11:07:08 pid:1 Error: Call to a member function send() on null in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php:216
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(118): handle->socketSend(24, '\xE5\x8D\xB3\xE6\x97\xB6\xE9\x80\x9A\xE8\xAE\xAF\xE4\xBF\xA1...', 2, 0, Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(263): Workerman\Worker::runAll()
+#9 {main}
+2021-03-18 11:07:08 pid:1 Worker process terminated
+2021-03-18 11:14:16 pid:1 PDOException: SQL:INSERT INTO `ims_wlmerchant_im` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x98\x8A\xF0\x9F...' for column 'content' at row 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO `im...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(100): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(280): Workerman\Worker::runAll()
+#10 {main}
+2021-03-18 11:14:16 pid:1 Worker process terminated
+2021-03-18 11:16:05 pid:1 PDOException: SQL:INSERT INTO `ims_wlmerchant_im` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x98\xA2\xF0\x9F...' for column 'content' at row 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO `im...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(100): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(280): Workerman\Worker::runAll()
+#10 {main}
+2021-03-18 11:16:05 pid:1 Worker process terminated
+2021-03-18 11:17:07 pid:1 PDOException: SQL:INSERT INTO `ims_wlmerchant_im` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\xA4\xA6\xE2\x80...' for column 'content' at row 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO `im...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(100): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(280): Workerman\Worker::runAll()
+#10 {main}
+2021-03-18 11:17:07 pid:1 Worker process terminated
+2021-03-18 11:17:36 pid:1 PDOException: SQL:INSERT INTO `ims_wlmerchant_im` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x8E\xB6' for column 'content' at row 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO `im...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(101): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(281): Workerman\Worker::runAll()
+#10 {main}
+2021-03-18 11:17:36 pid:1 Worker process terminated
+2021-03-18 11:18:25 pid:1 PDOException: SQL:INSERT INTO `ims_wlmerchant_im` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x98\x81' for column 'content' at row 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO `im...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(101): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(281): Workerman\Worker::runAll()
+#10 {main}
+2021-03-18 11:18:25 pid:1 Worker process terminated
+2021-03-18 11:18:46 pid:1 PDOException: SQL:INSERT INTO `ims_wlmerchant_im` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x8E\xB6' for column 'content' at row 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO `im...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(100): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(281): Workerman\Worker::runAll()
+#10 {main}
+2021-03-18 11:18:46 pid:1 Worker process terminated
+2021-03-18 11:19:21 pid:1 PDOException: SQL:INSERT INTO `ims_wlmerchant_im` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\xA4\xA6\xE2\x80...' for column 'content' at row 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO `im...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(100): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(281): Workerman\Worker::runAll()
+#10 {main}
+2021-03-18 11:19:21 pid:1 Worker process terminated
+2021-03-18 11:19:46 pid:1 PDOException: SQL:INSERT INTO `ims_wlmerchant_im` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x98\x8D' for column 'content' at row 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO `im...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(100): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(282): Workerman\Worker::runAll()
+#10 {main}
+2021-03-18 11:19:46 pid:1 Worker process terminated
+2021-03-18 11:20:11 pid:1 PDOException: SQL:INSERT INTO `ims_wlmerchant_im` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x90\xB1\xE2\x80...' for column 'content' at row 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO `im...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(100): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(283): Workerman\Worker::runAll()
+#10 {main}
+2021-03-18 11:20:11 pid:1 Worker process terminated
+2021-03-18 11:20:34 pid:1 PDOException: SQL:INSERT INTO `ims_wlmerchant_im` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x98\x81' for column 'content' at row 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO `im...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(101): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(284): Workerman\Worker::runAll()
+#10 {main}
+2021-03-18 11:20:34 pid:1 Worker process terminated
+2021-03-18 11:21:27 pid:1 PDOException: SQL:INSERT INTO `ims_wlmerchant_im` ( `uniacid`,`send_id`,`send_type`,`receive_id`,`receive_type`,`create_time`,`type`,`content`) VALUES ( :uniacid,:send_id,:send_type,:receive_id,:receive_type,:create_time,:type,:content) SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x98\x8D' for column 'content' at row 1 in D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php:1770
+Stack trace:
+#0 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\mysql\src\Connection.php(1828): Workerman\MySQL\Connection->execute('INSERT INTO `im...', Array)
+#1 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(101): Workerman\MySQL\Connection->query()
+#2 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(47): handle->handleData()
+#3 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Connection\TcpConnection.php(637): {closure}(Object(Workerman\Connection\TcpConnection), '{"im_type":2,"s...')
+#4 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Events\Select.php(293): Workerman\Connection\TcpConnection->baseRead(Resource id #70)
+#5 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(2430): Workerman\Events\Select->loop()
+#6 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1418): Workerman\Worker->run()
+#7 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(1361): Workerman\Worker::forkWorkersForWindows()
+#8 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\vendor\workerman\workerman\Worker.php(542): Workerman\Worker::forkWorkers()
+#9 D:\Software\phpstudy_pro\WWW\merchant\addons\weliam_smartcity\core\common\Im.php(281): Workerman\Worker::runAll()
+#10 {main}
+2021-03-18 11:21:27 pid:1 Worker process terminated
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/.gitignore b/addons/weliam_smartcity/vendor/workerman/workerman/.gitignore
new file mode 100644
index 0000000..f3f9e18
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/.gitignore
@@ -0,0 +1,6 @@
+logs
+.buildpath
+.project
+.settings
+.idea
+.DS_Store
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Autoloader.php b/addons/weliam_smartcity/vendor/workerman/workerman/Autoloader.php
new file mode 100644
index 0000000..7d760e9
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Autoloader.php
@@ -0,0 +1,69 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman;
+
+/**
+ * Autoload.
+ */
+class Autoloader
+{
+ /**
+ * Autoload root path.
+ *
+ * @var string
+ */
+ protected static $_autoloadRootPath = '';
+
+ /**
+ * Set autoload root path.
+ *
+ * @param string $root_path
+ * @return void
+ */
+ public static function setRootPath($root_path)
+ {
+ self::$_autoloadRootPath = $root_path;
+ }
+
+ /**
+ * Load files by namespace.
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public static function loadByNamespace($name)
+ {
+ $class_path = \str_replace('\\', \DIRECTORY_SEPARATOR, $name);
+ if (\strpos($name, 'Workerman\\') === 0) {
+ $class_file = __DIR__ . \substr($class_path, \strlen('Workerman')) . '.php';
+ } else {
+ if (self::$_autoloadRootPath) {
+ $class_file = self::$_autoloadRootPath . \DIRECTORY_SEPARATOR . $class_path . '.php';
+ }
+ if (empty($class_file) || !\is_file($class_file)) {
+ $class_file = __DIR__ . \DIRECTORY_SEPARATOR . '..' . \DIRECTORY_SEPARATOR . "$class_path.php";
+ }
+ }
+
+ if (\is_file($class_file)) {
+ require_once($class_file);
+ if (\class_exists($name, false)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+\spl_autoload_register('\Workerman\Autoloader::loadByNamespace');
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Connection/AsyncTcpConnection.php b/addons/weliam_smartcity/vendor/workerman/workerman/Connection/AsyncTcpConnection.php
new file mode 100644
index 0000000..6d0c3b5
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Connection/AsyncTcpConnection.php
@@ -0,0 +1,377 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Connection;
+
+use Workerman\Events\EventInterface;
+use Workerman\Lib\Timer;
+use Workerman\Worker;
+use \Exception;
+
+/**
+ * AsyncTcpConnection.
+ */
+class AsyncTcpConnection extends TcpConnection
+{
+ /**
+ * Emitted when socket connection is successfully established.
+ *
+ * @var callable|null
+ */
+ public $onConnect = null;
+
+ /**
+ * Transport layer protocol.
+ *
+ * @var string
+ */
+ public $transport = 'tcp';
+
+ /**
+ * Status.
+ *
+ * @var int
+ */
+ protected $_status = self::STATUS_INITIAL;
+
+ /**
+ * Remote host.
+ *
+ * @var string
+ */
+ protected $_remoteHost = '';
+
+ /**
+ * Remote port.
+ *
+ * @var int
+ */
+ protected $_remotePort = 80;
+
+ /**
+ * Connect start time.
+ *
+ * @var float
+ */
+ protected $_connectStartTime = 0;
+
+ /**
+ * Remote URI.
+ *
+ * @var string
+ */
+ protected $_remoteURI = '';
+
+ /**
+ * Context option.
+ *
+ * @var array
+ */
+ protected $_contextOption = null;
+
+ /**
+ * Reconnect timer.
+ *
+ * @var int
+ */
+ protected $_reconnectTimer = null;
+
+
+ /**
+ * PHP built-in protocols.
+ *
+ * @var array
+ */
+ protected static $_builtinTransports = array(
+ 'tcp' => 'tcp',
+ 'udp' => 'udp',
+ 'unix' => 'unix',
+ 'ssl' => 'ssl',
+ 'sslv2' => 'sslv2',
+ 'sslv3' => 'sslv3',
+ 'tls' => 'tls'
+ );
+
+ /**
+ * Construct.
+ *
+ * @param string $remote_address
+ * @param array $context_option
+ * @throws Exception
+ */
+ public function __construct($remote_address, array $context_option = array())
+ {
+ $address_info = \parse_url($remote_address);
+ if (!$address_info) {
+ list($scheme, $this->_remoteAddress) = \explode(':', $remote_address, 2);
+ if (!$this->_remoteAddress) {
+ Worker::safeEcho(new \Exception('bad remote_address'));
+ }
+ } else {
+ if (!isset($address_info['port'])) {
+ $address_info['port'] = 0;
+ }
+ if (!isset($address_info['path'])) {
+ $address_info['path'] = '/';
+ }
+ if (!isset($address_info['query'])) {
+ $address_info['query'] = '';
+ } else {
+ $address_info['query'] = '?' . $address_info['query'];
+ }
+ $this->_remoteAddress = "{$address_info['host']}:{$address_info['port']}";
+ $this->_remoteHost = $address_info['host'];
+ $this->_remotePort = $address_info['port'];
+ $this->_remoteURI = "{$address_info['path']}{$address_info['query']}";
+ $scheme = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp';
+ }
+
+ $this->id = $this->_id = self::$_idRecorder++;
+ if(\PHP_INT_MAX === self::$_idRecorder){
+ self::$_idRecorder = 0;
+ }
+ // Check application layer protocol class.
+ if (!isset(self::$_builtinTransports[$scheme])) {
+ $scheme = \ucfirst($scheme);
+ $this->protocol = '\\Protocols\\' . $scheme;
+ if (!\class_exists($this->protocol)) {
+ $this->protocol = "\\Workerman\\Protocols\\$scheme";
+ if (!\class_exists($this->protocol)) {
+ throw new Exception("class \\Protocols\\$scheme not exist");
+ }
+ }
+ } else {
+ $this->transport = self::$_builtinTransports[$scheme];
+ }
+
+ // For statistics.
+ ++self::$statistics['connection_count'];
+ $this->maxSendBufferSize = self::$defaultMaxSendBufferSize;
+ $this->maxPackageSize = self::$defaultMaxPackageSize;
+ $this->_contextOption = $context_option;
+ static::$connections[$this->_id] = $this;
+ }
+
+ /**
+ * Do connect.
+ *
+ * @return void
+ */
+ public function connect()
+ {
+ if ($this->_status !== self::STATUS_INITIAL && $this->_status !== self::STATUS_CLOSING &&
+ $this->_status !== self::STATUS_CLOSED) {
+ return;
+ }
+ $this->_status = self::STATUS_CONNECTING;
+ $this->_connectStartTime = \microtime(true);
+ if ($this->transport !== 'unix') {
+ if (!$this->_remotePort) {
+ $this->_remotePort = $this->transport === 'ssl' ? 443 : 80;
+ $this->_remoteAddress = $this->_remoteHost.':'.$this->_remotePort;
+ }
+ // Open socket connection asynchronously.
+ if ($this->_contextOption) {
+ $context = \stream_context_create($this->_contextOption);
+ $this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}",
+ $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context);
+ } else {
+ $this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}",
+ $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT);
+ }
+ } else {
+ $this->_socket = \stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0,
+ \STREAM_CLIENT_ASYNC_CONNECT);
+ }
+ // If failed attempt to emit onError callback.
+ if (!$this->_socket || !\is_resource($this->_socket)) {
+ $this->emitError(\WORKERMAN_CONNECT_FAIL, $errstr);
+ if ($this->_status === self::STATUS_CLOSING) {
+ $this->destroy();
+ }
+ if ($this->_status === self::STATUS_CLOSED) {
+ $this->onConnect = null;
+ }
+ return;
+ }
+ // Add socket to global event loop waiting connection is successfully established or faild.
+ Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'checkConnection'));
+ // For windows.
+ if(\DIRECTORY_SEPARATOR === '\\') {
+ Worker::$globalEvent->add($this->_socket, EventInterface::EV_EXCEPT, array($this, 'checkConnection'));
+ }
+ }
+
+ /**
+ * Reconnect.
+ *
+ * @param int $after
+ * @return void
+ */
+ public function reconnect($after = 0)
+ {
+ $this->_status = self::STATUS_INITIAL;
+ static::$connections[$this->_id] = $this;
+ if ($this->_reconnectTimer) {
+ Timer::del($this->_reconnectTimer);
+ }
+ if ($after > 0) {
+ $this->_reconnectTimer = Timer::add($after, array($this, 'connect'), null, false);
+ return;
+ }
+ $this->connect();
+ }
+
+ /**
+ * CancelReconnect.
+ */
+ public function cancelReconnect()
+ {
+ if ($this->_reconnectTimer) {
+ Timer::del($this->_reconnectTimer);
+ }
+ }
+
+ /**
+ * Get remote address.
+ *
+ * @return string
+ */
+ public function getRemoteHost()
+ {
+ return $this->_remoteHost;
+ }
+
+ /**
+ * Get remote URI.
+ *
+ * @return string
+ */
+ public function getRemoteURI()
+ {
+ return $this->_remoteURI;
+ }
+
+ /**
+ * Try to emit onError callback.
+ *
+ * @param int $code
+ * @param string $msg
+ * @return void
+ */
+ protected function emitError($code, $msg)
+ {
+ $this->_status = self::STATUS_CLOSING;
+ if ($this->onError) {
+ try {
+ \call_user_func($this->onError, $this, $code, $msg);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ }
+
+ /**
+ * Check connection is successfully established or faild.
+ *
+ * @param resource $socket
+ * @return void
+ */
+ public function checkConnection()
+ {
+ // Remove EV_EXPECT for windows.
+ if(\DIRECTORY_SEPARATOR === '\\') {
+ Worker::$globalEvent->del($this->_socket, EventInterface::EV_EXCEPT);
+ }
+
+ // Remove write listener.
+ Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE);
+
+ if ($this->_status !== self::STATUS_CONNECTING) {
+ return;
+ }
+
+ // Check socket state.
+ if ($address = \stream_socket_get_name($this->_socket, true)) {
+ // Nonblocking.
+ \stream_set_blocking($this->_socket, false);
+ // Compatible with hhvm
+ if (\function_exists('stream_set_read_buffer')) {
+ \stream_set_read_buffer($this->_socket, 0);
+ }
+ // Try to open keepalive for tcp and disable Nagle algorithm.
+ if (\function_exists('socket_import_stream') && $this->transport === 'tcp') {
+ $raw_socket = \socket_import_stream($this->_socket);
+ \socket_set_option($raw_socket, \SOL_SOCKET, \SO_KEEPALIVE, 1);
+ \socket_set_option($raw_socket, \SOL_TCP, \TCP_NODELAY, 1);
+ }
+
+ // SSL handshake.
+ if ($this->transport === 'ssl') {
+ $this->_sslHandshakeCompleted = $this->doSslHandshake($this->_socket);
+ if ($this->_sslHandshakeCompleted === false) {
+ return;
+ }
+ } else {
+ // There are some data waiting to send.
+ if ($this->_sendBuffer) {
+ Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
+ }
+ }
+
+ // Register a listener waiting read event.
+ Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
+
+ $this->_status = self::STATUS_ESTABLISHED;
+ $this->_remoteAddress = $address;
+
+ // Try to emit onConnect callback.
+ if ($this->onConnect) {
+ try {
+ \call_user_func($this->onConnect, $this);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ // Try to emit protocol::onConnect
+ if ($this->protocol && \method_exists($this->protocol, 'onConnect')) {
+ try {
+ \call_user_func(array($this->protocol, 'onConnect'), $this);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ } else {
+ // Connection failed.
+ $this->emitError(\WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(\microtime(true) - $this->_connectStartTime, 4) . ' seconds');
+ if ($this->_status === self::STATUS_CLOSING) {
+ $this->destroy();
+ }
+ if ($this->_status === self::STATUS_CLOSED) {
+ $this->onConnect = null;
+ }
+ }
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Connection/AsyncUdpConnection.php b/addons/weliam_smartcity/vendor/workerman/workerman/Connection/AsyncUdpConnection.php
new file mode 100644
index 0000000..7df93ad
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Connection/AsyncUdpConnection.php
@@ -0,0 +1,209 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Connection;
+
+use Workerman\Events\EventInterface;
+use Workerman\Worker;
+use \Exception;
+
+/**
+ * AsyncTcpConnection.
+ */
+class AsyncUdpConnection extends UdpConnection
+{
+ /**
+ * Emitted when socket connection is successfully established.
+ *
+ * @var callable
+ */
+ public $onConnect = null;
+
+ /**
+ * Emitted when socket connection closed.
+ *
+ * @var callable
+ */
+ public $onClose = null;
+
+ /**
+ * Connected or not.
+ *
+ * @var bool
+ */
+ protected $connected = false;
+
+ /**
+ * Context option.
+ *
+ * @var array
+ */
+ protected $_contextOption = null;
+
+ /**
+ * Construct.
+ *
+ * @param string $remote_address
+ * @throws Exception
+ */
+ public function __construct($remote_address, $context_option = null)
+ {
+ // Get the application layer communication protocol and listening address.
+ list($scheme, $address) = \explode(':', $remote_address, 2);
+ // Check application layer protocol class.
+ if ($scheme !== 'udp') {
+ $scheme = \ucfirst($scheme);
+ $this->protocol = '\\Protocols\\' . $scheme;
+ if (!\class_exists($this->protocol)) {
+ $this->protocol = "\\Workerman\\Protocols\\$scheme";
+ if (!\class_exists($this->protocol)) {
+ throw new Exception("class \\Protocols\\$scheme not exist");
+ }
+ }
+ }
+
+ $this->_remoteAddress = \substr($address, 2);
+ $this->_contextOption = $context_option;
+ }
+
+ /**
+ * For udp package.
+ *
+ * @param resource $socket
+ * @return bool
+ */
+ public function baseRead($socket)
+ {
+ $recv_buffer = \stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remote_address);
+ if (false === $recv_buffer || empty($remote_address)) {
+ return false;
+ }
+
+ if ($this->onMessage) {
+ if ($this->protocol) {
+ $parser = $this->protocol;
+ $recv_buffer = $parser::decode($recv_buffer, $this);
+ }
+ ++ConnectionInterface::$statistics['total_request'];
+ try {
+ \call_user_func($this->onMessage, $this, $recv_buffer);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Sends data on the connection.
+ *
+ * @param string $send_buffer
+ * @param bool $raw
+ * @return void|boolean
+ */
+ public function send($send_buffer, $raw = false)
+ {
+ if (false === $raw && $this->protocol) {
+ $parser = $this->protocol;
+ $send_buffer = $parser::encode($send_buffer, $this);
+ if ($send_buffer === '') {
+ return;
+ }
+ }
+ if ($this->connected === false) {
+ $this->connect();
+ }
+ return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0);
+ }
+
+
+ /**
+ * Close connection.
+ *
+ * @param mixed $data
+ * @param bool $raw
+ *
+ * @return bool
+ */
+ public function close($data = null, $raw = false)
+ {
+ if ($data !== null) {
+ $this->send($data, $raw);
+ }
+ Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ);
+ \fclose($this->_socket);
+ $this->connected = false;
+ // Try to emit onClose callback.
+ if ($this->onClose) {
+ try {
+ \call_user_func($this->onClose, $this);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ $this->onConnect = $this->onMessage = $this->onClose = null;
+ return true;
+ }
+
+ /**
+ * Connect.
+ *
+ * @return void
+ */
+ public function connect()
+ {
+ if ($this->connected === true) {
+ return;
+ }
+ if ($this->_contextOption) {
+ $context = \stream_context_create($this->_contextOption);
+ $this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg,
+ 30, \STREAM_CLIENT_CONNECT, $context);
+ } else {
+ $this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg);
+ }
+
+ if (!$this->_socket) {
+ Worker::safeEcho(new \Exception($errmsg));
+ return;
+ }
+
+ \stream_set_blocking($this->_socket, false);
+
+ if ($this->onMessage) {
+ Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
+ }
+ $this->connected = true;
+ // Try to emit onConnect callback.
+ if ($this->onConnect) {
+ try {
+ \call_user_func($this->onConnect, $this);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ }
+
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Connection/ConnectionInterface.php b/addons/weliam_smartcity/vendor/workerman/workerman/Connection/ConnectionInterface.php
new file mode 100644
index 0000000..05954e2
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Connection/ConnectionInterface.php
@@ -0,0 +1,125 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Connection;
+
+/**
+ * ConnectionInterface.
+ */
+abstract class ConnectionInterface
+{
+ /**
+ * Statistics for status command.
+ *
+ * @var array
+ */
+ public static $statistics = array(
+ 'connection_count' => 0,
+ 'total_request' => 0,
+ 'throw_exception' => 0,
+ 'send_fail' => 0,
+ );
+
+ /**
+ * Emitted when data is received.
+ *
+ * @var callable
+ */
+ public $onMessage = null;
+
+ /**
+ * Emitted when the other end of the socket sends a FIN packet.
+ *
+ * @var callable
+ */
+ public $onClose = null;
+
+ /**
+ * Emitted when an error occurs with connection.
+ *
+ * @var callable
+ */
+ public $onError = null;
+
+ /**
+ * Sends data on the connection.
+ *
+ * @param mixed $send_buffer
+ * @return void|boolean
+ */
+ abstract public function send($send_buffer);
+
+ /**
+ * Get remote IP.
+ *
+ * @return string
+ */
+ abstract public function getRemoteIp();
+
+ /**
+ * Get remote port.
+ *
+ * @return int
+ */
+ abstract public function getRemotePort();
+
+ /**
+ * Get remote address.
+ *
+ * @return string
+ */
+ abstract public function getRemoteAddress();
+
+ /**
+ * Get local IP.
+ *
+ * @return string
+ */
+ abstract public function getLocalIp();
+
+ /**
+ * Get local port.
+ *
+ * @return int
+ */
+ abstract public function getLocalPort();
+
+ /**
+ * Get local address.
+ *
+ * @return string
+ */
+ abstract public function getLocalAddress();
+
+ /**
+ * Is ipv4.
+ *
+ * @return bool
+ */
+ abstract public function isIPv4();
+
+ /**
+ * Is ipv6.
+ *
+ * @return bool
+ */
+ abstract public function isIPv6();
+
+ /**
+ * Close connection.
+ *
+ * @param $data
+ * @return void
+ */
+ abstract public function close($data = null);
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Connection/TcpConnection.php b/addons/weliam_smartcity/vendor/workerman/workerman/Connection/TcpConnection.php
new file mode 100644
index 0000000..28d8a02
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Connection/TcpConnection.php
@@ -0,0 +1,989 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Connection;
+
+use Workerman\Events\EventInterface;
+use Workerman\Worker;
+use \Exception;
+
+/**
+ * TcpConnection.
+ */
+class TcpConnection extends ConnectionInterface
+{
+ /**
+ * Read buffer size.
+ *
+ * @var int
+ */
+ const READ_BUFFER_SIZE = 65535;
+
+ /**
+ * Status initial.
+ *
+ * @var int
+ */
+ const STATUS_INITIAL = 0;
+
+ /**
+ * Status connecting.
+ *
+ * @var int
+ */
+ const STATUS_CONNECTING = 1;
+
+ /**
+ * Status connection established.
+ *
+ * @var int
+ */
+ const STATUS_ESTABLISHED = 2;
+
+ /**
+ * Status closing.
+ *
+ * @var int
+ */
+ const STATUS_CLOSING = 4;
+
+ /**
+ * Status closed.
+ *
+ * @var int
+ */
+ const STATUS_CLOSED = 8;
+
+ /**
+ * Emitted when data is received.
+ *
+ * @var callable
+ */
+ public $onMessage = null;
+
+ /**
+ * Emitted when the other end of the socket sends a FIN packet.
+ *
+ * @var callable
+ */
+ public $onClose = null;
+
+ /**
+ * Emitted when an error occurs with connection.
+ *
+ * @var callable
+ */
+ public $onError = null;
+
+ /**
+ * Emitted when the send buffer becomes full.
+ *
+ * @var callable
+ */
+ public $onBufferFull = null;
+
+ /**
+ * Emitted when the send buffer becomes empty.
+ *
+ * @var callable
+ */
+ public $onBufferDrain = null;
+
+ /**
+ * Application layer protocol.
+ * The format is like this Workerman\\Protocols\\Http.
+ *
+ * @var \Workerman\Protocols\ProtocolInterface
+ */
+ public $protocol = null;
+
+ /**
+ * Transport (tcp/udp/unix/ssl).
+ *
+ * @var string
+ */
+ public $transport = 'tcp';
+
+ /**
+ * Which worker belong to.
+ *
+ * @var Worker
+ */
+ public $worker = null;
+
+ /**
+ * Bytes read.
+ *
+ * @var int
+ */
+ public $bytesRead = 0;
+
+ /**
+ * Bytes written.
+ *
+ * @var int
+ */
+ public $bytesWritten = 0;
+
+ /**
+ * Connection->id.
+ *
+ * @var int
+ */
+ public $id = 0;
+
+ /**
+ * A copy of $worker->id which used to clean up the connection in worker->connections
+ *
+ * @var int
+ */
+ protected $_id = 0;
+
+ /**
+ * Sets the maximum send buffer size for the current connection.
+ * OnBufferFull callback will be emited When the send buffer is full.
+ *
+ * @var int
+ */
+ public $maxSendBufferSize = 1048576;
+
+ /**
+ * Default send buffer size.
+ *
+ * @var int
+ */
+ public static $defaultMaxSendBufferSize = 1048576;
+
+ /**
+ * Sets the maximum acceptable packet size for the current connection.
+ *
+ * @var int
+ */
+ public $maxPackageSize = 1048576;
+
+ /**
+ * Default maximum acceptable packet size.
+ *
+ * @var int
+ */
+ public static $defaultMaxPackageSize = 10485760;
+
+ /**
+ * Id recorder.
+ *
+ * @var int
+ */
+ protected static $_idRecorder = 1;
+
+ /**
+ * Socket
+ *
+ * @var resource
+ */
+ protected $_socket = null;
+
+ /**
+ * Send buffer.
+ *
+ * @var string
+ */
+ protected $_sendBuffer = '';
+
+ /**
+ * Receive buffer.
+ *
+ * @var string
+ */
+ protected $_recvBuffer = '';
+
+ /**
+ * Current package length.
+ *
+ * @var int
+ */
+ protected $_currentPackageLength = 0;
+
+ /**
+ * Connection status.
+ *
+ * @var int
+ */
+ protected $_status = self::STATUS_ESTABLISHED;
+
+ /**
+ * Remote address.
+ *
+ * @var string
+ */
+ protected $_remoteAddress = '';
+
+ /**
+ * Is paused.
+ *
+ * @var bool
+ */
+ protected $_isPaused = false;
+
+ /**
+ * SSL handshake completed or not.
+ *
+ * @var bool
+ */
+ protected $_sslHandshakeCompleted = false;
+
+ /**
+ * All connection instances.
+ *
+ * @var array
+ */
+ public static $connections = array();
+
+ /**
+ * Status to string.
+ *
+ * @var array
+ */
+ public static $_statusToString = array(
+ self::STATUS_INITIAL => 'INITIAL',
+ self::STATUS_CONNECTING => 'CONNECTING',
+ self::STATUS_ESTABLISHED => 'ESTABLISHED',
+ self::STATUS_CLOSING => 'CLOSING',
+ self::STATUS_CLOSED => 'CLOSED',
+ );
+
+ /**
+ * Construct.
+ *
+ * @param resource $socket
+ * @param string $remote_address
+ */
+ public function __construct($socket, $remote_address = '')
+ {
+ ++self::$statistics['connection_count'];
+ $this->id = $this->_id = self::$_idRecorder++;
+ if(self::$_idRecorder === \PHP_INT_MAX){
+ self::$_idRecorder = 0;
+ }
+ $this->_socket = $socket;
+ \stream_set_blocking($this->_socket, 0);
+ // Compatible with hhvm
+ if (\function_exists('stream_set_read_buffer')) {
+ \stream_set_read_buffer($this->_socket, 0);
+ }
+ Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
+ $this->maxSendBufferSize = self::$defaultMaxSendBufferSize;
+ $this->maxPackageSize = self::$defaultMaxPackageSize;
+ $this->_remoteAddress = $remote_address;
+ static::$connections[$this->id] = $this;
+ }
+
+ /**
+ * Get status.
+ *
+ * @param bool $raw_output
+ *
+ * @return int|string
+ */
+ public function getStatus($raw_output = true)
+ {
+ if ($raw_output) {
+ return $this->_status;
+ }
+ return self::$_statusToString[$this->_status];
+ }
+
+ /**
+ * Sends data on the connection.
+ *
+ * @param mixed $send_buffer
+ * @param bool $raw
+ * @return bool|null
+ */
+ public function send($send_buffer, $raw = false)
+ {
+ if ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) {
+ return false;
+ }
+
+ // Try to call protocol::encode($send_buffer) before sending.
+ if (false === $raw && $this->protocol !== null) {
+ $parser = $this->protocol;
+ $send_buffer = $parser::encode($send_buffer, $this);
+ if ($send_buffer === '') {
+ return;
+ }
+ }
+
+ if ($this->_status !== self::STATUS_ESTABLISHED ||
+ ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true)
+ ) {
+ if ($this->_sendBuffer && $this->bufferIsFull()) {
+ ++self::$statistics['send_fail'];
+ return false;
+ }
+ $this->_sendBuffer .= $send_buffer;
+ $this->checkBufferWillFull();
+ return;
+ }
+
+ // Attempt to send data directly.
+ if ($this->_sendBuffer === '') {
+ if ($this->transport === 'ssl') {
+ Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
+ $this->_sendBuffer = $send_buffer;
+ $this->checkBufferWillFull();
+ return;
+ }
+ $len = 0;
+ try {
+ $len = @\fwrite($this->_socket, $send_buffer);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ } catch (\Error $e) {
+ Worker::log($e);
+ }
+ // send successful.
+ if ($len === \strlen($send_buffer)) {
+ $this->bytesWritten += $len;
+ return true;
+ }
+ // Send only part of the data.
+ if ($len > 0) {
+ $this->_sendBuffer = \substr($send_buffer, $len);
+ $this->bytesWritten += $len;
+ } else {
+ // Connection closed?
+ if (!\is_resource($this->_socket) || \feof($this->_socket)) {
+ ++self::$statistics['send_fail'];
+ if ($this->onError) {
+ try {
+ \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'client closed');
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ $this->destroy();
+ return false;
+ }
+ $this->_sendBuffer = $send_buffer;
+ }
+ Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
+ // Check if the send buffer will be full.
+ $this->checkBufferWillFull();
+ return;
+ }
+
+ if ($this->bufferIsFull()) {
+ ++self::$statistics['send_fail'];
+ return false;
+ }
+
+ $this->_sendBuffer .= $send_buffer;
+ // Check if the send buffer is full.
+ $this->checkBufferWillFull();
+ }
+
+ /**
+ * Get remote IP.
+ *
+ * @return string
+ */
+ public function getRemoteIp()
+ {
+ $pos = \strrpos($this->_remoteAddress, ':');
+ if ($pos) {
+ return (string) \substr($this->_remoteAddress, 0, $pos);
+ }
+ return '';
+ }
+
+ /**
+ * Get remote port.
+ *
+ * @return int
+ */
+ public function getRemotePort()
+ {
+ if ($this->_remoteAddress) {
+ return (int) \substr(\strrchr($this->_remoteAddress, ':'), 1);
+ }
+ return 0;
+ }
+
+ /**
+ * Get remote address.
+ *
+ * @return string
+ */
+ public function getRemoteAddress()
+ {
+ return $this->_remoteAddress;
+ }
+
+ /**
+ * Get local IP.
+ *
+ * @return string
+ */
+ public function getLocalIp()
+ {
+ $address = $this->getLocalAddress();
+ $pos = \strrpos($address, ':');
+ if (!$pos) {
+ return '';
+ }
+ return \substr($address, 0, $pos);
+ }
+
+ /**
+ * Get local port.
+ *
+ * @return int
+ */
+ public function getLocalPort()
+ {
+ $address = $this->getLocalAddress();
+ $pos = \strrpos($address, ':');
+ if (!$pos) {
+ return 0;
+ }
+ return (int)\substr(\strrchr($address, ':'), 1);
+ }
+
+ /**
+ * Get local address.
+ *
+ * @return string
+ */
+ public function getLocalAddress()
+ {
+ return (string)@\stream_socket_get_name($this->_socket, false);
+ }
+
+ /**
+ * Get send buffer queue size.
+ *
+ * @return integer
+ */
+ public function getSendBufferQueueSize()
+ {
+ return \strlen($this->_sendBuffer);
+ }
+
+ /**
+ * Get recv buffer queue size.
+ *
+ * @return integer
+ */
+ public function getRecvBufferQueueSize()
+ {
+ return \strlen($this->_recvBuffer);
+ }
+
+ /**
+ * Is ipv4.
+ *
+ * return bool.
+ */
+ public function isIpV4()
+ {
+ if ($this->transport === 'unix') {
+ return false;
+ }
+ return \strpos($this->getRemoteIp(), ':') === false;
+ }
+
+ /**
+ * Is ipv6.
+ *
+ * return bool.
+ */
+ public function isIpV6()
+ {
+ if ($this->transport === 'unix') {
+ return false;
+ }
+ return \strpos($this->getRemoteIp(), ':') !== false;
+ }
+
+ /**
+ * Pauses the reading of data. That is onMessage will not be emitted. Useful to throttle back an upload.
+ *
+ * @return void
+ */
+ public function pauseRecv()
+ {
+ Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ);
+ $this->_isPaused = true;
+ }
+
+ /**
+ * Resumes reading after a call to pauseRecv.
+ *
+ * @return void
+ */
+ public function resumeRecv()
+ {
+ if ($this->_isPaused === true) {
+ Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
+ $this->_isPaused = false;
+ $this->baseRead($this->_socket, false);
+ }
+ }
+
+
+
+ /**
+ * Base read handler.
+ *
+ * @param resource $socket
+ * @param bool $check_eof
+ * @return void
+ */
+ public function baseRead($socket, $check_eof = true)
+ {
+ // SSL handshake.
+ if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) {
+ if ($this->doSslHandshake($socket)) {
+ $this->_sslHandshakeCompleted = true;
+ if ($this->_sendBuffer) {
+ Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
+ }
+ } else {
+ return;
+ }
+ }
+
+ $buffer = '';
+ try {
+ $buffer = @\fread($socket, self::READ_BUFFER_SIZE);
+ } catch (\Exception $e) {} catch (\Error $e) {}
+
+ // Check connection closed.
+ if ($buffer === '' || $buffer === false) {
+ if ($check_eof && (\feof($socket) || !\is_resource($socket) || $buffer === false)) {
+ $this->destroy();
+ return;
+ }
+ } else {
+ $this->bytesRead += \strlen($buffer);
+ $this->_recvBuffer .= $buffer;
+ }
+
+ // If the application layer protocol has been set up.
+ if ($this->protocol !== null) {
+ $parser = $this->protocol;
+ while ($this->_recvBuffer !== '' && !$this->_isPaused) {
+ // The current packet length is known.
+ if ($this->_currentPackageLength) {
+ // Data is not enough for a package.
+ if ($this->_currentPackageLength > \strlen($this->_recvBuffer)) {
+ break;
+ }
+ } else {
+ // Get current package length.
+ try {
+ $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this);
+ } catch (\Exception $e) {} catch (\Error $e) {}
+ // The packet length is unknown.
+ if ($this->_currentPackageLength === 0) {
+ break;
+ } elseif ($this->_currentPackageLength > 0 && $this->_currentPackageLength <= $this->maxPackageSize) {
+ // Data is not enough for a package.
+ if ($this->_currentPackageLength > \strlen($this->_recvBuffer)) {
+ break;
+ }
+ } // Wrong package.
+ else {
+ Worker::safeEcho('Error package. package_length=' . \var_export($this->_currentPackageLength, true));
+ $this->destroy();
+ return;
+ }
+ }
+
+ // The data is enough for a packet.
+ ++self::$statistics['total_request'];
+ // The current packet length is equal to the length of the buffer.
+ if (\strlen($this->_recvBuffer) === $this->_currentPackageLength) {
+ $one_request_buffer = $this->_recvBuffer;
+ $this->_recvBuffer = '';
+ } else {
+ // Get a full package from the buffer.
+ $one_request_buffer = \substr($this->_recvBuffer, 0, $this->_currentPackageLength);
+ // Remove the current package from the receive buffer.
+ $this->_recvBuffer = \substr($this->_recvBuffer, $this->_currentPackageLength);
+ }
+ // Reset the current packet length to 0.
+ $this->_currentPackageLength = 0;
+ if (!$this->onMessage) {
+ continue;
+ }
+ try {
+ // Decode request buffer before Emitting onMessage callback.
+ \call_user_func($this->onMessage, $this, $parser::decode($one_request_buffer, $this));
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ return;
+ }
+
+ if ($this->_recvBuffer === '' || $this->_isPaused) {
+ return;
+ }
+
+ // Applications protocol is not set.
+ ++self::$statistics['total_request'];
+ if (!$this->onMessage) {
+ $this->_recvBuffer = '';
+ return;
+ }
+ try {
+ \call_user_func($this->onMessage, $this, $this->_recvBuffer);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ // Clean receive buffer.
+ $this->_recvBuffer = '';
+ }
+
+ /**
+ * Base write handler.
+ *
+ * @return void|bool
+ */
+ public function baseWrite()
+ {
+ \set_error_handler(function(){});
+ if ($this->transport === 'ssl') {
+ $len = @\fwrite($this->_socket, $this->_sendBuffer, 8192);
+ } else {
+ $len = @\fwrite($this->_socket, $this->_sendBuffer);
+ }
+ \restore_error_handler();
+ if ($len === \strlen($this->_sendBuffer)) {
+ $this->bytesWritten += $len;
+ Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE);
+ $this->_sendBuffer = '';
+ // Try to emit onBufferDrain callback when the send buffer becomes empty.
+ if ($this->onBufferDrain) {
+ try {
+ \call_user_func($this->onBufferDrain, $this);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ if ($this->_status === self::STATUS_CLOSING) {
+ $this->destroy();
+ }
+ return true;
+ }
+ if ($len > 0) {
+ $this->bytesWritten += $len;
+ $this->_sendBuffer = \substr($this->_sendBuffer, $len);
+ } else {
+ ++self::$statistics['send_fail'];
+ $this->destroy();
+ }
+ }
+
+ /**
+ * SSL handshake.
+ *
+ * @param $socket
+ * @return bool
+ */
+ public function doSslHandshake($socket){
+ if (\feof($socket)) {
+ $this->destroy();
+ return false;
+ }
+ $async = $this instanceof AsyncTcpConnection;
+
+ /**
+ * We disabled ssl3 because https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack.
+ * You can enable ssl3 by the codes below.
+ */
+ /*if($async){
+ $type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT | STREAM_CRYPTO_METHOD_SSLv3_CLIENT;
+ }else{
+ $type = STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER | STREAM_CRYPTO_METHOD_SSLv3_SERVER;
+ }*/
+
+ if($async){
+ $type = \STREAM_CRYPTO_METHOD_SSLv2_CLIENT | \STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
+ }else{
+ $type = \STREAM_CRYPTO_METHOD_SSLv2_SERVER | \STREAM_CRYPTO_METHOD_SSLv23_SERVER;
+ }
+
+ // Hidden error.
+ \set_error_handler(function($errno, $errstr, $file){
+ if (!Worker::$daemonize) {
+ Worker::safeEcho("SSL handshake error: $errstr \n");
+ }
+ });
+ $ret = \stream_socket_enable_crypto($socket, true, $type);
+ \restore_error_handler();
+ // Negotiation has failed.
+ if (false === $ret) {
+ $this->destroy();
+ return false;
+ } elseif (0 === $ret) {
+ // There isn't enough data and should try again.
+ return 0;
+ }
+ if (isset($this->onSslHandshake)) {
+ try {
+ \call_user_func($this->onSslHandshake, $this);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * This method pulls all the data out of a readable stream, and writes it to the supplied destination.
+ *
+ * @param self $dest
+ * @return void
+ */
+ public function pipe(self $dest)
+ {
+ $source = $this;
+ $this->onMessage = function ($source, $data) use ($dest) {
+ $dest->send($data);
+ };
+ $this->onClose = function ($source) use ($dest) {
+ $dest->close();
+ };
+ $dest->onBufferFull = function ($dest) use ($source) {
+ $source->pauseRecv();
+ };
+ $dest->onBufferDrain = function ($dest) use ($source) {
+ $source->resumeRecv();
+ };
+ }
+
+ /**
+ * Remove $length of data from receive buffer.
+ *
+ * @param int $length
+ * @return void
+ */
+ public function consumeRecvBuffer($length)
+ {
+ $this->_recvBuffer = \substr($this->_recvBuffer, $length);
+ }
+
+ /**
+ * Close connection.
+ *
+ * @param mixed $data
+ * @param bool $raw
+ * @return void
+ */
+ public function close($data = null, $raw = false)
+ {
+ if($this->_status === self::STATUS_CONNECTING){
+ $this->destroy();
+ return;
+ }
+
+ if ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) {
+ return;
+ }
+
+ if ($data !== null) {
+ $this->send($data, $raw);
+ }
+
+ $this->_status = self::STATUS_CLOSING;
+
+ if ($this->_sendBuffer === '') {
+ $this->destroy();
+ } else {
+ $this->pauseRecv();
+ }
+ }
+
+ /**
+ * Get the real socket.
+ *
+ * @return resource
+ */
+ public function getSocket()
+ {
+ return $this->_socket;
+ }
+
+ /**
+ * Check whether the send buffer will be full.
+ *
+ * @return void
+ */
+ protected function checkBufferWillFull()
+ {
+ if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) {
+ if ($this->onBufferFull) {
+ try {
+ \call_user_func($this->onBufferFull, $this);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ }
+ }
+
+ /**
+ * Whether send buffer is full.
+ *
+ * @return bool
+ */
+ protected function bufferIsFull()
+ {
+ // Buffer has been marked as full but still has data to send then the packet is discarded.
+ if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) {
+ if ($this->onError) {
+ try {
+ \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package');
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Whether send buffer is Empty.
+ *
+ * @return bool
+ */
+ public function bufferIsEmpty()
+ {
+ return empty($this->_sendBuffer);
+ }
+
+ /**
+ * Destroy connection.
+ *
+ * @return void
+ */
+ public function destroy()
+ {
+ // Avoid repeated calls.
+ if ($this->_status === self::STATUS_CLOSED) {
+ return;
+ }
+ // Remove event listener.
+ Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ);
+ Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE);
+
+ // Close socket.
+ try {
+ @\fclose($this->_socket);
+ } catch (\Exception $e) {} catch (\Error $e) {}
+
+ $this->_status = self::STATUS_CLOSED;
+ // Try to emit onClose callback.
+ if ($this->onClose) {
+ try {
+ \call_user_func($this->onClose, $this);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ // Try to emit protocol::onClose
+ if ($this->protocol && \method_exists($this->protocol, 'onClose')) {
+ try {
+ \call_user_func(array($this->protocol, 'onClose'), $this);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ $this->_sendBuffer = $this->_recvBuffer = '';
+ $this->_currentPackageLength = 0;
+ $this->_isPaused = $this->_sslHandshakeCompleted = false;
+ if ($this->_status === self::STATUS_CLOSED) {
+ // Cleaning up the callback to avoid memory leaks.
+ $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null;
+ // Remove from worker->connections.
+ if ($this->worker) {
+ unset($this->worker->connections[$this->_id]);
+ }
+ unset(static::$connections[$this->_id]);
+ }
+ }
+
+ /**
+ * Destruct.
+ *
+ * @return void
+ */
+ public function __destruct()
+ {
+ static $mod;
+ self::$statistics['connection_count']--;
+ if (Worker::getGracefulStop()) {
+ if (!isset($mod)) {
+ $mod = \ceil((self::$statistics['connection_count'] + 1) / 3);
+ }
+
+ if (0 === self::$statistics['connection_count'] % $mod) {
+ Worker::log('worker[' . \posix_getpid() . '] remains ' . self::$statistics['connection_count'] . ' connection(s)');
+ }
+
+ if(0 === self::$statistics['connection_count']) {
+ Worker::stopAll();
+ }
+ }
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Connection/UdpConnection.php b/addons/weliam_smartcity/vendor/workerman/workerman/Connection/UdpConnection.php
new file mode 100644
index 0000000..48c0092
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Connection/UdpConnection.php
@@ -0,0 +1,191 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Connection;
+
+/**
+ * UdpConnection.
+ */
+class UdpConnection extends ConnectionInterface
+{
+ /**
+ * Application layer protocol.
+ * The format is like this Workerman\\Protocols\\Http.
+ *
+ * @var \Workerman\Protocols\ProtocolInterface
+ */
+ public $protocol = null;
+
+ /**
+ * Udp socket.
+ *
+ * @var resource
+ */
+ protected $_socket = null;
+
+ /**
+ * Remote address.
+ *
+ * @var string
+ */
+ protected $_remoteAddress = '';
+
+ /**
+ * Construct.
+ *
+ * @param resource $socket
+ * @param string $remote_address
+ */
+ public function __construct($socket, $remote_address)
+ {
+ $this->_socket = $socket;
+ $this->_remoteAddress = $remote_address;
+ }
+
+ /**
+ * Sends data on the connection.
+ *
+ * @param string $send_buffer
+ * @param bool $raw
+ * @return void|boolean
+ */
+ public function send($send_buffer, $raw = false)
+ {
+ if (false === $raw && $this->protocol) {
+ $parser = $this->protocol;
+ $send_buffer = $parser::encode($send_buffer, $this);
+ if ($send_buffer === '') {
+ return;
+ }
+ }
+ return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0, $this->_remoteAddress);
+ }
+
+ /**
+ * Get remote IP.
+ *
+ * @return string
+ */
+ public function getRemoteIp()
+ {
+ $pos = \strrpos($this->_remoteAddress, ':');
+ if ($pos) {
+ return \trim(\substr($this->_remoteAddress, 0, $pos), '[]');
+ }
+ return '';
+ }
+
+ /**
+ * Get remote port.
+ *
+ * @return int
+ */
+ public function getRemotePort()
+ {
+ if ($this->_remoteAddress) {
+ return (int)\substr(\strrchr($this->_remoteAddress, ':'), 1);
+ }
+ return 0;
+ }
+
+ /**
+ * Get remote address.
+ *
+ * @return string
+ */
+ public function getRemoteAddress()
+ {
+ return $this->_remoteAddress;
+ }
+
+ /**
+ * Get local IP.
+ *
+ * @return string
+ */
+ public function getLocalIp()
+ {
+ $address = $this->getLocalAddress();
+ $pos = \strrpos($address, ':');
+ if (!$pos) {
+ return '';
+ }
+ return \substr($address, 0, $pos);
+ }
+
+ /**
+ * Get local port.
+ *
+ * @return int
+ */
+ public function getLocalPort()
+ {
+ $address = $this->getLocalAddress();
+ $pos = \strrpos($address, ':');
+ if (!$pos) {
+ return 0;
+ }
+ return (int)\substr(\strrchr($address, ':'), 1);
+ }
+
+ /**
+ * Get local address.
+ *
+ * @return string
+ */
+ public function getLocalAddress()
+ {
+ return (string)@\stream_socket_get_name($this->_socket, false);
+ }
+
+ /**
+ * Is ipv4.
+ *
+ * @return bool.
+ */
+ public function isIpV4()
+ {
+ if ($this->transport === 'unix') {
+ return false;
+ }
+ return \strpos($this->getRemoteIp(), ':') === false;
+ }
+
+ /**
+ * Is ipv6.
+ *
+ * @return bool.
+ */
+ public function isIpV6()
+ {
+ if ($this->transport === 'unix') {
+ return false;
+ }
+ return \strpos($this->getRemoteIp(), ':') !== false;
+ }
+
+ /**
+ * Close connection.
+ *
+ * @param mixed $data
+ * @param bool $raw
+ * @return bool
+ */
+ public function close($data = null, $raw = false)
+ {
+ if ($data !== null) {
+ $this->send($data, $raw);
+ }
+ return true;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Events/Ev.php b/addons/weliam_smartcity/vendor/workerman/workerman/Events/Ev.php
new file mode 100644
index 0000000..8dba860
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Events/Ev.php
@@ -0,0 +1,195 @@
+
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events;
+
+use Workerman\Worker;
+use \EvWatcher;
+
+/**
+ * ev eventloop
+ */
+class Ev implements EventInterface
+{
+ /**
+ * All listeners for read/write event.
+ *
+ * @var array
+ */
+ protected $_allEvents = array();
+
+ /**
+ * Event listeners of signal.
+ *
+ * @var array
+ */
+ protected $_eventSignal = array();
+
+ /**
+ * All timer event listeners.
+ * [func, args, event, flag, time_interval]
+ *
+ * @var array
+ */
+ protected $_eventTimer = array();
+
+ /**
+ * Timer id.
+ *
+ * @var int
+ */
+ protected static $_timerId = 1;
+
+ /**
+ * Add a timer.
+ * {@inheritdoc}
+ */
+ public function add($fd, $flag, $func, $args = null)
+ {
+ $callback = function ($event, $socket) use ($fd, $func) {
+ try {
+ \call_user_func($func, $fd);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ };
+ switch ($flag) {
+ case self::EV_SIGNAL:
+ $event = new \EvSignal($fd, $callback);
+ $this->_eventSignal[$fd] = $event;
+ return true;
+ case self::EV_TIMER:
+ case self::EV_TIMER_ONCE:
+ $repeat = $flag === self::EV_TIMER_ONCE ? 0 : $fd;
+ $param = array($func, (array)$args, $flag, $fd, self::$_timerId);
+ $event = new \EvTimer($fd, $repeat, array($this, 'timerCallback'), $param);
+ $this->_eventTimer[self::$_timerId] = $event;
+ return self::$_timerId++;
+ default :
+ $fd_key = (int)$fd;
+ $real_flag = $flag === self::EV_READ ? \Ev::READ : \Ev::WRITE;
+ $event = new \EvIo($fd, $real_flag, $callback);
+ $this->_allEvents[$fd_key][$flag] = $event;
+ return true;
+ }
+
+ }
+
+ /**
+ * Remove a timer.
+ * {@inheritdoc}
+ */
+ public function del($fd, $flag)
+ {
+ switch ($flag) {
+ case self::EV_READ:
+ case self::EV_WRITE:
+ $fd_key = (int)$fd;
+ if (isset($this->_allEvents[$fd_key][$flag])) {
+ $this->_allEvents[$fd_key][$flag]->stop();
+ unset($this->_allEvents[$fd_key][$flag]);
+ }
+ if (empty($this->_allEvents[$fd_key])) {
+ unset($this->_allEvents[$fd_key]);
+ }
+ break;
+ case self::EV_SIGNAL:
+ $fd_key = (int)$fd;
+ if (isset($this->_eventSignal[$fd_key])) {
+ $this->_eventSignal[$fd_key]->stop();
+ unset($this->_eventSignal[$fd_key]);
+ }
+ break;
+ case self::EV_TIMER:
+ case self::EV_TIMER_ONCE:
+ if (isset($this->_eventTimer[$fd])) {
+ $this->_eventTimer[$fd]->stop();
+ unset($this->_eventTimer[$fd]);
+ }
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Timer callback.
+ *
+ * @param EvWatcher $event
+ */
+ public function timerCallback(EvWatcher $event)
+ {
+ $param = $event->data;
+ $timer_id = $param[4];
+ if ($param[2] === self::EV_TIMER_ONCE) {
+ $this->_eventTimer[$timer_id]->stop();
+ unset($this->_eventTimer[$timer_id]);
+ }
+ try {
+ \call_user_func_array($param[0], $param[1]);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+
+ /**
+ * Remove all timers.
+ *
+ * @return void
+ */
+ public function clearAllTimer()
+ {
+ foreach ($this->_eventTimer as $event) {
+ $event->stop();
+ }
+ $this->_eventTimer = array();
+ }
+
+ /**
+ * Main loop.
+ *
+ * @see EventInterface::loop()
+ */
+ public function loop()
+ {
+ \Ev::run();
+ }
+
+ /**
+ * Destroy loop.
+ *
+ * @return void
+ */
+ public function destroy()
+ {
+ foreach ($this->_allEvents as $event) {
+ $event->stop();
+ }
+ }
+
+ /**
+ * Get timer count.
+ *
+ * @return integer
+ */
+ public function getTimerCount()
+ {
+ return \count($this->_eventTimer);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Events/Event.php b/addons/weliam_smartcity/vendor/workerman/workerman/Events/Event.php
new file mode 100644
index 0000000..3e305a1
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Events/Event.php
@@ -0,0 +1,217 @@
+
+ * @copyright 有个鬼<42765633@qq.com>
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events;
+
+use Workerman\Worker;
+
+/**
+ * libevent eventloop
+ */
+class Event implements EventInterface
+{
+ /**
+ * Event base.
+ * @var object
+ */
+ protected $_eventBase = null;
+
+ /**
+ * All listeners for read/write event.
+ * @var array
+ */
+ protected $_allEvents = array();
+
+ /**
+ * Event listeners of signal.
+ * @var array
+ */
+ protected $_eventSignal = array();
+
+ /**
+ * All timer event listeners.
+ * [func, args, event, flag, time_interval]
+ * @var array
+ */
+ protected $_eventTimer = array();
+
+ /**
+ * Timer id.
+ * @var int
+ */
+ protected static $_timerId = 1;
+
+ /**
+ * construct
+ * @return void
+ */
+ public function __construct()
+ {
+ if (\class_exists('\\\\EventBase', false)) {
+ $class_name = '\\\\EventBase';
+ } else {
+ $class_name = '\EventBase';
+ }
+ $this->_eventBase = new $class_name();
+ }
+
+ /**
+ * @see EventInterface::add()
+ */
+ public function add($fd, $flag, $func, $args=array())
+ {
+ if (\class_exists('\\\\Event', false)) {
+ $class_name = '\\\\Event';
+ } else {
+ $class_name = '\Event';
+ }
+ switch ($flag) {
+ case self::EV_SIGNAL:
+
+ $fd_key = (int)$fd;
+ $event = $class_name::signal($this->_eventBase, $fd, $func);
+ if (!$event||!$event->add()) {
+ return false;
+ }
+ $this->_eventSignal[$fd_key] = $event;
+ return true;
+
+ case self::EV_TIMER:
+ case self::EV_TIMER_ONCE:
+
+ $param = array($func, (array)$args, $flag, $fd, self::$_timerId);
+ $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT|$class_name::PERSIST, array($this, "timerCallback"), $param);
+ if (!$event||!$event->addTimer($fd)) {
+ return false;
+ }
+ $this->_eventTimer[self::$_timerId] = $event;
+ return self::$_timerId++;
+
+ default :
+ $fd_key = (int)$fd;
+ $real_flag = $flag === self::EV_READ ? $class_name::READ | $class_name::PERSIST : $class_name::WRITE | $class_name::PERSIST;
+ $event = new $class_name($this->_eventBase, $fd, $real_flag, $func, $fd);
+ if (!$event||!$event->add()) {
+ return false;
+ }
+ $this->_allEvents[$fd_key][$flag] = $event;
+ return true;
+ }
+ }
+
+ /**
+ * @see Events\EventInterface::del()
+ */
+ public function del($fd, $flag)
+ {
+ switch ($flag) {
+
+ case self::EV_READ:
+ case self::EV_WRITE:
+
+ $fd_key = (int)$fd;
+ if (isset($this->_allEvents[$fd_key][$flag])) {
+ $this->_allEvents[$fd_key][$flag]->del();
+ unset($this->_allEvents[$fd_key][$flag]);
+ }
+ if (empty($this->_allEvents[$fd_key])) {
+ unset($this->_allEvents[$fd_key]);
+ }
+ break;
+
+ case self::EV_SIGNAL:
+ $fd_key = (int)$fd;
+ if (isset($this->_eventSignal[$fd_key])) {
+ $this->_eventSignal[$fd_key]->del();
+ unset($this->_eventSignal[$fd_key]);
+ }
+ break;
+
+ case self::EV_TIMER:
+ case self::EV_TIMER_ONCE:
+ if (isset($this->_eventTimer[$fd])) {
+ $this->_eventTimer[$fd]->del();
+ unset($this->_eventTimer[$fd]);
+ }
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Timer callback.
+ * @param null $fd
+ * @param int $what
+ * @param int $timer_id
+ */
+ public function timerCallback($fd, $what, $param)
+ {
+ $timer_id = $param[4];
+
+ if ($param[2] === self::EV_TIMER_ONCE) {
+ $this->_eventTimer[$timer_id]->del();
+ unset($this->_eventTimer[$timer_id]);
+ }
+
+ try {
+ \call_user_func_array($param[0], $param[1]);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+
+ /**
+ * @see Events\EventInterface::clearAllTimer()
+ * @return void
+ */
+ public function clearAllTimer()
+ {
+ foreach ($this->_eventTimer as $event) {
+ $event->del();
+ }
+ $this->_eventTimer = array();
+ }
+
+
+ /**
+ * @see EventInterface::loop()
+ */
+ public function loop()
+ {
+ $this->_eventBase->loop();
+ }
+
+ /**
+ * Destroy loop.
+ *
+ * @return void
+ */
+ public function destroy()
+ {
+ $this->_eventBase->exit();
+ }
+
+ /**
+ * Get timer count.
+ *
+ * @return integer
+ */
+ public function getTimerCount()
+ {
+ return \count($this->_eventTimer);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Events/EventInterface.php b/addons/weliam_smartcity/vendor/workerman/workerman/Events/EventInterface.php
new file mode 100644
index 0000000..88f38f2
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Events/EventInterface.php
@@ -0,0 +1,107 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events;
+
+interface EventInterface
+{
+ /**
+ * Read event.
+ *
+ * @var int
+ */
+ const EV_READ = 1;
+
+ /**
+ * Write event.
+ *
+ * @var int
+ */
+ const EV_WRITE = 2;
+
+ /**
+ * Except event
+ *
+ * @var int
+ */
+ const EV_EXCEPT = 3;
+
+ /**
+ * Signal event.
+ *
+ * @var int
+ */
+ const EV_SIGNAL = 4;
+
+ /**
+ * Timer event.
+ *
+ * @var int
+ */
+ const EV_TIMER = 8;
+
+ /**
+ * Timer once event.
+ *
+ * @var int
+ */
+ const EV_TIMER_ONCE = 16;
+
+ /**
+ * Add event listener to event loop.
+ *
+ * @param mixed $fd
+ * @param int $flag
+ * @param callable $func
+ * @param mixed $args
+ * @return bool
+ */
+ public function add($fd, $flag, $func, $args = null);
+
+ /**
+ * Remove event listener from event loop.
+ *
+ * @param mixed $fd
+ * @param int $flag
+ * @return bool
+ */
+ public function del($fd, $flag);
+
+ /**
+ * Remove all timers.
+ *
+ * @return void
+ */
+ public function clearAllTimer();
+
+ /**
+ * Main loop.
+ *
+ * @return void
+ */
+ public function loop();
+
+ /**
+ * Destroy loop.
+ *
+ * @return mixed
+ */
+ public function destroy();
+
+ /**
+ * Get Timer count.
+ *
+ * @return mixed
+ */
+ public function getTimerCount();
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Events/Libevent.php b/addons/weliam_smartcity/vendor/workerman/workerman/Events/Libevent.php
new file mode 100644
index 0000000..ac3427c
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Events/Libevent.php
@@ -0,0 +1,227 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events;
+
+use Workerman\Worker;
+
+/**
+ * libevent eventloop
+ */
+class Libevent implements EventInterface
+{
+ /**
+ * Event base.
+ *
+ * @var resource
+ */
+ protected $_eventBase = null;
+
+ /**
+ * All listeners for read/write event.
+ *
+ * @var array
+ */
+ protected $_allEvents = array();
+
+ /**
+ * Event listeners of signal.
+ *
+ * @var array
+ */
+ protected $_eventSignal = array();
+
+ /**
+ * All timer event listeners.
+ * [func, args, event, flag, time_interval]
+ *
+ * @var array
+ */
+ protected $_eventTimer = array();
+
+ /**
+ * construct
+ */
+ public function __construct()
+ {
+ $this->_eventBase = \event_base_new();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add($fd, $flag, $func, $args = array())
+ {
+ switch ($flag) {
+ case self::EV_SIGNAL:
+ $fd_key = (int)$fd;
+ $real_flag = \EV_SIGNAL | \EV_PERSIST;
+ $this->_eventSignal[$fd_key] = \event_new();
+ if (!\event_set($this->_eventSignal[$fd_key], $fd, $real_flag, $func, null)) {
+ return false;
+ }
+ if (!\event_base_set($this->_eventSignal[$fd_key], $this->_eventBase)) {
+ return false;
+ }
+ if (!\event_add($this->_eventSignal[$fd_key])) {
+ return false;
+ }
+ return true;
+ case self::EV_TIMER:
+ case self::EV_TIMER_ONCE:
+ $event = \event_new();
+ $timer_id = (int)$event;
+ if (!\event_set($event, 0, \EV_TIMEOUT, array($this, 'timerCallback'), $timer_id)) {
+ return false;
+ }
+
+ if (!\event_base_set($event, $this->_eventBase)) {
+ return false;
+ }
+
+ $time_interval = $fd * 1000000;
+ if (!\event_add($event, $time_interval)) {
+ return false;
+ }
+ $this->_eventTimer[$timer_id] = array($func, (array)$args, $event, $flag, $time_interval);
+ return $timer_id;
+
+ default :
+ $fd_key = (int)$fd;
+ $real_flag = $flag === self::EV_READ ? \EV_READ | \EV_PERSIST : \EV_WRITE | \EV_PERSIST;
+
+ $event = \event_new();
+
+ if (!\event_set($event, $fd, $real_flag, $func, null)) {
+ return false;
+ }
+
+ if (!\event_base_set($event, $this->_eventBase)) {
+ return false;
+ }
+
+ if (!\event_add($event)) {
+ return false;
+ }
+
+ $this->_allEvents[$fd_key][$flag] = $event;
+
+ return true;
+ }
+
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function del($fd, $flag)
+ {
+ switch ($flag) {
+ case self::EV_READ:
+ case self::EV_WRITE:
+ $fd_key = (int)$fd;
+ if (isset($this->_allEvents[$fd_key][$flag])) {
+ \event_del($this->_allEvents[$fd_key][$flag]);
+ unset($this->_allEvents[$fd_key][$flag]);
+ }
+ if (empty($this->_allEvents[$fd_key])) {
+ unset($this->_allEvents[$fd_key]);
+ }
+ break;
+ case self::EV_SIGNAL:
+ $fd_key = (int)$fd;
+ if (isset($this->_eventSignal[$fd_key])) {
+ \event_del($this->_eventSignal[$fd_key]);
+ unset($this->_eventSignal[$fd_key]);
+ }
+ break;
+ case self::EV_TIMER:
+ case self::EV_TIMER_ONCE:
+ // 这里 fd 为timerid
+ if (isset($this->_eventTimer[$fd])) {
+ \event_del($this->_eventTimer[$fd][2]);
+ unset($this->_eventTimer[$fd]);
+ }
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Timer callback.
+ *
+ * @param mixed $_null1
+ * @param int $_null2
+ * @param mixed $timer_id
+ */
+ protected function timerCallback($_null1, $_null2, $timer_id)
+ {
+ if ($this->_eventTimer[$timer_id][3] === self::EV_TIMER) {
+ \event_add($this->_eventTimer[$timer_id][2], $this->_eventTimer[$timer_id][4]);
+ }
+ try {
+ \call_user_func_array($this->_eventTimer[$timer_id][0], $this->_eventTimer[$timer_id][1]);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ if (isset($this->_eventTimer[$timer_id]) && $this->_eventTimer[$timer_id][3] === self::EV_TIMER_ONCE) {
+ $this->del($timer_id, self::EV_TIMER_ONCE);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clearAllTimer()
+ {
+ foreach ($this->_eventTimer as $task_data) {
+ \event_del($task_data[2]);
+ }
+ $this->_eventTimer = array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function loop()
+ {
+ \event_base_loop($this->_eventBase);
+ }
+
+ /**
+ * Destroy loop.
+ *
+ * @return void
+ */
+ public function destroy()
+ {
+ foreach ($this->_eventSignal as $event) {
+ \event_del($event);
+ }
+ }
+
+ /**
+ * Get timer count.
+ *
+ * @return integer
+ */
+ public function getTimerCount()
+ {
+ return \count($this->_eventTimer);
+ }
+}
+
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Events/React/Base.php b/addons/weliam_smartcity/vendor/workerman/workerman/Events/React/Base.php
new file mode 100644
index 0000000..a0a33ae
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Events/React/Base.php
@@ -0,0 +1,264 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events\React;
+
+use Workerman\Events\EventInterface;
+use React\EventLoop\TimerInterface;
+use React\EventLoop\LoopInterface;
+
+/**
+ * Class StreamSelectLoop
+ * @package Workerman\Events\React
+ */
+class Base implements LoopInterface
+{
+ /**
+ * @var array
+ */
+ protected $_timerIdMap = array();
+
+ /**
+ * @var int
+ */
+ protected $_timerIdIndex = 0;
+
+ /**
+ * @var array
+ */
+ protected $_signalHandlerMap = array();
+
+ /**
+ * @var LoopInterface
+ */
+ protected $_eventLoop = null;
+
+ /**
+ * Base constructor.
+ */
+ public function __construct()
+ {
+ $this->_eventLoop = new \React\EventLoop\StreamSelectLoop();
+ }
+
+ /**
+ * Add event listener to event loop.
+ *
+ * @param $fd
+ * @param $flag
+ * @param $func
+ * @param array $args
+ * @return bool
+ */
+ public function add($fd, $flag, $func, array $args = array())
+ {
+ $args = (array)$args;
+ switch ($flag) {
+ case EventInterface::EV_READ:
+ return $this->addReadStream($fd, $func);
+ case EventInterface::EV_WRITE:
+ return $this->addWriteStream($fd, $func);
+ case EventInterface::EV_SIGNAL:
+ if (isset($this->_signalHandlerMap[$fd])) {
+ $this->removeSignal($fd, $this->_signalHandlerMap[$fd]);
+ }
+ $this->_signalHandlerMap[$fd] = $func;
+ return $this->addSignal($fd, $func);
+ case EventInterface::EV_TIMER:
+ $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) {
+ \call_user_func_array($func, $args);
+ });
+ $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj;
+ return $this->_timerIdIndex;
+ case EventInterface::EV_TIMER_ONCE:
+ $index = ++$this->_timerIdIndex;
+ $timer_obj = $this->addTimer($fd, function() use ($func, $args, $index) {
+ $this->del($index,EventInterface::EV_TIMER_ONCE);
+ \call_user_func_array($func, $args);
+ });
+ $this->_timerIdMap[$index] = $timer_obj;
+ return $this->_timerIdIndex;
+ }
+ return false;
+ }
+
+ /**
+ * Remove event listener from event loop.
+ *
+ * @param mixed $fd
+ * @param int $flag
+ * @return bool
+ */
+ public function del($fd, $flag)
+ {
+ switch ($flag) {
+ case EventInterface::EV_READ:
+ return $this->removeReadStream($fd);
+ case EventInterface::EV_WRITE:
+ return $this->removeWriteStream($fd);
+ case EventInterface::EV_SIGNAL:
+ if (!isset($this->_eventLoop[$fd])) {
+ return false;
+ }
+ $func = $this->_eventLoop[$fd];
+ unset($this->_eventLoop[$fd]);
+ return $this->removeSignal($fd, $func);
+
+ case EventInterface::EV_TIMER:
+ case EventInterface::EV_TIMER_ONCE:
+ if (isset($this->_timerIdMap[$fd])){
+ $timer_obj = $this->_timerIdMap[$fd];
+ unset($this->_timerIdMap[$fd]);
+ $this->cancelTimer($timer_obj);
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * Main loop.
+ *
+ * @return void
+ */
+ public function loop()
+ {
+ $this->run();
+ }
+
+
+ /**
+ * Destroy loop.
+ *
+ * @return void
+ */
+ public function destroy()
+ {
+
+ }
+
+ /**
+ * Get timer count.
+ *
+ * @return integer
+ */
+ public function getTimerCount()
+ {
+ return \count($this->_timerIdMap);
+ }
+
+ /**
+ * @param resource $stream
+ * @param callable $listener
+ */
+ public function addReadStream($stream, $listener)
+ {
+ return $this->_eventLoop->addReadStream($stream, $listener);
+ }
+
+ /**
+ * @param resource $stream
+ * @param callable $listener
+ */
+ public function addWriteStream($stream, $listener)
+ {
+ return $this->_eventLoop->addWriteStream($stream, $listener);
+ }
+
+ /**
+ * @param resource $stream
+ */
+ public function removeReadStream($stream)
+ {
+ return $this->_eventLoop->removeReadStream($stream);
+ }
+
+ /**
+ * @param resource $stream
+ */
+ public function removeWriteStream($stream)
+ {
+ return $this->_eventLoop->removeWriteStream($stream);
+ }
+
+ /**
+ * @param float|int $interval
+ * @param callable $callback
+ * @return \React\EventLoop\Timer\Timer|TimerInterface
+ */
+ public function addTimer($interval, $callback)
+ {
+ return $this->_eventLoop->addTimer($interval, $callback);
+ }
+
+ /**
+ * @param float|int $interval
+ * @param callable $callback
+ * @return \React\EventLoop\Timer\Timer|TimerInterface
+ */
+ public function addPeriodicTimer($interval, $callback)
+ {
+ return $this->_eventLoop->addPeriodicTimer($interval, $callback);
+ }
+
+ /**
+ * @param TimerInterface $timer
+ */
+ public function cancelTimer(TimerInterface $timer)
+ {
+ return $this->_eventLoop->cancelTimer($timer);
+ }
+
+ /**
+ * @param callable $listener
+ */
+ public function futureTick($listener)
+ {
+ return $this->_eventLoop->futureTick($listener);
+ }
+
+ /**
+ * @param int $signal
+ * @param callable $listener
+ */
+ public function addSignal($signal, $listener)
+ {
+ return $this->_eventLoop->addSignal($signal, $listener);
+ }
+
+ /**
+ * @param int $signal
+ * @param callable $listener
+ */
+ public function removeSignal($signal, $listener)
+ {
+ return $this->_eventLoop->removeSignal($signal, $listener);
+ }
+
+ /**
+ * Run.
+ */
+ public function run()
+ {
+ return $this->_eventLoop->run();
+ }
+
+ /**
+ * Stop.
+ */
+ public function stop()
+ {
+ return $this->_eventLoop->stop();
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Events/React/ExtEventLoop.php b/addons/weliam_smartcity/vendor/workerman/workerman/Events/React/ExtEventLoop.php
new file mode 100644
index 0000000..3dab25b
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Events/React/ExtEventLoop.php
@@ -0,0 +1,27 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events\React;
+
+/**
+ * Class ExtEventLoop
+ * @package Workerman\Events\React
+ */
+class ExtEventLoop extends Base
+{
+
+ public function __construct()
+ {
+ $this->_eventLoop = new \React\EventLoop\ExtEventLoop();
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Events/React/ExtLibEventLoop.php b/addons/weliam_smartcity/vendor/workerman/workerman/Events/React/ExtLibEventLoop.php
new file mode 100644
index 0000000..eb02b35
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Events/React/ExtLibEventLoop.php
@@ -0,0 +1,27 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events\React;
+use Workerman\Events\EventInterface;
+
+/**
+ * Class ExtLibEventLoop
+ * @package Workerman\Events\React
+ */
+class ExtLibEventLoop extends Base
+{
+ public function __construct()
+ {
+ $this->_eventLoop = new \React\EventLoop\ExtLibeventLoop();
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Events/React/StreamSelectLoop.php b/addons/weliam_smartcity/vendor/workerman/workerman/Events/React/StreamSelectLoop.php
new file mode 100644
index 0000000..7f5f94b
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Events/React/StreamSelectLoop.php
@@ -0,0 +1,26 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events\React;
+
+/**
+ * Class StreamSelectLoop
+ * @package Workerman\Events\React
+ */
+class StreamSelectLoop extends Base
+{
+ public function __construct()
+ {
+ $this->_eventLoop = new \React\EventLoop\StreamSelectLoop();
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Events/Select.php b/addons/weliam_smartcity/vendor/workerman/workerman/Events/Select.php
new file mode 100644
index 0000000..8b7e1af
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Events/Select.php
@@ -0,0 +1,339 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events;
+
+/**
+ * select eventloop
+ */
+class Select implements EventInterface
+{
+ /**
+ * All listeners for read/write event.
+ *
+ * @var array
+ */
+ public $_allEvents = array();
+
+ /**
+ * Event listeners of signal.
+ *
+ * @var array
+ */
+ public $_signalEvents = array();
+
+ /**
+ * Fds waiting for read event.
+ *
+ * @var array
+ */
+ protected $_readFds = array();
+
+ /**
+ * Fds waiting for write event.
+ *
+ * @var array
+ */
+ protected $_writeFds = array();
+
+ /**
+ * Fds waiting for except event.
+ *
+ * @var array
+ */
+ protected $_exceptFds = array();
+
+ /**
+ * Timer scheduler.
+ * {['data':timer_id, 'priority':run_timestamp], ..}
+ *
+ * @var \SplPriorityQueue
+ */
+ protected $_scheduler = null;
+
+ /**
+ * All timer event listeners.
+ * [[func, args, flag, timer_interval], ..]
+ *
+ * @var array
+ */
+ protected $_eventTimer = array();
+
+ /**
+ * Timer id.
+ *
+ * @var int
+ */
+ protected $_timerId = 1;
+
+ /**
+ * Select timeout.
+ *
+ * @var int
+ */
+ protected $_selectTimeout = 100000000;
+
+ /**
+ * Paired socket channels
+ *
+ * @var array
+ */
+ protected $channel = array();
+
+ /**
+ * Construct.
+ */
+ public function __construct()
+ {
+ // Init SplPriorityQueue.
+ $this->_scheduler = new \SplPriorityQueue();
+ $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add($fd, $flag, $func, $args = array())
+ {
+ switch ($flag) {
+ case self::EV_READ:
+ case self::EV_WRITE:
+ $count = $flag === self::EV_READ ? \count($this->_readFds) : \count($this->_writeFds);
+ if ($count >= 1024) {
+ echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n";
+ } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) {
+ echo "Warning: system call select exceeded the maximum number of connections 256.\n";
+ }
+ $fd_key = (int)$fd;
+ $this->_allEvents[$fd_key][$flag] = array($func, $fd);
+ if ($flag === self::EV_READ) {
+ $this->_readFds[$fd_key] = $fd;
+ } else {
+ $this->_writeFds[$fd_key] = $fd;
+ }
+ break;
+ case self::EV_EXCEPT:
+ $fd_key = (int)$fd;
+ $this->_allEvents[$fd_key][$flag] = array($func, $fd);
+ $this->_exceptFds[$fd_key] = $fd;
+ break;
+ case self::EV_SIGNAL:
+ // Windows not support signal.
+ if(\DIRECTORY_SEPARATOR !== '/') {
+ return false;
+ }
+ $fd_key = (int)$fd;
+ $this->_signalEvents[$fd_key][$flag] = array($func, $fd);
+ \pcntl_signal($fd, array($this, 'signalHandler'));
+ break;
+ case self::EV_TIMER:
+ case self::EV_TIMER_ONCE:
+ $timer_id = $this->_timerId++;
+ $run_time = \microtime(true) + $fd;
+ $this->_scheduler->insert($timer_id, -$run_time);
+ $this->_eventTimer[$timer_id] = array($func, (array)$args, $flag, $fd);
+ $select_timeout = ($run_time - \microtime(true)) * 1000000;
+ if( $this->_selectTimeout > $select_timeout ){
+ $this->_selectTimeout = $select_timeout;
+ }
+ return $timer_id;
+ }
+
+ return true;
+ }
+
+ /**
+ * Signal handler.
+ *
+ * @param int $signal
+ */
+ public function signalHandler($signal)
+ {
+ \call_user_func_array($this->_signalEvents[$signal][self::EV_SIGNAL][0], array($signal));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function del($fd, $flag)
+ {
+ $fd_key = (int)$fd;
+ switch ($flag) {
+ case self::EV_READ:
+ unset($this->_allEvents[$fd_key][$flag], $this->_readFds[$fd_key]);
+ if (empty($this->_allEvents[$fd_key])) {
+ unset($this->_allEvents[$fd_key]);
+ }
+ return true;
+ case self::EV_WRITE:
+ unset($this->_allEvents[$fd_key][$flag], $this->_writeFds[$fd_key]);
+ if (empty($this->_allEvents[$fd_key])) {
+ unset($this->_allEvents[$fd_key]);
+ }
+ return true;
+ case self::EV_EXCEPT:
+ unset($this->_allEvents[$fd_key][$flag], $this->_exceptFds[$fd_key]);
+ if(empty($this->_allEvents[$fd_key]))
+ {
+ unset($this->_allEvents[$fd_key]);
+ }
+ return true;
+ case self::EV_SIGNAL:
+ if(\DIRECTORY_SEPARATOR !== '/') {
+ return false;
+ }
+ unset($this->_signalEvents[$fd_key]);
+ \pcntl_signal($fd, SIG_IGN);
+ break;
+ case self::EV_TIMER:
+ case self::EV_TIMER_ONCE;
+ unset($this->_eventTimer[$fd_key]);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Tick for timer.
+ *
+ * @return void
+ */
+ protected function tick()
+ {
+ while (!$this->_scheduler->isEmpty()) {
+ $scheduler_data = $this->_scheduler->top();
+ $timer_id = $scheduler_data['data'];
+ $next_run_time = -$scheduler_data['priority'];
+ $time_now = \microtime(true);
+ $this->_selectTimeout = ($next_run_time - $time_now) * 1000000;
+ if ($this->_selectTimeout <= 0) {
+ $this->_scheduler->extract();
+
+ if (!isset($this->_eventTimer[$timer_id])) {
+ continue;
+ }
+
+ // [func, args, flag, timer_interval]
+ $task_data = $this->_eventTimer[$timer_id];
+ if ($task_data[2] === self::EV_TIMER) {
+ $next_run_time = $time_now + $task_data[3];
+ $this->_scheduler->insert($timer_id, -$next_run_time);
+ }
+ \call_user_func_array($task_data[0], $task_data[1]);
+ if (isset($this->_eventTimer[$timer_id]) && $task_data[2] === self::EV_TIMER_ONCE) {
+ $this->del($timer_id, self::EV_TIMER_ONCE);
+ }
+ continue;
+ }
+ return;
+ }
+ $this->_selectTimeout = 100000000;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clearAllTimer()
+ {
+ $this->_scheduler = new \SplPriorityQueue();
+ $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
+ $this->_eventTimer = array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function loop()
+ {
+ while (1) {
+ if(\DIRECTORY_SEPARATOR === '/') {
+ // Calls signal handlers for pending signals
+ \pcntl_signal_dispatch();
+ }
+
+ $read = $this->_readFds;
+ $write = $this->_writeFds;
+ $except = $this->_exceptFds;
+
+ if ($read || $write || $except) {
+ // Waiting read/write/signal/timeout events.
+ try {
+ $ret = @stream_select($read, $write, $except, 0, $this->_selectTimeout);
+ } catch (\Exception $e) {} catch (\Error $e) {}
+
+ } else {
+ usleep($this->_selectTimeout);
+ $ret = false;
+ }
+
+
+ if (!$this->_scheduler->isEmpty()) {
+ $this->tick();
+ }
+
+ if (!$ret) {
+ continue;
+ }
+
+ if ($read) {
+ foreach ($read as $fd) {
+ $fd_key = (int)$fd;
+ if (isset($this->_allEvents[$fd_key][self::EV_READ])) {
+ \call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0],
+ array($this->_allEvents[$fd_key][self::EV_READ][1]));
+ }
+ }
+ }
+
+ if ($write) {
+ foreach ($write as $fd) {
+ $fd_key = (int)$fd;
+ if (isset($this->_allEvents[$fd_key][self::EV_WRITE])) {
+ \call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0],
+ array($this->_allEvents[$fd_key][self::EV_WRITE][1]));
+ }
+ }
+ }
+
+ if($except) {
+ foreach($except as $fd) {
+ $fd_key = (int) $fd;
+ if(isset($this->_allEvents[$fd_key][self::EV_EXCEPT])) {
+ \call_user_func_array($this->_allEvents[$fd_key][self::EV_EXCEPT][0],
+ array($this->_allEvents[$fd_key][self::EV_EXCEPT][1]));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Destroy loop.
+ *
+ * @return void
+ */
+ public function destroy()
+ {
+
+ }
+
+ /**
+ * Get timer count.
+ *
+ * @return integer
+ */
+ public function getTimerCount()
+ {
+ return \count($this->_eventTimer);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Events/Swoole.php b/addons/weliam_smartcity/vendor/workerman/workerman/Events/Swoole.php
new file mode 100644
index 0000000..ea828eb
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Events/Swoole.php
@@ -0,0 +1,222 @@
+
+ * @link http://www.workerman.net/
+ * @link https://github.com/ares333/Workerman
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events;
+
+use Swoole\Event;
+use Swoole\Timer;
+
+class Swoole implements EventInterface
+{
+
+ protected $_timer = array();
+
+ protected $_timerOnceMap = array();
+
+ protected $mapId = 0;
+
+ protected $_fd = array();
+
+ // milisecond
+ public static $signalDispatchInterval = 500;
+
+ protected $_hasSignal = false;
+
+ /**
+ *
+ * {@inheritdoc}
+ *
+ * @see \Workerman\Events\EventInterface::add()
+ */
+ public function add($fd, $flag, $func, $args = null)
+ {
+ if (! isset($args)) {
+ $args = array();
+ }
+ switch ($flag) {
+ case self::EV_SIGNAL:
+ $res = \pcntl_signal($fd, $func, false);
+ if (! $this->_hasSignal && $res) {
+ Timer::tick(static::$signalDispatchInterval,
+ function () {
+ \pcntl_signal_dispatch();
+ });
+ $this->_hasSignal = true;
+ }
+ return $res;
+ case self::EV_TIMER:
+ case self::EV_TIMER_ONCE:
+ $method = self::EV_TIMER === $flag ? 'tick' : 'after';
+ if ($this->mapId > \PHP_INT_MAX) {
+ $this->mapId = 0;
+ }
+ $mapId = $this->mapId++;
+ $timer_id = Timer::$method($fd * 1000,
+ function ($timer_id = null) use ($func, $args, $mapId) {
+ \call_user_func_array($func, $args);
+ // EV_TIMER_ONCE
+ if (! isset($timer_id)) {
+ // may be deleted in $func
+ if (\array_key_exists($mapId, $this->_timerOnceMap)) {
+ $timer_id = $this->_timerOnceMap[$mapId];
+ unset($this->_timer[$timer_id],
+ $this->_timerOnceMap[$mapId]);
+ }
+ }
+ });
+ if ($flag === self::EV_TIMER_ONCE) {
+ $this->_timerOnceMap[$mapId] = $timer_id;
+ $this->_timer[$timer_id] = $mapId;
+ } else {
+ $this->_timer[$timer_id] = null;
+ }
+ return $timer_id;
+ case self::EV_READ:
+ case self::EV_WRITE:
+ $fd_key = (int) $fd;
+ if (! isset($this->_fd[$fd_key])) {
+ if ($flag === self::EV_READ) {
+ $res = Event::add($fd, $func, null, SWOOLE_EVENT_READ);
+ $fd_type = SWOOLE_EVENT_READ;
+ } else {
+ $res = Event::add($fd, null, $func, SWOOLE_EVENT_WRITE);
+ $fd_type = SWOOLE_EVENT_WRITE;
+ }
+ if ($res) {
+ $this->_fd[$fd_key] = $fd_type;
+ }
+ } else {
+ $fd_val = $this->_fd[$fd_key];
+ $res = true;
+ if ($flag === self::EV_READ) {
+ if (($fd_val & SWOOLE_EVENT_READ) !== SWOOLE_EVENT_READ) {
+ $res = Event::set($fd, $func, null,
+ SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE);
+ $this->_fd[$fd_key] |= SWOOLE_EVENT_READ;
+ }
+ } else {
+ if (($fd_val & SWOOLE_EVENT_WRITE) !== SWOOLE_EVENT_WRITE) {
+ $res = Event::set($fd, null, $func,
+ SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE);
+ $this->_fd[$fd_key] |= SWOOLE_EVENT_WRITE;
+ }
+ }
+ }
+ return $res;
+ }
+ }
+
+ /**
+ *
+ * {@inheritdoc}
+ *
+ * @see \Workerman\Events\EventInterface::del()
+ */
+ public function del($fd, $flag)
+ {
+ switch ($flag) {
+ case self::EV_SIGNAL:
+ return \pcntl_signal($fd, SIG_IGN, false);
+ case self::EV_TIMER:
+ case self::EV_TIMER_ONCE:
+ // already remove in EV_TIMER_ONCE callback.
+ if (! \array_key_exists($fd, $this->_timer)) {
+ return true;
+ }
+ $res = Timer::clear($fd);
+ if ($res) {
+ $mapId = $this->_timer[$fd];
+ if (isset($mapId)) {
+ unset($this->_timerOnceMap[$mapId]);
+ }
+ unset($this->_timer[$fd]);
+ }
+ return $res;
+ case self::EV_READ:
+ case self::EV_WRITE:
+ $fd_key = (int) $fd;
+ if (isset($this->_fd[$fd_key])) {
+ $fd_val = $this->_fd[$fd_key];
+ if ($flag === self::EV_READ) {
+ $flag_remove = ~ SWOOLE_EVENT_READ;
+ } else {
+ $flag_remove = ~ SWOOLE_EVENT_WRITE;
+ }
+ $fd_val &= $flag_remove;
+ if (0 === $fd_val) {
+ $res = Event::del($fd);
+ if ($res) {
+ unset($this->_fd[$fd_key]);
+ }
+ } else {
+ $res = Event::set($fd, null, null, $fd_val);
+ if ($res) {
+ $this->_fd[$fd_key] = $fd_val;
+ }
+ }
+ } else {
+ $res = true;
+ }
+ return $res;
+ }
+ }
+
+ /**
+ *
+ * {@inheritdoc}
+ *
+ * @see \Workerman\Events\EventInterface::clearAllTimer()
+ */
+ public function clearAllTimer()
+ {
+ foreach (array_keys($this->_timer) as $v) {
+ Timer::clear($v);
+ }
+ $this->_timer = array();
+ $this->_timerOnceMap = array();
+ }
+
+ /**
+ *
+ * {@inheritdoc}
+ *
+ * @see \Workerman\Events\EventInterface::loop()
+ */
+ public function loop()
+ {
+ Event::wait();
+ }
+
+ /**
+ *
+ * {@inheritdoc}
+ *
+ * @see \Workerman\Events\EventInterface::destroy()
+ */
+ public function destroy()
+ {
+ Event::exit();
+ posix_kill(posix_getpid(), SIGINT);
+ }
+
+ /**
+ *
+ * {@inheritdoc}
+ *
+ * @see \Workerman\Events\EventInterface::getTimerCount()
+ */
+ public function getTimerCount()
+ {
+ return \count($this->_timer);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Lib/Constants.php b/addons/weliam_smartcity/vendor/workerman/workerman/Lib/Constants.php
new file mode 100644
index 0000000..f82a781
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Lib/Constants.php
@@ -0,0 +1,48 @@
+
+ * @copyright walkor
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ *
+ * @link http://www.workerman.net/
+ */
+
+// Display errors.
+ini_set('display_errors', 'on');
+// Reporting all.
+error_reporting(E_ALL);
+// JIT is not stable, temporarily disabled.
+ini_set('pcre.jit', 0);
+
+// For onError callback.
+const WORKERMAN_CONNECT_FAIL = 1;
+// For onError callback.
+const WORKERMAN_SEND_FAIL = 2;
+
+// Define OS Type
+const OS_TYPE_LINUX = 'linux';
+const OS_TYPE_WINDOWS = 'windows';
+
+// Compatible with php7
+if (!class_exists('Error')) {
+ class Error extends Exception
+ {
+ }
+}
+
+if (!interface_exists('SessionHandlerInterface')) {
+ interface SessionHandlerInterface {
+ public function close();
+ public function destroy($session_id);
+ public function gc($maxlifetime);
+ public function open($save_path ,$session_name);
+ public function read($session_id);
+ public function write($session_id , $session_data);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Lib/Timer.php b/addons/weliam_smartcity/vendor/workerman/workerman/Lib/Timer.php
new file mode 100644
index 0000000..b110051
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Lib/Timer.php
@@ -0,0 +1,22 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Lib;
+
+/**
+ * Do not use Workerman\Lib\Timer.
+ * Please use Workerman\Timer.
+ * This class is only used for compatibility with workerman 3.*
+ * @package Workerman\Lib
+ */
+class Timer extends \Workerman\Timer {}
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/MIT-LICENSE.txt b/addons/weliam_smartcity/vendor/workerman/workerman/MIT-LICENSE.txt
new file mode 100644
index 0000000..fd6b1c8
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/MIT-LICENSE.txt
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2009-2015 walkor and contributors (see https://github.com/walkor/workerman/contributors)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Frame.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Frame.php
new file mode 100644
index 0000000..26b04de
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Frame.php
@@ -0,0 +1,61 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols;
+
+use Workerman\Connection\TcpConnection;
+
+/**
+ * Frame Protocol.
+ */
+class Frame
+{
+ /**
+ * Check the integrity of the package.
+ *
+ * @param string $buffer
+ * @param TcpConnection $connection
+ * @return int
+ */
+ public static function input($buffer, TcpConnection $connection)
+ {
+ if (\strlen($buffer) < 4) {
+ return 0;
+ }
+ $unpack_data = \unpack('Ntotal_length', $buffer);
+ return $unpack_data['total_length'];
+ }
+
+ /**
+ * Decode.
+ *
+ * @param string $buffer
+ * @return string
+ */
+ public static function decode($buffer)
+ {
+ return \substr($buffer, 4);
+ }
+
+ /**
+ * Encode.
+ *
+ * @param string $buffer
+ * @return string
+ */
+ public static function encode($buffer)
+ {
+ $total_length = 4 + \strlen($buffer);
+ return \pack('N', $total_length) . $buffer;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http.php
new file mode 100644
index 0000000..441e5e7
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http.php
@@ -0,0 +1,326 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols;
+
+use Workerman\Connection\TcpConnection;
+use Workerman\Protocols\Http\Request;
+use Workerman\Protocols\Http\Response;
+use Workerman\Protocols\Websocket;
+use Workerman\Worker;
+
+/**
+ * Class Http.
+ * @package Workerman\Protocols
+ */
+class Http
+{
+ /**
+ * Request class name.
+ *
+ * @var string
+ */
+ protected static $_requestClass = 'Workerman\Protocols\Http\Request';
+
+ /**
+ * Session name.
+ *
+ * @var string
+ */
+ protected static $_sessionName = 'PHPSID';
+
+ /**
+ * Upload tmp dir.
+ *
+ * @var string
+ */
+ protected static $_uploadTmpDir = '';
+
+ /**
+ * Open cache.
+ *
+ * @var bool.
+ */
+ protected static $_enableCache = true;
+
+ /**
+ * Get or set session name.
+ *
+ * @param null $name
+ * @return string
+ */
+ public static function sessionName($name = null)
+ {
+ if ($name !== null && $name !== '') {
+ static::$_sessionName = (string)$name;
+ }
+ return static::$_sessionName;
+ }
+
+ /**
+ * Get or set the request class name.
+ *
+ * @param null $class_name
+ * @return string
+ */
+ public static function requestClass($class_name = null)
+ {
+ if ($class_name) {
+ static::$_requestClass = $class_name;
+ }
+ return static::$_requestClass;
+ }
+
+ /**
+ * Enable or disable Cache.
+ *
+ * @param $value
+ */
+ public static function enableCache($value)
+ {
+ static::$_enableCache = (bool)$value;
+ }
+
+ /**
+ * Check the integrity of the package.
+ *
+ * @param string $recv_buffer
+ * @param TcpConnection $connection
+ * @return int
+ */
+ public static function input($recv_buffer, TcpConnection $connection)
+ {
+ static $input = array();
+ if (!isset($recv_buffer[512]) && isset($input[$recv_buffer])) {
+ return $input[$recv_buffer];
+ }
+ $crlf_pos = \strpos($recv_buffer, "\r\n\r\n");
+ if (false === $crlf_pos) {
+ // Judge whether the package length exceeds the limit.
+ if ($recv_len = \strlen($recv_buffer) >= 16384) {
+ $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n");
+ return 0;
+ }
+ return 0;
+ }
+
+ $head_len = $crlf_pos + 4;
+ $method = \strstr($recv_buffer, ' ', true);
+
+ if ($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD' || $method === 'DELETE') {
+ if (!isset($recv_buffer[512])) {
+ $input[$recv_buffer] = $head_len;
+ if (\count($input) > 512) {
+ unset($input[key($input)]);
+ }
+ }
+ return $head_len;
+ } else if ($method !== 'POST' && $method !== 'PUT') {
+ $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true);
+ return 0;
+ }
+
+ $header = \substr($recv_buffer, 0, $crlf_pos);
+ $length = false;
+ if ($pos = \strpos($header, "\r\nContent-Length: ")) {
+ $length = $head_len + (int)\substr($header, $pos + 18, 10);
+ } else if (\preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) {
+ $length = $head_len + $match[1];
+ }
+
+ if ($length !== false) {
+ if (!isset($recv_buffer[512])) {
+ $input[$recv_buffer] = $length;
+ if (\count($input) > 512) {
+ unset($input[key($input)]);
+ }
+ }
+ return $length;
+ }
+
+ $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true);
+ return 0;
+ }
+
+ /**
+ * Http decode.
+ *
+ * @param string $recv_buffer
+ * @param TcpConnection $connection
+ * @return \Workerman\Protocols\Http\Request
+ */
+ public static function decode($recv_buffer, TcpConnection $connection)
+ {
+ static $requests = array();
+ $cacheable = static::$_enableCache && !isset($recv_buffer[512]);
+ if (true === $cacheable && isset($requests[$recv_buffer])) {
+ $request = $requests[$recv_buffer];
+ $request->connection = $connection;
+ $connection->__request = $request;
+ $request->properties = array();
+ return $request;
+ }
+ $request = new static::$_requestClass($recv_buffer);
+ $request->connection = $connection;
+ $connection->__request = $request;
+ if (true === $cacheable) {
+ $requests[$recv_buffer] = $request;
+ if (\count($requests) > 512) {
+ unset($requests[key($requests)]);
+ }
+ }
+ return $request;
+ }
+
+ /**
+ * Http encode.
+ *
+ * @param string|Response $response
+ * @param TcpConnection $connection
+ * @return string
+ */
+ public static function encode($response, TcpConnection $connection)
+ {
+ if (isset($connection->__request)) {
+ $connection->__request->session = null;
+ $connection->__request->connection = null;
+ $connection->__request = null;
+ }
+ if (!\is_object($response)) {
+ $ext_header = '';
+ if (isset($connection->__header)) {
+ foreach ($connection->__header as $name => $value) {
+ if (\is_array($value)) {
+ foreach ($value as $item) {
+ $ext_header = "$name: $item\r\n";
+ }
+ } else {
+ $ext_header = "$name: $value\r\n";
+ }
+ }
+ unset($connection->__header);
+ }
+ $body_len = \strlen($response);
+ return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$ext_header}Connection: keep-alive\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\n\r\n$response";
+ }
+
+ if (isset($connection->__header)) {
+ $response->withHeaders($connection->__header);
+ unset($connection->__header);
+ }
+
+ if (isset($response->file)) {
+ $file = $response->file['file'];
+ $offset = $response->file['offset'];
+ $length = $response->file['length'];
+ $file_size = (int)\filesize($file);
+ $body_len = $length > 0 ? $length : $file_size - $offset;
+ $response->withHeaders(array(
+ 'Content-Length' => $body_len,
+ 'Accept-Ranges' => 'bytes',
+ ));
+ if ($offset || $length) {
+ $offset_end = $offset + $body_len - 1;
+ $response->header('Content-Range', "bytes $offset-$offset_end/$file_size");
+ }
+ if ($body_len < 2 * 1024 * 1024) {
+ $connection->send((string)$response . file_get_contents($file, false, null, $offset, $body_len), true);
+ return '';
+ }
+ $handler = \fopen($file, 'r');
+ if (false === $handler) {
+ $connection->close(new Response(403, null, '403 Forbidden'));
+ return '';
+ }
+ $connection->send((string)$response, true);
+ static::sendStream($connection, $handler, $offset, $length);
+ return '';
+ }
+
+ return (string)$response;
+ }
+
+ /**
+ * Send remainder of a stream to client.
+ *
+ * @param TcpConnection $connection
+ * @param $handler
+ * @param $offset
+ * @param $length
+ */
+ protected static function sendStream(TcpConnection $connection, $handler, $offset = 0, $length = 0)
+ {
+ $connection->bufferFull = false;
+ if ($offset !== 0) {
+ \fseek($handler, $offset);
+ }
+ $offset_end = $offset + $length;
+ // Read file content from disk piece by piece and send to client.
+ $do_write = function () use ($connection, $handler, $length, $offset_end) {
+ // Send buffer not full.
+ while ($connection->bufferFull === false) {
+ // Read from disk.
+ $size = 1024 * 1024;
+ if ($length !== 0) {
+ $tell = \ftell($handler);
+ $remain_size = $offset_end - $tell;
+ if ($remain_size <= 0) {
+ fclose($handler);
+ $connection->onBufferDrain = null;
+ return;
+ }
+ $size = $remain_size > $size ? $size : $remain_size;
+ }
+
+ $buffer = \fread($handler, $size);
+ // Read eof.
+ if ($buffer === '' || $buffer === false) {
+ fclose($handler);
+ $connection->onBufferDrain = null;
+ return;
+ }
+ $connection->send($buffer, true);
+ }
+ };
+ // Send buffer full.
+ $connection->onBufferFull = function ($connection) {
+ $connection->bufferFull = true;
+ };
+ // Send buffer drain.
+ $connection->onBufferDrain = function ($connection) use ($do_write) {
+ $connection->bufferFull = false;
+ $do_write();
+ };
+ $do_write();
+ }
+
+ /**
+ * Set or get uploadTmpDir.
+ *
+ * @return bool|string
+ */
+ public static function uploadTmpDir($dir = null)
+ {
+ if (null !== $dir) {
+ static::$_uploadTmpDir = $dir;
+ }
+ if (static::$_uploadTmpDir === '') {
+ if ($upload_tmp_dir = \ini_get('upload_tmp_dir')) {
+ static::$_uploadTmpDir = $upload_tmp_dir;
+ } else if ($upload_tmp_dir = \sys_get_temp_dir()) {
+ static::$_uploadTmpDir = $upload_tmp_dir;
+ }
+ }
+ return static::$_uploadTmpDir;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Chunk.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Chunk.php
new file mode 100644
index 0000000..00f3570
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Chunk.php
@@ -0,0 +1,48 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols\Http;
+
+
+/**
+ * Class Chunk
+ * @package Workerman\Protocols\Http
+ */
+class Chunk
+{
+ /**
+ * Chunk buffer.
+ *
+ * @var string
+ */
+ protected $_buffer = null;
+
+ /**
+ * Chunk constructor.
+ * @param $buffer
+ */
+ public function __construct($buffer)
+ {
+ $this->_buffer = $buffer;
+ }
+
+ /**
+ * __toString
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return \dechex(\strlen($this->_buffer))."\r\n$this->_buffer\r\n";
+ }
+}
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Request.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Request.php
new file mode 100644
index 0000000..0484f21
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Request.php
@@ -0,0 +1,623 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols\Http;
+
+use Workerman\Connection\TcpConnection;
+use Workerman\Protocols\Http\Session;
+use Workerman\Protocols\Http;
+use Workerman\Worker;
+
+/**
+ * Class Request
+ * @package Workerman\Protocols\Http
+ */
+class Request
+{
+ /**
+ * Connection.
+ *
+ * @var TcpConnection
+ */
+ public $connection = null;
+
+ /**
+ * Session instance.
+ *
+ * @var Session
+ */
+ public $session = null;
+
+ /**
+ * Properties.
+ *
+ * @var array
+ */
+ public $properties = array();
+
+ /**
+ * Http buffer.
+ *
+ * @var string
+ */
+ protected $_buffer = null;
+
+ /**
+ * Request data.
+ *
+ * @var array
+ */
+ protected $_data = null;
+
+ /**
+ * Header cache.
+ *
+ * @var array
+ */
+ protected static $_headerCache = array();
+
+ /**
+ * Get cache.
+ *
+ * @var array
+ */
+ protected static $_getCache = array();
+
+ /**
+ * Post cache.
+ *
+ * @var array
+ */
+ protected static $_postCache = array();
+
+ /**
+ * Enable cache.
+ *
+ * @var bool
+ */
+ protected static $_enableCache = true;
+
+
+ /**
+ * Request constructor.
+ *
+ * @param $buffer
+ */
+ public function __construct($buffer)
+ {
+ $this->_buffer = $buffer;
+ }
+
+ /**
+ * $_GET.
+ *
+ * @param null $name
+ * @param null $default
+ * @return mixed|null
+ */
+ public function get($name = null, $default = null)
+ {
+ if (!isset($this->_data['get'])) {
+ $this->parseGet();
+ }
+ if (null === $name) {
+ return $this->_data['get'];
+ }
+ return isset($this->_data['get'][$name]) ? $this->_data['get'][$name] : $default;
+ }
+
+ /**
+ * $_POST.
+ *
+ * @param $name
+ * @param null $default
+ * @return mixed|null
+ */
+ public function post($name = null, $default = null)
+ {
+ if (!isset($this->_data['post'])) {
+ $this->parsePost();
+ }
+ if (null === $name) {
+ return $this->_data['post'];
+ }
+ return isset($this->_data['post'][$name]) ? $this->_data['post'][$name] : $default;
+ }
+
+ /**
+ * Get header item by name.
+ *
+ * @param null $name
+ * @param null $default
+ * @return string|null
+ */
+ public function header($name = null, $default = null)
+ {
+ if (!isset($this->_data['headers'])) {
+ $this->parseHeaders();
+ }
+ if (null === $name) {
+ return $this->_data['headers'];
+ }
+ $name = \strtolower($name);
+ return isset($this->_data['headers'][$name]) ? $this->_data['headers'][$name] : $default;
+ }
+
+ /**
+ * Get cookie item by name.
+ *
+ * @param null $name
+ * @param null $default
+ * @return string|null
+ */
+ public function cookie($name = null, $default = null)
+ {
+ if (!isset($this->_data['cookie'])) {
+ \parse_str(\str_replace('; ', '&', $this->header('cookie')), $this->_data['cookie']);
+ }
+ if ($name === null) {
+ return $this->_data['cookie'];
+ }
+ return isset($this->_data['cookie'][$name]) ? $this->_data['cookie'][$name] : $default;
+ }
+
+ /**
+ * Get upload files.
+ *
+ * @param null $name
+ * @return array|null
+ */
+ public function file($name = null)
+ {
+ if (!isset($this->_data['files'])) {
+ $this->parsePost();
+ }
+ if (null === $name) {
+ return $this->_data['files'];
+ }
+ return isset($this->_data['files'][$name]) ? $this->_data['files'][$name] : null;
+ }
+
+ /**
+ * Get method.
+ *
+ * @return string
+ */
+ public function method()
+ {
+ if (!isset($this->_data['method'])) {
+ $this->parseHeadFirstLine();
+ }
+ return $this->_data['method'];
+ }
+
+ /**
+ * Get http protocol version.
+ *
+ * @return string.
+ */
+ public function protocolVersion()
+ {
+ if (!isset($this->_data['protocolVersion'])) {
+ $this->parseProtocolVersion();
+ }
+ return $this->_data['protocolVersion'];
+ }
+
+ /**
+ * Get host.
+ *
+ * @param bool $without_port
+ * @return string
+ */
+ public function host($without_port = false)
+ {
+ $host = $this->header('host');
+ if ($without_port && $pos = \strpos($host, ':')) {
+ return \substr($host, 0, $pos);
+ }
+ return $host;
+ }
+
+ /**
+ * Get uri.
+ *
+ * @return mixed
+ */
+ public function uri()
+ {
+ if (!isset($this->_data['uri'])) {
+ $this->parseHeadFirstLine();
+ }
+ return $this->_data['uri'];
+ }
+
+ /**
+ * Get path.
+ *
+ * @return mixed
+ */
+ public function path()
+ {
+ if (!isset($this->_data['path'])) {
+ $this->_data['path'] = \parse_url($this->uri(), PHP_URL_PATH);
+ }
+ return $this->_data['path'];
+ }
+
+ /**
+ * Get query string.
+ *
+ * @return mixed
+ */
+ public function queryString()
+ {
+ if (!isset($this->_data['query_string'])) {
+ $this->_data['query_string'] = \parse_url($this->uri(), PHP_URL_QUERY);
+ }
+ return $this->_data['query_string'];
+ }
+
+ /**
+ * Get session.
+ *
+ * @return bool|\Workerman\Protocols\Http\Session
+ */
+ public function session()
+ {
+ if ($this->session === null) {
+ $session_id = $this->sessionId();
+ if ($session_id === false) {
+ return false;
+ }
+ $this->session = new Session($session_id);
+ }
+ return $this->session;
+ }
+
+ /**
+ * Get session id.
+ *
+ * @return bool|mixed
+ */
+ public function sessionId()
+ {
+ if (!isset($this->_data['sid'])) {
+ $session_name = Http::sessionName();
+ $sid = $this->cookie($session_name);
+ if ($sid === '' || $sid === null) {
+ if ($this->connection === null) {
+ Worker::safeEcho('Request->session() fail, header already send');
+ return false;
+ }
+ $sid = static::createSessionId();
+ $cookie_params = \session_get_cookie_params();
+ $this->connection->__header['Set-Cookie'] = array($session_name . '=' . $sid
+ . (empty($cookie_params['domain']) ? '' : '; Domain=' . $cookie_params['domain'])
+ . (empty($cookie_params['lifetime']) ? '' : '; Max-Age=' . ($cookie_params['lifetime'] + \time()))
+ . (empty($cookie_params['path']) ? '' : '; Path=' . $cookie_params['path'])
+ . (empty($cookie_params['samesite']) ? '' : '; SameSite=' . $cookie_params['samesite'])
+ . (!$cookie_params['secure'] ? '' : '; Secure')
+ . (!$cookie_params['httponly'] ? '' : '; HttpOnly'));
+ }
+ $this->_data['sid'] = $sid;
+ }
+ return $this->_data['sid'];
+ }
+
+ /**
+ * Get http raw head.
+ *
+ * @return string
+ */
+ public function rawHead()
+ {
+ if (!isset($this->_data['head'])) {
+ $this->_data['head'] = \strstr($this->_buffer, "\r\n\r\n", true);
+ }
+ return $this->_data['head'];
+ }
+
+ /**
+ * Get http raw body.
+ *
+ * @return string
+ */
+ public function rawBody()
+ {
+ return \substr($this->_buffer, \strpos($this->_buffer, "\r\n\r\n") + 4);
+ }
+
+ /**
+ * Get raw buffer.
+ *
+ * @return string
+ */
+ public function rawBuffer()
+ {
+ return $this->_buffer;
+ }
+
+ /**
+ * Enable or disable cache.
+ *
+ * @param $value
+ */
+ public static function enableCache($value)
+ {
+ static::$_enableCache = (bool)$value;
+ }
+
+ /**
+ * Parse first line of http header buffer.
+ *
+ * @return void
+ */
+ protected function parseHeadFirstLine()
+ {
+ $first_line = \strstr($this->_buffer, "\r\n", true);
+ $tmp = \explode(' ', $first_line, 3);
+ $this->_data['method'] = $tmp[0];
+ $this->_data['uri'] = isset($tmp[1]) ? $tmp[1] : '/';
+ }
+
+ /**
+ * Parse protocol version.
+ *
+ * @return void
+ */
+ protected function parseProtocolVersion()
+ {
+ $first_line = \strstr($this->_buffer, "\r\n", true);
+ $protoco_version = substr(\strstr($first_line, 'HTTP/'), 5);
+ $this->_data['protocolVersion'] = $protoco_version ? $protoco_version : '1.0';
+ }
+
+ /**
+ * Parse headers.
+ *
+ * @return void
+ */
+ protected function parseHeaders()
+ {
+ $this->_data['headers'] = array();
+ $raw_head = $this->rawHead();
+ $head_buffer = \substr($raw_head, \strpos($raw_head, "\r\n") + 2);
+ $cacheable = static::$_enableCache && !isset($head_buffer[2048]);
+ if ($cacheable && isset(static::$_headerCache[$head_buffer])) {
+ $this->_data['headers'] = static::$_headerCache[$head_buffer];
+ return;
+ }
+ $head_data = \explode("\r\n", $head_buffer);
+ foreach ($head_data as $content) {
+ if (false !== \strpos($content, ':')) {
+ list($key, $value) = \explode(':', $content, 2);
+ $this->_data['headers'][\strtolower($key)] = \ltrim($value);
+ } else {
+ $this->_data['headers'][\strtolower($content)] = '';
+ }
+ }
+ if ($cacheable) {
+ static::$_headerCache[$head_buffer] = $this->_data['headers'];
+ if (\count(static::$_headerCache) > 128) {
+ unset(static::$_headerCache[key(static::$_headerCache)]);
+ }
+ }
+ }
+
+ /**
+ * Parse head.
+ *
+ * @return void
+ */
+ protected function parseGet()
+ {
+ $query_string = $this->queryString();
+ $this->_data['get'] = array();
+ if ($query_string === '') {
+ return;
+ }
+ $cacheable = static::$_enableCache && !isset($query_string[1024]);
+ if ($cacheable && isset(static::$_getCache[$query_string])) {
+ $this->_data['get'] = static::$_getCache[$query_string];
+ return;
+ }
+ \parse_str($query_string, $this->_data['get']);
+ if ($cacheable) {
+ static::$_getCache[$query_string] = $this->_data['get'];
+ if (\count(static::$_getCache) > 256) {
+ unset(static::$_getCache[key(static::$_getCache)]);
+ }
+ }
+ }
+
+ /**
+ * Parse post.
+ *
+ * @return void
+ */
+ protected function parsePost()
+ {
+ $body_buffer = $this->rawBody();
+ $this->_data['post'] = $this->_data['files'] = array();
+ if ($body_buffer === '') {
+ return;
+ }
+ $cacheable = static::$_enableCache && !isset($body_buffer[1024]);
+ if ($cacheable && isset(static::$_postCache[$body_buffer])) {
+ $this->_data['post'] = static::$_postCache[$body_buffer];
+ return;
+ }
+ $content_type = $this->header('content-type', '');
+ if (\preg_match('/boundary="?(\S+)"?/', $content_type, $match)) {
+ $http_post_boundary = '--' . $match[1];
+ $this->parseUploadFiles($http_post_boundary);
+ return;
+ }
+ if (\preg_match('/\bjson\b/i', $content_type)) {
+ $this->_data['post'] = (array) json_decode($body_buffer, true);
+ } else {
+ \parse_str($body_buffer, $this->_data['post']);
+ }
+ if ($cacheable) {
+ static::$_postCache[$body_buffer] = $this->_data['post'];
+ if (\count(static::$_postCache) > 256) {
+ unset(static::$_postCache[key(static::$_postCache)]);
+ }
+ }
+ }
+
+ /**
+ * Parse upload files.
+ *
+ * @param $http_post_boundary
+ * @return void
+ */
+ protected function parseUploadFiles($http_post_boundary)
+ {
+ $http_body = $this->rawBody();
+ $http_body = \substr($http_body, 0, \strlen($http_body) - (\strlen($http_post_boundary) + 4));
+ $boundary_data_array = \explode($http_post_boundary . "\r\n", $http_body);
+ if ($boundary_data_array[0] === '') {
+ unset($boundary_data_array[0]);
+ }
+ $key = -1;
+ $files = array();
+ foreach ($boundary_data_array as $boundary_data_buffer) {
+ list($boundary_header_buffer, $boundary_value) = \explode("\r\n\r\n", $boundary_data_buffer, 2);
+ // Remove \r\n from the end of buffer.
+ $boundary_value = \substr($boundary_value, 0, -2);
+ $key++;
+ foreach (\explode("\r\n", $boundary_header_buffer) as $item) {
+ list($header_key, $header_value) = \explode(": ", $item);
+ $header_key = \strtolower($header_key);
+ switch ($header_key) {
+ case "content-disposition":
+ // Is file data.
+ if (\preg_match('/name="(.*?)"; filename="(.*?)"$/i', $header_value, $match)) {
+ $error = 0;
+ $tmp_file = '';
+ $size = \strlen($boundary_value);
+ $tmp_upload_dir = HTTP::uploadTmpDir();
+ if (!$tmp_upload_dir) {
+ $error = UPLOAD_ERR_NO_TMP_DIR;
+ } else {
+ $tmp_file = \tempnam($tmp_upload_dir, 'workerman.upload.');
+ if ($tmp_file === false || false == \file_put_contents($tmp_file, $boundary_value)) {
+ $error = UPLOAD_ERR_CANT_WRITE;
+ }
+ }
+ // Parse upload files.
+ $files[$key] = array(
+ 'key' => $match[1],
+ 'name' => $match[2],
+ 'tmp_name' => $tmp_file,
+ 'size' => $size,
+ 'error' => $error
+ );
+ break;
+ } // Is post field.
+ else {
+ // Parse $_POST.
+ if (\preg_match('/name="(.*?)"$/', $header_value, $match)) {
+ $this->_data['post'][$match[1]] = $boundary_value;
+ }
+ }
+ break;
+ case "content-type":
+ // add file_type
+ $files[$key]['type'] = \trim($header_value);
+ break;
+ }
+ }
+ }
+
+ foreach ($files as $file) {
+ $key = $file['key'];
+ unset($file['key']);
+ $this->_data['files'][$key] = $file;
+ }
+ }
+
+ /**
+ * Create session id.
+ *
+ * @return string
+ */
+ protected static function createSessionId()
+ {
+ return \bin2hex(\pack('d', \microtime(true)) . \pack('N', \mt_rand()));
+ }
+
+ /**
+ * Setter.
+ *
+ * @param $name
+ * @param $value
+ * @return void
+ */
+ public function __set($name, $value)
+ {
+ $this->properties[$name] = $value;
+ }
+
+ /**
+ * Getter.
+ *
+ * @param $name
+ * @return mixed|null
+ */
+ public function __get($name)
+ {
+ return isset($this->properties[$name]) ? $this->properties[$name] : null;
+ }
+
+ /**
+ * Isset.
+ *
+ * @param $name
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ return isset($this->properties[$name]);
+ }
+
+ /**
+ * Unset.
+ *
+ * @param $name
+ * @return void
+ */
+ public function __unset($name)
+ {
+ unset($this->properties[$name]);
+ }
+
+ /**
+ * __destruct.
+ *
+ * @return void
+ */
+ public function __destruct()
+ {
+ if (isset($this->_data['files'])) {
+ \clearstatcache();
+ foreach ($this->_data['files'] as $item) {
+ if (\is_file($item['tmp_name'])) {
+ \unlink($item['tmp_name']);
+ }
+ }
+ }
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Response.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Response.php
new file mode 100644
index 0000000..14e8ac1
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Response.php
@@ -0,0 +1,447 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols\Http;
+
+/**
+ * Class Response
+ * @package Workerman\Protocols\Http
+ */
+class Response
+{
+ /**
+ * Header data.
+ *
+ * @var array
+ */
+ protected $_header = null;
+
+ /**
+ * Http status.
+ *
+ * @var int
+ */
+ protected $_status = null;
+
+ /**
+ * Http reason.
+ *
+ * @var string
+ */
+ protected $_reason = null;
+
+ /**
+ * Http version.
+ *
+ * @var string
+ */
+ protected $_version = '1.1';
+
+ /**
+ * Http body.
+ *
+ * @var string
+ */
+ protected $_body = null;
+
+ /**
+ * Mine type map.
+ * @var array
+ */
+ protected static $_mimeTypeMap = null;
+
+ /**
+ * Phrases.
+ *
+ * @var array
+ */
+ protected static $_phrases = array(
+ 100 => 'Continue',
+ 101 => 'Switching Protocols',
+ 102 => 'Processing',
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 207 => 'Multi-status',
+ 208 => 'Already Reported',
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 306 => 'Switch Proxy',
+ 307 => 'Temporary Redirect',
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Time-out',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Large',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested range not satisfiable',
+ 417 => 'Expectation Failed',
+ 418 => 'I\'m a teapot',
+ 422 => 'Unprocessable Entity',
+ 423 => 'Locked',
+ 424 => 'Failed Dependency',
+ 425 => 'Unordered Collection',
+ 426 => 'Upgrade Required',
+ 428 => 'Precondition Required',
+ 429 => 'Too Many Requests',
+ 431 => 'Request Header Fields Too Large',
+ 451 => 'Unavailable For Legal Reasons',
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Time-out',
+ 505 => 'HTTP Version not supported',
+ 506 => 'Variant Also Negotiates',
+ 507 => 'Insufficient Storage',
+ 508 => 'Loop Detected',
+ 511 => 'Network Authentication Required',
+ );
+
+ /**
+ * Init.
+ *
+ * @return void
+ */
+ public static function init() {
+ static::initMimeTypeMap();
+ }
+
+ /**
+ * Response constructor.
+ *
+ * @param int $status
+ * @param array $headers
+ * @param string $body
+ */
+ public function __construct(
+ $status = 200,
+ $headers = array(),
+ $body = ''
+ ) {
+ $this->_status = $status;
+ $this->_header = $headers;
+ $this->_body = $body;
+ }
+
+ /**
+ * Set header.
+ *
+ * @param $name
+ * @param $value
+ * @return $this
+ */
+ public function header($name, $value) {
+ $this->_header[$name] = $value;
+ return $this;
+ }
+
+ /**
+ * Set header.
+ *
+ * @param $name
+ * @param $value
+ * @return Response
+ */
+ public function withHeader($name, $value) {
+ return $this->header($name, $value);
+ }
+
+ /**
+ * Set headers.
+ *
+ * @param $headers
+ * @return $this
+ */
+ public function withHeaders($headers) {
+ $this->_header = \array_merge($this->_header, $headers);
+ return $this;
+ }
+
+ /**
+ * Remove header.
+ *
+ * @param $name
+ * @return $this
+ */
+ public function withoutHeader($name) {
+ unset($this->_header[$name]);
+ return $this;
+ }
+
+ /**
+ * Get header.
+ *
+ * @param $name
+ * @return null|array|string
+ */
+ public function getHeader($name) {
+ if (!isset($this->_header[$name])) {
+ return null;
+ }
+ return $this->_header[$name];
+ }
+
+ /**
+ * Get headers.
+ *
+ * @return array
+ */
+ public function getHeaders() {
+ return $this->_header;
+ }
+
+ /**
+ * Set status.
+ *
+ * @param $code
+ * @param null $reason_phrase
+ * @return $this
+ */
+ public function withStatus($code, $reason_phrase = null) {
+ $this->_status = $code;
+ $this->_reason = $reason_phrase;
+ return $this;
+ }
+
+ /**
+ * Get status code.
+ *
+ * @return int
+ */
+ public function getStatusCode() {
+ return $this->_status;
+ }
+
+ /**
+ * Get reason phrase.
+ *
+ * @return string
+ */
+ public function getReasonPhrase() {
+ return $this->_reason;
+ }
+
+ /**
+ * Set protocol version.
+ *
+ * @param $version
+ * @return $this
+ */
+ public function withProtocolVersion($version) {
+ $this->_version = $version;
+ return $this;
+ }
+
+ /**
+ * Set http body.
+ *
+ * @param $body
+ * @return $this
+ */
+ public function withBody($body) {
+ $this->_body = $body;
+ return $this;
+ }
+
+ /**
+ * Get http raw body.
+ */
+ public function rawBody() {
+ return $this->_body;
+ }
+
+ /**
+ * Send file.
+ *
+ * @param $file
+ * @param int $offset
+ * @param int $length
+ * @return $this
+ */
+ public function withFile($file, $offset = 0, $length = 0) {
+ if (!\is_file($file)) {
+ return $this->withStatus(404)->withBody('404 Not Found
');
+ }
+ $this->file = array('file' => $file, 'offset' => $offset, 'length' => $length);
+ return $this;
+ }
+
+ /**
+ * Set cookie.
+ *
+ * @param $name
+ * @param string $value
+ * @param int $maxage
+ * @param string $path
+ * @param string $domain
+ * @param bool $secure
+ * @param bool $http_only
+ * @return $this
+ */
+ public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = '', $secure = false, $http_only = false)
+ {
+ $this->_header['Set-Cookie'][] = $name . '=' . \rawurlencode($value)
+ . (empty($domain) ? '' : '; Domain=' . $domain)
+ . (empty($max_age) ? '' : '; Max-Age=' . $max_age)
+ . (empty($path) ? '' : '; Path=' . $path)
+ . (!$secure ? '' : '; Secure')
+ . (!$http_only ? '' : '; HttpOnly');
+ return $this;
+ }
+
+ /**
+ * Create header for file.
+ *
+ * @param $file
+ * @return string
+ */
+ protected function createHeadForFile($file_info)
+ {
+ $file = $file_info['file'];
+ $reason = $this->_reason ? $this->_reason : static::$_phrases[$this->_status];
+ $head = "HTTP/{$this->_version} {$this->_status} $reason\r\n";
+ $headers = $this->_header;
+ if (!isset($headers['Server'])) {
+ $head .= "Server: workerman\r\n";
+ }
+ foreach ($headers as $name => $value) {
+ if (\is_array($value)) {
+ foreach ($value as $item) {
+ $head .= "$name: $item\r\n";
+ }
+ continue;
+ }
+ $head .= "$name: $value\r\n";
+ }
+
+ if (!isset($headers['Connection'])) {
+ $head .= "Connection: keep-alive\r\n";
+ }
+
+ $file_info = \pathinfo($file);
+ $extension = isset($file_info['extension']) ? $file_info['extension'] : '';
+ $base_name = isset($file_info['basename']) ? $file_info['basename'] : 'unknown';
+ if (!isset($headers['Content-Type'])) {
+ if (isset(self::$_mimeTypeMap[$extension])) {
+ $head .= "Content-Type: " . self::$_mimeTypeMap[$extension] . "\r\n";
+ } else {
+ $head .= "Content-Type: application/octet-stream\r\n";
+ }
+ }
+
+ if (!isset($headers['Content-Disposition']) && !isset(self::$_mimeTypeMap[$extension])) {
+ $head .= "Content-Disposition: attachment; filename=\"$base_name\"\r\n";
+ }
+
+ if (!isset($headers['Last-Modified'])) {
+ if ($mtime = \filemtime($file)) {
+ $head .= 'Last-Modified: '.\date('D, d M Y H:i:s', $mtime) . ' ' . \date_default_timezone_get() ."\r\n";
+ }
+ }
+
+ return "{$head}\r\n";
+ }
+
+ /**
+ * __toString.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ if (isset($this->file)) {
+ return $this->createHeadForFile($this->file);
+ }
+
+ $reason = $this->_reason ? $this->_reason : static::$_phrases[$this->_status];
+ $body_len = \strlen($this->_body);
+ if (empty($this->_header)) {
+ return "HTTP/{$this->_version} {$this->_status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\nConnection: keep-alive\r\n\r\n{$this->_body}";
+ }
+
+ $head = "HTTP/{$this->_version} {$this->_status} $reason\r\n";
+ $headers = $this->_header;
+ if (!isset($headers['Server'])) {
+ $head .= "Server: workerman\r\n";
+ }
+ foreach ($headers as $name => $value) {
+ if (\is_array($value)) {
+ foreach ($value as $item) {
+ $head .= "$name: $item\r\n";
+ }
+ continue;
+ }
+ $head .= "$name: $value\r\n";
+ }
+
+ if (!isset($headers['Connection'])) {
+ $head .= "Connection: keep-alive\r\n";
+ }
+
+ if (!isset($headers['Content-Type'])) {
+ $head .= "Content-Type: text/html;charset=utf-8\r\n";
+ } else if ($headers['Content-Type'] === 'text/event-stream') {
+ return $head . $this->_body;
+ }
+
+ if (!isset($headers['Transfer-Encoding'])) {
+ $head .= "Content-Length: $body_len\r\n\r\n";
+ } else {
+ return "$head\r\n".dechex($body_len)."\r\n{$this->_body}\r\n";
+ }
+
+ // The whole http package
+ return $head . $this->_body;
+ }
+
+ /**
+ * Init mime map.
+ *
+ * @return void
+ */
+ public static function initMimeTypeMap()
+ {
+ $mime_file = __DIR__ . '/mime.types';
+ $items = \file($mime_file, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES);
+ foreach ($items as $content) {
+ if (\preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) {
+ $mime_type = $match[1];
+ $extension_var = $match[2];
+ $extension_array = \explode(' ', \substr($extension_var, 0, -1));
+ foreach ($extension_array as $file_extension) {
+ static::$_mimeTypeMap[$file_extension] = $mime_type;
+ }
+ }
+ }
+ }
+}
+Response::init();
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/ServerSentEvents.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/ServerSentEvents.php
new file mode 100644
index 0000000..7aeafc7
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/ServerSentEvents.php
@@ -0,0 +1,64 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols\Http;
+
+/**
+ * Class ServerSentEvents
+ * @package Workerman\Protocols\Http
+ */
+class ServerSentEvents
+{
+ /**
+ * Data.
+ * @var array
+ */
+ protected $_data = null;
+
+ /**
+ * ServerSentEvents constructor.
+ * $data for example ['event'=>'ping', 'data' => 'some thing', 'id' => 1000, 'retry' => 5000]
+ * @param array $data
+ */
+ public function __construct(array $data)
+ {
+ $this->_data = $data;
+ }
+
+ /**
+ * __toString.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $buffer = '';
+ $data = $this->_data;
+ if (isset($data[''])) {
+ $buffer = ": {$data['']}\n";
+ }
+ if (isset($data['event'])) {
+ $buffer .= "event: {$data['event']}\n";
+ }
+ if (isset($data['data'])) {
+ $buffer .= 'data: ' . \str_replace("\n", "\ndata: ", $data['data']) . "\n\n";
+ }
+ if (isset($data['id'])) {
+ $buffer .= "id: {$data['id']}\n";
+ }
+ if (isset($data['retry'])) {
+ $buffer .= "retry: {$data['retry']}\n";
+ }
+ return $buffer;
+ }
+}
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Session.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Session.php
new file mode 100644
index 0000000..91d5cf5
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Session.php
@@ -0,0 +1,359 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols\Http;
+
+
+/**
+ * Class Session
+ * @package Workerman\Protocols\Http
+ */
+class Session
+{
+ /**
+ * Session andler class which implements SessionHandlerInterface.
+ *
+ * @var string
+ */
+ protected static $_handlerClass = 'Workerman\Protocols\Http\Session\FileSessionHandler';
+
+ /**
+ * Parameters of __constructor for session handler class.
+ *
+ * @var null
+ */
+ protected static $_handlerConfig = null;
+
+ /**
+ * Session.gc_probability
+ *
+ * @var int
+ */
+ protected static $_sessionGcProbability = 1;
+
+ /**
+ * Session.gc_divisor
+ *
+ * @var int
+ */
+ protected static $_sessionGcDivisor = 1000;
+
+ /**
+ * Session.gc_maxlifetime
+ *
+ * @var int
+ */
+ protected static $_sessionGcMaxLifeTime = 1440;
+
+ /**
+ * Session handler instance.
+ *
+ * @var \SessionHandlerInterface
+ */
+ protected static $_handler = null;
+
+ /**
+ * Session data.
+ *
+ * @var array
+ */
+ protected $_data = array();
+
+ /**
+ * Session changed and need to save.
+ *
+ * @var bool
+ */
+ protected $_needSave = false;
+
+ /**
+ * Session id.
+ *
+ * @var null
+ */
+ protected $_sessionId = null;
+
+ /**
+ * Session constructor.
+ *
+ * @param $session_id
+ */
+ public function __construct($session_id)
+ {
+ static::checkSessionId($session_id);
+ if (static::$_handler === null) {
+ static::initHandler();
+ }
+ $this->_sessionId = $session_id;
+ if ($data = static::$_handler->read($session_id)) {
+ $this->_data = \unserialize($data);
+ }
+ }
+
+ /**
+ * Get session id.
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ return $this->_sessionId;
+ }
+
+ /**
+ * Get session.
+ *
+ * @param $name
+ * @param null $default
+ * @return mixed|null
+ */
+ public function get($name, $default = null)
+ {
+ return isset($this->_data[$name]) ? $this->_data[$name] : $default;
+ }
+
+ /**
+ * Store data in the session.
+ *
+ * @param $name
+ * @param $value
+ */
+ public function set($name, $value)
+ {
+ $this->_data[$name] = $value;
+ $this->_needSave = true;
+ }
+
+ /**
+ * Delete an item from the session.
+ *
+ * @param $name
+ */
+ public function delete($name)
+ {
+ unset($this->_data[$name]);
+ $this->_needSave = true;
+ }
+
+ /**
+ * Retrieve and delete an item from the session.
+ *
+ * @param $name
+ * @param null $default
+ * @return mixed|null
+ */
+ public function pull($name, $default = null)
+ {
+ $value = $this->get($name, $default);
+ $this->delete($name);
+ return $value;
+ }
+
+ /**
+ * Store data in the session.
+ *
+ * @param $key
+ * @param null $value
+ */
+ public function put($key, $value = null)
+ {
+ if (!\is_array($key)) {
+ $this->set($key, $value);
+ return;
+ }
+
+ foreach ($key as $k => $v) {
+ $this->_data[$k] = $v;
+ }
+ $this->_needSave = true;
+ }
+
+ /**
+ * Remove a piece of data from the session.
+ *
+ * @param $name
+ */
+ public function forget($name)
+ {
+ if (\is_scalar($name)) {
+ $this->delete($name);
+ return;
+ }
+ if (\is_array($name)) {
+ foreach ($name as $key) {
+ unset($this->_data[$key]);
+ }
+ }
+ $this->_needSave = true;
+ }
+
+ /**
+ * Retrieve all the data in the session.
+ *
+ * @return array
+ */
+ public function all()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Remove all data from the session.
+ *
+ * @return void
+ */
+ public function flush()
+ {
+ $this->_needSave = true;
+ $this->_data = array();
+ }
+
+ /**
+ * Determining If An Item Exists In The Session.
+ *
+ * @param $name
+ * @return bool
+ */
+ public function has($name)
+ {
+ return isset($this->_data[$name]);
+ }
+
+ /**
+ * To determine if an item is present in the session, even if its value is null.
+ *
+ * @param $name
+ * @return bool
+ */
+ public function exists($name)
+ {
+ return \array_key_exists($name, $this->_data);
+ }
+
+ /**
+ * Save session to store.
+ *
+ * @return void
+ */
+ public function save()
+ {
+ if ($this->_needSave) {
+ if (empty($this->_data)) {
+ static::$_handler->destroy($this->_sessionId);
+ } else {
+ static::$_handler->write($this->_sessionId, \serialize($this->_data));
+ }
+ }
+ $this->_needSave = false;
+ }
+
+ /**
+ * Init.
+ *
+ * @return void
+ */
+ public static function init()
+ {
+ if ($gc_probability = \ini_get('session.gc_probability')) {
+ self::$_sessionGcProbability = (int)$gc_probability;
+ }
+
+ if ($gc_divisor = \ini_get('session.gc_divisor')) {
+ self::$_sessionGcDivisor = (int)$gc_divisor;
+ }
+
+ if ($gc_max_life_time = \ini_get('session.gc_maxlifetime')) {
+ self::$_sessionGcMaxLifeTime = (int)$gc_max_life_time;
+ }
+ }
+
+ /**
+ * Set session handler class.
+ *
+ * @param null $class_name
+ * @param null $config
+ * @return string
+ */
+ public static function handlerClass($class_name = null, $config = null)
+ {
+ if ($class_name) {
+ static::$_handlerClass = $class_name;
+ }
+ if ($config) {
+ static::$_handlerConfig = $config;
+ }
+ return static::$_handlerClass;
+ }
+
+ /**
+ * Init handler.
+ *
+ * @return void
+ */
+ protected static function initHandler()
+ {
+ if (static::$_handlerConfig === null) {
+ static::$_handler = new static::$_handlerClass();
+ } else {
+ static::$_handler = new static::$_handlerClass(static::$_handlerConfig);
+ }
+ }
+
+ /**
+ * Try GC sessions.
+ *
+ * @return void
+ */
+ public function tryGcSessions()
+ {
+ if (\rand(1, static::$_sessionGcDivisor) > static::$_sessionGcProbability) {
+ return;
+ }
+ static::$_handler->gc(static::$_sessionGcMaxLifeTime);
+ }
+
+ /**
+ * __destruct.
+ *
+ * @return void
+ */
+ public function __destruct()
+ {
+ $this->save();
+ $this->tryGcSessions();
+ }
+
+ /**
+ * Check session id.
+ *
+ * @param $session_id
+ */
+ protected static function checkSessionId($session_id)
+ {
+ if (!\preg_match('/^[a-zA-Z0-9]+$/', $session_id)) {
+ throw new SessionException("session_id $session_id is invalid");
+ }
+ }
+}
+
+/**
+ * Class SessionException
+ * @package Workerman\Protocols\Http
+ */
+class SessionException extends \RuntimeException
+{
+
+}
+
+// Init session.
+Session::init();
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Session/FileSessionHandler.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Session/FileSessionHandler.php
new file mode 100644
index 0000000..9baa34f
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Session/FileSessionHandler.php
@@ -0,0 +1,153 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols\Http\Session;
+
+/**
+ * Class FileSessionHandler
+ * @package Workerman\Protocols\Http\Session
+ */
+class FileSessionHandler implements \SessionHandlerInterface
+{
+ /**
+ * Session save path.
+ *
+ * @var string
+ */
+ protected static $_sessionSavePath = null;
+
+ /**
+ * Session file prefix.
+ *
+ * @var string
+ */
+ protected static $_sessionFilePrefix = 'session_';
+
+ /**
+ * Init.
+ */
+ public static function init() {
+ $save_path = @\session_save_path();
+ if (!$save_path || \strpos($save_path, 'tcp://') === 0) {
+ $save_path = \sys_get_temp_dir();
+ }
+ static::sessionSavePath($save_path);
+ }
+
+ /**
+ * FileSessionHandler constructor.
+ * @param array $config
+ */
+ public function __construct($config = array()) {
+ if (isset($config['save_path'])) {
+ static::sessionSavePath($config['save_path']);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function open($save_path, $name)
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read($session_id)
+ {
+ $session_file = static::sessionFile($session_id);
+ \clearstatcache();
+ if (\is_file($session_file)) {
+ $data = \file_get_contents($session_file);
+ return $data ? $data : '';
+ }
+ return '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write($session_id, $session_data)
+ {
+ $temp_file = static::$_sessionSavePath.uniqid(mt_rand(), true);
+ if (!\file_put_contents($temp_file, $session_data)) {
+ return false;
+ }
+ return \rename($temp_file, static::sessionFile($session_id));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function destroy($session_id)
+ {
+ $session_file = static::sessionFile($session_id);
+ if (\is_file($session_file)) {
+ \unlink($session_file);
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function gc($maxlifetime) {
+ $time_now = \time();
+ foreach (\glob(static::$_sessionSavePath . static::$_sessionFilePrefix . '*') as $file) {
+ if(\is_file($file) && $time_now - \filemtime($file) > $maxlifetime) {
+ \unlink($file);
+ }
+ }
+ }
+
+ /**
+ * Get session file path.
+ *
+ * @param $session_id
+ * @return string
+ */
+ protected static function sessionFile($session_id) {
+ return static::$_sessionSavePath.static::$_sessionFilePrefix.$session_id;
+ }
+
+ /**
+ * Get or set session file path.
+ *
+ * @param $path
+ * @return string
+ */
+ public static function sessionSavePath($path) {
+ if ($path) {
+ if ($path[\strlen($path)-1] !== DIRECTORY_SEPARATOR) {
+ $path .= DIRECTORY_SEPARATOR;
+ }
+ static::$_sessionSavePath = $path;
+ if (!\is_dir($path)) {
+ \mkdir($path, 0777, true);
+ }
+ }
+ return $path;
+ }
+}
+
+FileSessionHandler::init();
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Session/RedisSessionHandler.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Session/RedisSessionHandler.php
new file mode 100644
index 0000000..4876ab7
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/Session/RedisSessionHandler.php
@@ -0,0 +1,119 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols\Http\Session;
+
+/**
+ * Class RedisSessionHandler
+ * @package Workerman\Protocols\Http\Session
+ */
+class RedisSessionHandler extends \SessionHandler
+{
+
+ /**
+ * @var \Redis
+ */
+ protected $_redis;
+
+ /**
+ * @var int
+ */
+ protected $_maxLifeTime;
+
+ /**
+ * RedisSessionHandler constructor.
+ * @param $config = [
+ * 'host' => '127.0.0.1',
+ * 'port' => 6379,
+ * 'timeout' => 2,
+ * 'auth' => '******',
+ * 'database' => 2,
+ * 'prefix' => 'redis_session_',
+ * ]
+ */
+ public function __construct($config)
+ {
+ if (false === extension_loaded('redis')) {
+ throw new \RuntimeException('Please install redis extension.');
+ }
+ $this->_maxLifeTime = (int)ini_get('session.gc_maxlifetime');
+
+ if (!isset($config['timeout'])) {
+ $config['timeout'] = 2;
+ }
+
+ $this->_redis = new \Redis();
+ if (false === $this->_redis->connect($config['host'], $config['port'], $config['timeout'])) {
+ throw new \RuntimeException("Redis connect {$config['host']}:{$config['port']} fail.");
+ }
+ if (!empty($config['auth'])) {
+ $this->_redis->auth($config['auth']);
+ }
+ if (!empty($config['database'])) {
+ $this->_redis->select($config['database']);
+ }
+ if (empty($config['prefix'])) {
+ $config['prefix'] = 'redis_session_';
+ }
+ $this->_redis->setOption(\Redis::OPT_PREFIX, $config['prefix']);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function open($save_path, $name)
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read($session_id)
+ {
+ return $this->_redis->get($session_id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write($session_id, $session_data)
+ {
+ return true === $this->_redis->setex($session_id, $this->_maxLifeTime, $session_data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function destroy($session_id)
+ {
+ $this->_redis->del($session_id);
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function gc($maxlifetime)
+ {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/mime.types b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/mime.types
new file mode 100644
index 0000000..e6ccf0a
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Http/mime.types
@@ -0,0 +1,90 @@
+
+types {
+ text/html html htm shtml;
+ text/css css;
+ text/xml xml;
+ image/gif gif;
+ image/jpeg jpeg jpg;
+ application/javascript js;
+ application/atom+xml atom;
+ application/rss+xml rss;
+
+ text/mathml mml;
+ text/plain txt;
+ text/vnd.sun.j2me.app-descriptor jad;
+ text/vnd.wap.wml wml;
+ text/x-component htc;
+
+ image/png png;
+ image/tiff tif tiff;
+ image/vnd.wap.wbmp wbmp;
+ image/x-icon ico;
+ image/x-jng jng;
+ image/x-ms-bmp bmp;
+ image/svg+xml svg svgz;
+ image/webp webp;
+
+ application/font-woff woff;
+ application/java-archive jar war ear;
+ application/json json;
+ application/mac-binhex40 hqx;
+ application/msword doc;
+ application/pdf pdf;
+ application/postscript ps eps ai;
+ application/rtf rtf;
+ application/vnd.apple.mpegurl m3u8;
+ application/vnd.ms-excel xls;
+ application/vnd.ms-fontobject eot;
+ application/vnd.ms-powerpoint ppt;
+ application/vnd.wap.wmlc wmlc;
+ application/vnd.google-earth.kml+xml kml;
+ application/vnd.google-earth.kmz kmz;
+ application/x-7z-compressed 7z;
+ application/x-cocoa cco;
+ application/x-java-archive-diff jardiff;
+ application/x-java-jnlp-file jnlp;
+ application/x-makeself run;
+ application/x-perl pl pm;
+ application/x-pilot prc pdb;
+ application/x-rar-compressed rar;
+ application/x-redhat-package-manager rpm;
+ application/x-sea sea;
+ application/x-shockwave-flash swf;
+ application/x-stuffit sit;
+ application/x-tcl tcl tk;
+ application/x-x509-ca-cert der pem crt;
+ application/x-xpinstall xpi;
+ application/xhtml+xml xhtml;
+ application/xspf+xml xspf;
+ application/zip zip;
+
+ application/octet-stream bin exe dll;
+ application/octet-stream deb;
+ application/octet-stream dmg;
+ application/octet-stream iso img;
+ application/octet-stream msi msp msm;
+
+ application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
+ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
+ application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
+
+ audio/midi mid midi kar;
+ audio/mpeg mp3;
+ audio/ogg ogg;
+ audio/x-m4a m4a;
+ audio/x-realaudio ra;
+
+ video/3gpp 3gpp 3gp;
+ video/mp2t ts;
+ video/mp4 mp4;
+ video/mpeg mpeg mpg;
+ video/quicktime mov;
+ video/webm webm;
+ video/x-flv flv;
+ video/x-m4v m4v;
+ video/x-mng mng;
+ video/x-ms-asf asx asf;
+ video/x-ms-wmv wmv;
+ video/x-msvideo avi;
+ font/ttf ttf;
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/ProtocolInterface.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/ProtocolInterface.php
new file mode 100644
index 0000000..4fea87d
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/ProtocolInterface.php
@@ -0,0 +1,52 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols;
+
+use Workerman\Connection\ConnectionInterface;
+
+/**
+ * Protocol interface
+ */
+interface ProtocolInterface
+{
+ /**
+ * Check the integrity of the package.
+ * Please return the length of package.
+ * If length is unknow please return 0 that mean wating more data.
+ * If the package has something wrong please return false the connection will be closed.
+ *
+ * @param string $recv_buffer
+ * @param ConnectionInterface $connection
+ * @return int|false
+ */
+ public static function input($recv_buffer, ConnectionInterface $connection);
+
+ /**
+ * Decode package and emit onMessage($message) callback, $message is the result that decode returned.
+ *
+ * @param string $recv_buffer
+ * @param ConnectionInterface $connection
+ * @return mixed
+ */
+ public static function decode($recv_buffer, ConnectionInterface $connection);
+
+ /**
+ * Encode package brefore sending to client.
+ *
+ * @param mixed $data
+ * @param ConnectionInterface $connection
+ * @return string
+ */
+ public static function encode($data, ConnectionInterface $connection);
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Text.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Text.php
new file mode 100644
index 0000000..407ea2d
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Text.php
@@ -0,0 +1,70 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols;
+
+use Workerman\Connection\ConnectionInterface;
+
+/**
+ * Text Protocol.
+ */
+class Text
+{
+ /**
+ * Check the integrity of the package.
+ *
+ * @param string $buffer
+ * @param ConnectionInterface $connection
+ * @return int
+ */
+ public static function input($buffer, ConnectionInterface $connection)
+ {
+ // Judge whether the package length exceeds the limit.
+ if (isset($connection->maxPackageSize) && \strlen($buffer) >= $connection->maxPackageSize) {
+ $connection->close();
+ return 0;
+ }
+ // Find the position of "\n".
+ $pos = \strpos($buffer, "\n");
+ // No "\n", packet length is unknown, continue to wait for the data so return 0.
+ if ($pos === false) {
+ return 0;
+ }
+ // Return the current package length.
+ return $pos + 1;
+ }
+
+ /**
+ * Encode.
+ *
+ * @param string $buffer
+ * @return string
+ */
+ public static function encode($buffer)
+ {
+ // Add "\n"
+ return $buffer . "\n";
+ }
+
+ /**
+ * Decode.
+ *
+ * @param string $buffer
+ * @return string
+ */
+ public static function decode($buffer)
+ {
+ // Remove "\n"
+ return \rtrim($buffer, "\r\n");
+ }
+}
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Websocket.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Websocket.php
new file mode 100644
index 0000000..f00b147
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Websocket.php
@@ -0,0 +1,503 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols;
+
+use Workerman\Connection\ConnectionInterface;
+use Workerman\Connection\TcpConnection;
+use Workerman\Worker;
+
+/**
+ * WebSocket protocol.
+ */
+class Websocket implements \Workerman\Protocols\ProtocolInterface
+{
+ /**
+ * Websocket blob type.
+ *
+ * @var string
+ */
+ const BINARY_TYPE_BLOB = "\x81";
+
+ /**
+ * Websocket arraybuffer type.
+ *
+ * @var string
+ */
+ const BINARY_TYPE_ARRAYBUFFER = "\x82";
+
+ /**
+ * Check the integrity of the package.
+ *
+ * @param string $buffer
+ * @param ConnectionInterface $connection
+ * @return int
+ */
+ public static function input($buffer, ConnectionInterface $connection)
+ {
+ // Receive length.
+ $recv_len = \strlen($buffer);
+ // We need more data.
+ if ($recv_len < 6) {
+ return 0;
+ }
+
+ // Has not yet completed the handshake.
+ if (empty($connection->websocketHandshake)) {
+ return static::dealHandshake($buffer, $connection);
+ }
+
+ // Buffer websocket frame data.
+ if ($connection->websocketCurrentFrameLength) {
+ // We need more frame data.
+ if ($connection->websocketCurrentFrameLength > $recv_len) {
+ // Return 0, because it is not clear the full packet length, waiting for the frame of fin=1.
+ return 0;
+ }
+ } else {
+ $firstbyte = \ord($buffer[0]);
+ $secondbyte = \ord($buffer[1]);
+ $data_len = $secondbyte & 127;
+ $is_fin_frame = $firstbyte >> 7;
+ $masked = $secondbyte >> 7;
+
+ if (!$masked) {
+ Worker::safeEcho("frame not masked so close the connection\n");
+ $connection->close();
+ return 0;
+ }
+
+ $opcode = $firstbyte & 0xf;
+ switch ($opcode) {
+ case 0x0:
+ break;
+ // Blob type.
+ case 0x1:
+ break;
+ // Arraybuffer type.
+ case 0x2:
+ break;
+ // Close package.
+ case 0x8:
+ // Try to emit onWebSocketClose callback.
+ if (isset($connection->onWebSocketClose) || isset($connection->worker->onWebSocketClose)) {
+ try {
+ \call_user_func(isset($connection->onWebSocketClose)?$connection->onWebSocketClose:$connection->worker->onWebSocketClose, $connection);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ } // Close connection.
+ else {
+ $connection->close("\x88\x02\x03\xe8", true);
+ }
+ return 0;
+ // Ping package.
+ case 0x9:
+ break;
+ // Pong package.
+ case 0xa:
+ break;
+ // Wrong opcode.
+ default :
+ Worker::safeEcho("error opcode $opcode and close websocket connection. Buffer:" . bin2hex($buffer) . "\n");
+ $connection->close();
+ return 0;
+ }
+
+ // Calculate packet length.
+ $head_len = 6;
+ if ($data_len === 126) {
+ $head_len = 8;
+ if ($head_len > $recv_len) {
+ return 0;
+ }
+ $pack = \unpack('nn/ntotal_len', $buffer);
+ $data_len = $pack['total_len'];
+ } else {
+ if ($data_len === 127) {
+ $head_len = 14;
+ if ($head_len > $recv_len) {
+ return 0;
+ }
+ $arr = \unpack('n/N2c', $buffer);
+ $data_len = $arr['c1']*4294967296 + $arr['c2'];
+ }
+ }
+ $current_frame_length = $head_len + $data_len;
+
+ $total_package_size = \strlen($connection->websocketDataBuffer) + $current_frame_length;
+ if ($total_package_size > $connection->maxPackageSize) {
+ Worker::safeEcho("error package. package_length=$total_package_size\n");
+ $connection->close();
+ return 0;
+ }
+
+ if ($is_fin_frame) {
+ if ($opcode === 0x9) {
+ if ($recv_len >= $current_frame_length) {
+ $ping_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection);
+ $connection->consumeRecvBuffer($current_frame_length);
+ $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB;
+ $connection->websocketType = "\x8a";
+ if (isset($connection->onWebSocketPing) || isset($connection->worker->onWebSocketPing)) {
+ try {
+ \call_user_func(isset($connection->onWebSocketPing)?$connection->onWebSocketPing:$connection->worker->onWebSocketPing, $connection, $ping_data);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ } else {
+ $connection->send($ping_data);
+ }
+ $connection->websocketType = $tmp_connection_type;
+ if ($recv_len > $current_frame_length) {
+ return static::input(\substr($buffer, $current_frame_length), $connection);
+ }
+ }
+ return 0;
+ } else if ($opcode === 0xa) {
+ if ($recv_len >= $current_frame_length) {
+ $pong_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection);
+ $connection->consumeRecvBuffer($current_frame_length);
+ $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB;
+ $connection->websocketType = "\x8a";
+ // Try to emit onWebSocketPong callback.
+ if (isset($connection->onWebSocketPong) || isset($connection->worker->onWebSocketPong)) {
+ try {
+ \call_user_func(isset($connection->onWebSocketPong)?$connection->onWebSocketPong:$connection->worker->onWebSocketPong, $connection, $pong_data);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ $connection->websocketType = $tmp_connection_type;
+ if ($recv_len > $current_frame_length) {
+ return static::input(\substr($buffer, $current_frame_length), $connection);
+ }
+ }
+ return 0;
+ }
+ return $current_frame_length;
+ } else {
+ $connection->websocketCurrentFrameLength = $current_frame_length;
+ }
+ }
+
+ // Received just a frame length data.
+ if ($connection->websocketCurrentFrameLength === $recv_len) {
+ static::decode($buffer, $connection);
+ $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength);
+ $connection->websocketCurrentFrameLength = 0;
+ return 0;
+ } // The length of the received data is greater than the length of a frame.
+ elseif ($connection->websocketCurrentFrameLength < $recv_len) {
+ static::decode(\substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection);
+ $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength);
+ $current_frame_length = $connection->websocketCurrentFrameLength;
+ $connection->websocketCurrentFrameLength = 0;
+ // Continue to read next frame.
+ return static::input(\substr($buffer, $current_frame_length), $connection);
+ } // The length of the received data is less than the length of a frame.
+ else {
+ return 0;
+ }
+ }
+
+ /**
+ * Websocket encode.
+ *
+ * @param string $buffer
+ * @param ConnectionInterface $connection
+ * @return string
+ */
+ public static function encode($buffer, ConnectionInterface $connection)
+ {
+ if (!is_scalar($buffer)) {
+ throw new \Exception("You can't send(" . \gettype($buffer) . ") to client, you need to convert it to a string. ");
+ }
+ $len = \strlen($buffer);
+ if (empty($connection->websocketType)) {
+ $connection->websocketType = static::BINARY_TYPE_BLOB;
+ }
+
+ $first_byte = $connection->websocketType;
+
+ if ($len <= 125) {
+ $encode_buffer = $first_byte . \chr($len) . $buffer;
+ } else {
+ if ($len <= 65535) {
+ $encode_buffer = $first_byte . \chr(126) . \pack("n", $len) . $buffer;
+ } else {
+ $encode_buffer = $first_byte . \chr(127) . \pack("xxxxN", $len) . $buffer;
+ }
+ }
+
+ // Handshake not completed so temporary buffer websocket data waiting for send.
+ if (empty($connection->websocketHandshake)) {
+ if (empty($connection->tmpWebsocketData)) {
+ $connection->tmpWebsocketData = '';
+ }
+ // If buffer has already full then discard the current package.
+ if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) {
+ if ($connection->onError) {
+ try {
+ \call_user_func($connection->onError, $connection, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package');
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ return '';
+ }
+ $connection->tmpWebsocketData .= $encode_buffer;
+ // Check buffer is full.
+ if ($connection->maxSendBufferSize <= \strlen($connection->tmpWebsocketData)) {
+ if ($connection->onBufferFull) {
+ try {
+ \call_user_func($connection->onBufferFull, $connection);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ }
+
+ // Return empty string.
+ return '';
+ }
+
+ return $encode_buffer;
+ }
+
+ /**
+ * Websocket decode.
+ *
+ * @param string $buffer
+ * @param ConnectionInterface $connection
+ * @return string
+ */
+ public static function decode($buffer, ConnectionInterface $connection)
+ {
+ $len = \ord($buffer[1]) & 127;
+ if ($len === 126) {
+ $masks = \substr($buffer, 4, 4);
+ $data = \substr($buffer, 8);
+ } else {
+ if ($len === 127) {
+ $masks = \substr($buffer, 10, 4);
+ $data = \substr($buffer, 14);
+ } else {
+ $masks = \substr($buffer, 2, 4);
+ $data = \substr($buffer, 6);
+ }
+ }
+ $dataLength = \strlen($data);
+ $masks = \str_repeat($masks, \floor($dataLength / 4)) . \substr($masks, 0, $dataLength % 4);
+ $decoded = $data ^ $masks;
+ if ($connection->websocketCurrentFrameLength) {
+ $connection->websocketDataBuffer .= $decoded;
+ return $connection->websocketDataBuffer;
+ } else {
+ if ($connection->websocketDataBuffer !== '') {
+ $decoded = $connection->websocketDataBuffer . $decoded;
+ $connection->websocketDataBuffer = '';
+ }
+ return $decoded;
+ }
+ }
+
+ /**
+ * Websocket handshake.
+ *
+ * @param string $buffer
+ * @param TcpConnection $connection
+ * @return int
+ */
+ public static function dealHandshake($buffer, TcpConnection $connection)
+ {
+ // HTTP protocol.
+ if (0 === \strpos($buffer, 'GET')) {
+ // Find \r\n\r\n.
+ $heder_end_pos = \strpos($buffer, "\r\n\r\n");
+ if (!$heder_end_pos) {
+ return 0;
+ }
+ $header_length = $heder_end_pos + 4;
+
+ // Get Sec-WebSocket-Key.
+ $Sec_WebSocket_Key = '';
+ if (\preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) {
+ $Sec_WebSocket_Key = $match[1];
+ } else {
+ $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n",
+ true);
+ $connection->close();
+ return 0;
+ }
+ // Calculation websocket key.
+ $new_key = \base64_encode(\sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));
+ // Handshake response data.
+ $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n"
+ ."Upgrade: websocket\r\n"
+ ."Sec-WebSocket-Version: 13\r\n"
+ ."Connection: Upgrade\r\n"
+ ."Sec-WebSocket-Accept: " . $new_key . "\r\n";
+
+ // Websocket data buffer.
+ $connection->websocketDataBuffer = '';
+ // Current websocket frame length.
+ $connection->websocketCurrentFrameLength = 0;
+ // Current websocket frame data.
+ $connection->websocketCurrentFrameBuffer = '';
+ // Consume handshake data.
+ $connection->consumeRecvBuffer($header_length);
+
+ // blob or arraybuffer
+ if (empty($connection->websocketType)) {
+ $connection->websocketType = static::BINARY_TYPE_BLOB;
+ }
+
+ $has_server_header = false;
+
+ // Try to emit onWebSocketConnect callback.
+ if (isset($connection->onWebSocketConnect) || isset($connection->worker->onWebSocketConnect)) {
+ static::parseHttpHeader($buffer);
+ try {
+ \call_user_func(isset($connection->onWebSocketConnect)?$connection->onWebSocketConnect:$connection->worker->onWebSocketConnect, $connection, $buffer);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ if (!empty($_SESSION) && \class_exists('\GatewayWorker\Lib\Context')) {
+ $connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION);
+ }
+ $_GET = $_SERVER = $_SESSION = $_COOKIE = array();
+
+ if (isset($connection->headers)) {
+ if (\is_array($connection->headers)) {
+ foreach ($connection->headers as $header) {
+ if (\strpos($header, 'Server:') === 0) {
+ $has_server_header = true;
+ }
+ $handshake_message .= "$header\r\n";
+ }
+ } else {
+ $handshake_message .= "$connection->headers\r\n";
+ }
+ }
+ }
+ if (!$has_server_header) {
+ $handshake_message .= "Server: workerman/".Worker::VERSION."\r\n";
+ }
+ $handshake_message .= "\r\n";
+ // Send handshake response.
+ $connection->send($handshake_message, true);
+ // Mark handshake complete..
+ $connection->websocketHandshake = true;
+ // There are data waiting to be sent.
+ if (!empty($connection->tmpWebsocketData)) {
+ $connection->send($connection->tmpWebsocketData, true);
+ $connection->tmpWebsocketData = '';
+ }
+ if (\strlen($buffer) > $header_length) {
+ return static::input(\substr($buffer, $header_length), $connection);
+ }
+ return 0;
+ } // Is flash policy-file-request.
+ elseif (0 === \strpos($buffer, '' . "\0";
+ $connection->send($policy_xml, true);
+ $connection->consumeRecvBuffer(\strlen($buffer));
+ return 0;
+ }
+ // Bad websocket handshake request.
+ $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n",
+ true);
+ $connection->close();
+ return 0;
+ }
+
+ /**
+ * Parse http header.
+ *
+ * @param string $buffer
+ * @return void
+ */
+ protected static function parseHttpHeader($buffer)
+ {
+ // Parse headers.
+ list($http_header, ) = \explode("\r\n\r\n", $buffer, 2);
+ $header_data = \explode("\r\n", $http_header);
+
+ if ($_SERVER) {
+ $_SERVER = array();
+ }
+
+ list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = \explode(' ',
+ $header_data[0]);
+
+ unset($header_data[0]);
+ foreach ($header_data as $content) {
+ // \r\n\r\n
+ if (empty($content)) {
+ continue;
+ }
+ list($key, $value) = \explode(':', $content, 2);
+ $key = \str_replace('-', '_', \strtoupper($key));
+ $value = \trim($value);
+ $_SERVER['HTTP_' . $key] = $value;
+ switch ($key) {
+ // HTTP_HOST
+ case 'HOST':
+ $tmp = \explode(':', $value);
+ $_SERVER['SERVER_NAME'] = $tmp[0];
+ if (isset($tmp[1])) {
+ $_SERVER['SERVER_PORT'] = $tmp[1];
+ }
+ break;
+ // cookie
+ case 'COOKIE':
+ \parse_str(\str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE);
+ break;
+ }
+ }
+
+ // QUERY_STRING
+ $_SERVER['QUERY_STRING'] = \parse_url($_SERVER['REQUEST_URI'], \PHP_URL_QUERY);
+ if ($_SERVER['QUERY_STRING']) {
+ // $GET
+ \parse_str($_SERVER['QUERY_STRING'], $_GET);
+ } else {
+ $_SERVER['QUERY_STRING'] = '';
+ }
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Ws.php b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Ws.php
new file mode 100644
index 0000000..7372187
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Protocols/Ws.php
@@ -0,0 +1,472 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Protocols;
+
+use Workerman\Worker;
+use Workerman\Lib\Timer;
+use Workerman\Connection\TcpConnection;
+use Workerman\Connection\ConnectionInterface;
+
+/**
+ * Websocket protocol for client.
+ */
+class Ws
+{
+ /**
+ * Websocket blob type.
+ *
+ * @var string
+ */
+ const BINARY_TYPE_BLOB = "\x81";
+
+ /**
+ * Websocket arraybuffer type.
+ *
+ * @var string
+ */
+ const BINARY_TYPE_ARRAYBUFFER = "\x82";
+
+ /**
+ * Check the integrity of the package.
+ *
+ * @param string $buffer
+ * @param ConnectionInterface $connection
+ * @return int
+ */
+ public static function input($buffer, ConnectionInterface $connection)
+ {
+ if (empty($connection->handshakeStep)) {
+ Worker::safeEcho("recv data before handshake. Buffer:" . \bin2hex($buffer) . "\n");
+ return false;
+ }
+ // Recv handshake response
+ if ($connection->handshakeStep === 1) {
+ return self::dealHandshake($buffer, $connection);
+ }
+ $recv_len = \strlen($buffer);
+ if ($recv_len < 2) {
+ return 0;
+ }
+ // Buffer websocket frame data.
+ if ($connection->websocketCurrentFrameLength) {
+ // We need more frame data.
+ if ($connection->websocketCurrentFrameLength > $recv_len) {
+ // Return 0, because it is not clear the full packet length, waiting for the frame of fin=1.
+ return 0;
+ }
+ } else {
+
+ $firstbyte = \ord($buffer[0]);
+ $secondbyte = \ord($buffer[1]);
+ $data_len = $secondbyte & 127;
+ $is_fin_frame = $firstbyte >> 7;
+ $masked = $secondbyte >> 7;
+
+ if ($masked) {
+ Worker::safeEcho("frame masked so close the connection\n");
+ $connection->close();
+ return 0;
+ }
+
+ $opcode = $firstbyte & 0xf;
+
+ switch ($opcode) {
+ case 0x0:
+ break;
+ // Blob type.
+ case 0x1:
+ break;
+ // Arraybuffer type.
+ case 0x2:
+ break;
+ // Close package.
+ case 0x8:
+ // Try to emit onWebSocketClose callback.
+ if (isset($connection->onWebSocketClose)) {
+ try {
+ \call_user_func($connection->onWebSocketClose, $connection);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ } // Close connection.
+ else {
+ $connection->close();
+ }
+ return 0;
+ // Ping package.
+ case 0x9:
+ break;
+ // Pong package.
+ case 0xa:
+ break;
+ // Wrong opcode.
+ default :
+ Worker::safeEcho("error opcode $opcode and close websocket connection. Buffer:" . $buffer . "\n");
+ $connection->close();
+ return 0;
+ }
+ // Calculate packet length.
+ if ($data_len === 126) {
+ if (\strlen($buffer) < 4) {
+ return 0;
+ }
+ $pack = \unpack('nn/ntotal_len', $buffer);
+ $current_frame_length = $pack['total_len'] + 4;
+ } else if ($data_len === 127) {
+ if (\strlen($buffer) < 10) {
+ return 0;
+ }
+ $arr = \unpack('n/N2c', $buffer);
+ $current_frame_length = $arr['c1']*4294967296 + $arr['c2'] + 10;
+ } else {
+ $current_frame_length = $data_len + 2;
+ }
+
+ $total_package_size = \strlen($connection->websocketDataBuffer) + $current_frame_length;
+ if ($total_package_size > $connection->maxPackageSize) {
+ Worker::safeEcho("error package. package_length=$total_package_size\n");
+ $connection->close();
+ return 0;
+ }
+
+ if ($is_fin_frame) {
+ if ($opcode === 0x9) {
+ if ($recv_len >= $current_frame_length) {
+ $ping_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection);
+ $connection->consumeRecvBuffer($current_frame_length);
+ $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB;
+ $connection->websocketType = "\x8a";
+ if (isset($connection->onWebSocketPing)) {
+ try {
+ \call_user_func($connection->onWebSocketPing, $connection, $ping_data);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ } else {
+ $connection->send($ping_data);
+ }
+ $connection->websocketType = $tmp_connection_type;
+ if ($recv_len > $current_frame_length) {
+ return static::input(\substr($buffer, $current_frame_length), $connection);
+ }
+ }
+ return 0;
+
+ } else if ($opcode === 0xa) {
+ if ($recv_len >= $current_frame_length) {
+ $pong_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection);
+ $connection->consumeRecvBuffer($current_frame_length);
+ $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB;
+ $connection->websocketType = "\x8a";
+ // Try to emit onWebSocketPong callback.
+ if (isset($connection->onWebSocketPong)) {
+ try {
+ \call_user_func($connection->onWebSocketPong, $connection, $pong_data);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ $connection->websocketType = $tmp_connection_type;
+ if ($recv_len > $current_frame_length) {
+ return static::input(\substr($buffer, $current_frame_length), $connection);
+ }
+ }
+ return 0;
+ }
+ return $current_frame_length;
+ } else {
+ $connection->websocketCurrentFrameLength = $current_frame_length;
+ }
+ }
+ // Received just a frame length data.
+ if ($connection->websocketCurrentFrameLength === $recv_len) {
+ self::decode($buffer, $connection);
+ $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength);
+ $connection->websocketCurrentFrameLength = 0;
+ return 0;
+ } // The length of the received data is greater than the length of a frame.
+ elseif ($connection->websocketCurrentFrameLength < $recv_len) {
+ self::decode(\substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection);
+ $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength);
+ $current_frame_length = $connection->websocketCurrentFrameLength;
+ $connection->websocketCurrentFrameLength = 0;
+ // Continue to read next frame.
+ return self::input(\substr($buffer, $current_frame_length), $connection);
+ } // The length of the received data is less than the length of a frame.
+ else {
+ return 0;
+ }
+ }
+
+ /**
+ * Websocket encode.
+ *
+ * @param string $buffer
+ * @param ConnectionInterface $connection
+ * @return string
+ */
+ public static function encode($payload, ConnectionInterface $connection)
+ {
+ if (empty($connection->websocketType)) {
+ $connection->websocketType = self::BINARY_TYPE_BLOB;
+ }
+ $payload = (string)$payload;
+ if (empty($connection->handshakeStep)) {
+ static::sendHandshake($connection);
+ }
+ $mask = 1;
+ $mask_key = "\x00\x00\x00\x00";
+
+ $pack = '';
+ $length = $length_flag = \strlen($payload);
+ if (65535 < $length) {
+ $pack = \pack('NN', ($length & 0xFFFFFFFF00000000) >> 32, $length & 0x00000000FFFFFFFF);
+ $length_flag = 127;
+ } else if (125 < $length) {
+ $pack = \pack('n*', $length);
+ $length_flag = 126;
+ }
+
+ $head = ($mask << 7) | $length_flag;
+ $head = $connection->websocketType . \chr($head) . $pack;
+
+ $frame = $head . $mask_key;
+ // append payload to frame:
+ $mask_key = \str_repeat($mask_key, \floor($length / 4)) . \substr($mask_key, 0, $length % 4);
+ $frame .= $payload ^ $mask_key;
+ if ($connection->handshakeStep === 1) {
+ // If buffer has already full then discard the current package.
+ if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) {
+ if ($connection->onError) {
+ try {
+ \call_user_func($connection->onError, $connection, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package');
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ return '';
+ }
+ $connection->tmpWebsocketData = $connection->tmpWebsocketData . $frame;
+ // Check buffer is full.
+ if ($connection->maxSendBufferSize <= \strlen($connection->tmpWebsocketData)) {
+ if ($connection->onBufferFull) {
+ try {
+ \call_user_func($connection->onBufferFull, $connection);
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ }
+ return '';
+ }
+ return $frame;
+ }
+
+ /**
+ * Websocket decode.
+ *
+ * @param string $buffer
+ * @param ConnectionInterface $connection
+ * @return string
+ */
+ public static function decode($bytes, ConnectionInterface $connection)
+ {
+ $data_length = \ord($bytes[1]);
+
+ if ($data_length === 126) {
+ $decoded_data = \substr($bytes, 4);
+ } else if ($data_length === 127) {
+ $decoded_data = \substr($bytes, 10);
+ } else {
+ $decoded_data = \substr($bytes, 2);
+ }
+ if ($connection->websocketCurrentFrameLength) {
+ $connection->websocketDataBuffer .= $decoded_data;
+ return $connection->websocketDataBuffer;
+ } else {
+ if ($connection->websocketDataBuffer !== '') {
+ $decoded_data = $connection->websocketDataBuffer . $decoded_data;
+ $connection->websocketDataBuffer = '';
+ }
+ return $decoded_data;
+ }
+ }
+
+ /**
+ * Send websocket handshake data.
+ *
+ * @return void
+ */
+ public static function onConnect($connection)
+ {
+ static::sendHandshake($connection);
+ }
+
+ /**
+ * Clean
+ *
+ * @param $connection
+ */
+ public static function onClose($connection)
+ {
+ $connection->handshakeStep = null;
+ $connection->websocketCurrentFrameLength = 0;
+ $connection->tmpWebsocketData = '';
+ $connection->websocketDataBuffer = '';
+ if (!empty($connection->websocketPingTimer)) {
+ Timer::del($connection->websocketPingTimer);
+ $connection->websocketPingTimer = null;
+ }
+ }
+
+ /**
+ * Send websocket handshake.
+ *
+ * @param TcpConnection $connection
+ * @return void
+ */
+ public static function sendHandshake(TcpConnection $connection)
+ {
+ if (!empty($connection->handshakeStep)) {
+ return;
+ }
+ // Get Host.
+ $port = $connection->getRemotePort();
+ $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port;
+ // Handshake header.
+ $connection->websocketSecKey = \base64_encode(\md5(\mt_rand(), true));
+ $user_header = isset($connection->headers) ? $connection->headers :
+ (isset($connection->wsHttpHeader) ? $connection->wsHttpHeader : null);
+ $user_header_str = '';
+ if (!empty($user_header)) {
+ if (\is_array($user_header)){
+ foreach($user_header as $k=>$v){
+ $user_header_str .= "$k: $v\r\n";
+ }
+ } else {
+ $user_header_str .= $user_header;
+ }
+ $user_header_str = "\r\n".\trim($user_header_str);
+ }
+ $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n".
+ (!\preg_match("/\nHost:/i", $user_header_str) ? "Host: $host\r\n" : '').
+ "Connection: Upgrade\r\n".
+ "Upgrade: websocket\r\n".
+ (isset($connection->websocketOrigin) ? "Origin: ".$connection->websocketOrigin."\r\n":'').
+ (isset($connection->WSClientProtocol)?"Sec-WebSocket-Protocol: ".$connection->WSClientProtocol."\r\n":'').
+ "Sec-WebSocket-Version: 13\r\n".
+ "Sec-WebSocket-Key: " . $connection->websocketSecKey . $user_header_str . "\r\n\r\n";
+ $connection->send($header, true);
+ $connection->handshakeStep = 1;
+ $connection->websocketCurrentFrameLength = 0;
+ $connection->websocketDataBuffer = '';
+ $connection->tmpWebsocketData = '';
+ }
+
+ /**
+ * Websocket handshake.
+ *
+ * @param string $buffer
+ * @param TcpConnection $connection
+ * @return int
+ */
+ public static function dealHandshake($buffer, TcpConnection $connection)
+ {
+ $pos = \strpos($buffer, "\r\n\r\n");
+ if ($pos) {
+ //checking Sec-WebSocket-Accept
+ if (\preg_match("/Sec-WebSocket-Accept: *(.*?)\r\n/i", $buffer, $match)) {
+ if ($match[1] !== \base64_encode(\sha1($connection->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) {
+ Worker::safeEcho("Sec-WebSocket-Accept not match. Header:\n" . \substr($buffer, 0, $pos) . "\n");
+ $connection->close();
+ return 0;
+ }
+ } else {
+ Worker::safeEcho("Sec-WebSocket-Accept not found. Header:\n" . \substr($buffer, 0, $pos) . "\n");
+ $connection->close();
+ return 0;
+ }
+
+ // handshake complete
+
+ // Get WebSocket subprotocol (if specified by server)
+ if (\preg_match("/Sec-WebSocket-Protocol: *(.*?)\r\n/i", $buffer, $match)) {
+ $connection->WSServerProtocol = \trim($match[1]);
+ }
+
+ $connection->handshakeStep = 2;
+ $handshake_response_length = $pos + 4;
+ // Try to emit onWebSocketConnect callback.
+ if (isset($connection->onWebSocketConnect)) {
+ try {
+ \call_user_func($connection->onWebSocketConnect, $connection, \substr($buffer, 0, $handshake_response_length));
+ } catch (\Exception $e) {
+ Worker::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ Worker::log($e);
+ exit(250);
+ }
+ }
+ // Headbeat.
+ if (!empty($connection->websocketPingInterval)) {
+ $connection->websocketPingTimer = Timer::add($connection->websocketPingInterval, function() use ($connection){
+ if (false === $connection->send(\pack('H*', '898000000000'), true)) {
+ Timer::del($connection->websocketPingTimer);
+ $connection->websocketPingTimer = null;
+ }
+ });
+ }
+
+ $connection->consumeRecvBuffer($handshake_response_length);
+ if (!empty($connection->tmpWebsocketData)) {
+ $connection->send($connection->tmpWebsocketData, true);
+ $connection->tmpWebsocketData = '';
+ }
+ if (\strlen($buffer) > $handshake_response_length) {
+ return self::input(\substr($buffer, $handshake_response_length), $connection);
+ }
+ }
+ return 0;
+ }
+
+ public static function WSSetProtocol($connection, $params) {
+ $connection->WSClientProtocol = $params[0];
+ }
+
+ public static function WSGetServerProtocol($connection) {
+ return (\property_exists($connection, 'WSServerProtocol') ? $connection->WSServerProtocol : null);
+ }
+
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/README.md b/addons/weliam_smartcity/vendor/workerman/workerman/README.md
new file mode 100644
index 0000000..81bc7ee
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/README.md
@@ -0,0 +1,306 @@
+# Workerman
+[](https://gitter.im/walkor/Workerman?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge)
+[](https://packagist.org/packages/workerman/workerman)
+[](https://packagist.org/packages/workerman/workerman)
+[](https://packagist.org/packages/workerman/workerman)
+[](https://packagist.org/packages/workerman/workerman)
+[](https://packagist.org/packages/workerman/workerman)
+
+## What is it
+Workerman is an asynchronous event-driven PHP framework with high performance to build fast and scalable network applications.
+Workerman supports HTTP, Websocket, SSL and other custom protocols.
+Workerman supports event extension.
+
+## Requires
+PHP 5.3 or Higher
+A POSIX compatible operating system (Linux, OSX, BSD)
+POSIX and PCNTL extensions required
+Event extension recommended for better performance
+
+## Installation
+
+```
+composer require workerman/workerman
+```
+
+## Basic Usage
+
+### A websocket server
+```php
+count = 4;
+
+// Emitted when new connection come
+$ws_worker->onConnect = function ($connection) {
+ echo "New connection\n";
+};
+
+// Emitted when data received
+$ws_worker->onMessage = function ($connection, $data) {
+ // Send hello $data
+ $connection->send('Hello ' . $data);
+};
+
+// Emitted when connection closed
+$ws_worker->onClose = function ($connection) {
+ echo "Connection closed\n";
+};
+
+// Run worker
+Worker::runAll();
+```
+
+### An http server
+```php
+use Workerman\Worker;
+
+require_once __DIR__ . '/vendor/autoload.php';
+
+// #### http worker ####
+$http_worker = new Worker('http://0.0.0.0:2345');
+
+// 4 processes
+$http_worker->count = 4;
+
+// Emitted when data received
+$http_worker->onMessage = function ($connection, $request) {
+ //$request->get();
+ //$request->post();
+ //$request->header();
+ //$request->cookie();
+ //$requset->session();
+ //$request->uri();
+ //$request->path();
+ //$request->method();
+
+ // Send data to client
+ $connection->send("Hello World");
+};
+
+// Run all workers
+Worker::runAll();
+```
+
+### A tcp server
+```php
+use Workerman\Worker;
+
+require_once __DIR__ . '/vendor/autoload.php';
+
+// #### create socket and listen 1234 port ####
+$tcp_worker = new Worker('tcp://0.0.0.0:1234');
+
+// 4 processes
+$tcp_worker->count = 4;
+
+// Emitted when new connection come
+$tcp_worker->onConnect = function ($connection) {
+ echo "New Connection\n";
+};
+
+// Emitted when data received
+$tcp_worker->onMessage = function ($connection, $data) {
+ // Send data to client
+ $connection->send("Hello $data \n");
+};
+
+// Emitted when connection is closed
+$tcp_worker->onClose = function ($connection) {
+ echo "Connection closed\n";
+};
+
+Worker::runAll();
+```
+
+### Enable SSL
+```php
+ array(
+ 'local_cert' => '/your/path/of/server.pem',
+ 'local_pk' => '/your/path/of/server.key',
+ 'verify_peer' => false,
+ )
+);
+
+// Create a Websocket server with ssl context.
+$ws_worker = new Worker('websocket://0.0.0.0:2346', $context);
+
+// Enable SSL. WebSocket+SSL means that Secure WebSocket (wss://).
+// The similar approaches for Https etc.
+$ws_worker->transport = 'ssl';
+
+$ws_worker->onMessage = function ($connection, $data) {
+ // Send hello $data
+ $connection->send('Hello ' . $data);
+};
+
+Worker::runAll();
+```
+
+### Custom protocol
+Protocols/MyTextProtocol.php
+```php
+
+namespace Protocols;
+
+/**
+ * User defined protocol
+ * Format Text+"\n"
+ */
+class MyTextProtocol
+{
+ public static function input($recv_buffer)
+ {
+ // Find the position of the first occurrence of "\n"
+ $pos = strpos($recv_buffer, "\n");
+
+ // Not a complete package. Return 0 because the length of package can not be calculated
+ if ($pos === false) {
+ return 0;
+ }
+
+ // Return length of the package
+ return $pos+1;
+ }
+
+ public static function decode($recv_buffer)
+ {
+ return trim($recv_buffer);
+ }
+
+ public static function encode($data)
+ {
+ return $data . "\n";
+ }
+}
+```
+
+```php
+use Workerman\Worker;
+
+require_once __DIR__ . '/vendor/autoload.php';
+
+// #### MyTextProtocol worker ####
+$text_worker = new Worker('MyTextProtocol://0.0.0.0:5678');
+
+$text_worker->onConnect = function ($connection) {
+ echo "New connection\n";
+};
+
+$text_worker->onMessage = function ($connection, $data) {
+ // Send data to client
+ $connection->send("Hello world\n");
+};
+
+$text_worker->onClose = function ($connection) {
+ echo "Connection closed\n";
+};
+
+// Run all workers
+Worker::runAll();
+```
+
+### Timer
+```php
+
+use Workerman\Worker;
+use Workerman\Timer;
+
+require_once __DIR__ . '/vendor/autoload.php';
+
+$task = new Worker();
+$task->onWorkerStart = function ($task) {
+ // 2.5 seconds
+ $time_interval = 2.5;
+ $timer_id = Timer::add($time_interval, function () {
+ echo "Timer run\n";
+ });
+};
+
+// Run all workers
+Worker::runAll();
+```
+
+### AsyncTcpConnection (tcp/ws/text/frame etc...)
+```php
+
+use Workerman\Worker;
+use Workerman\Connection\AsyncTcpConnection;
+
+require_once __DIR__ . '/vendor/autoload.php';
+
+$worker = new Worker();
+$worker->onWorkerStart = function () {
+ // Websocket protocol for client.
+ $ws_connection = new AsyncTcpConnection('ws://echo.websocket.org:80');
+ $ws_connection->onConnect = function ($connection) {
+ $connection->send('Hello');
+ };
+ $ws_connection->onMessage = function ($connection, $data) {
+ echo "Recv: $data\n";
+ };
+ $ws_connection->onError = function ($connection, $code, $msg) {
+ echo "Error: $msg\n";
+ };
+ $ws_connection->onClose = function ($connection) {
+ echo "Connection closed\n";
+ };
+ $ws_connection->connect();
+};
+
+Worker::runAll();
+```
+
+
+
+## Available commands
+```php start.php start ```
+```php start.php start -d ```
+
+```php start.php status ```
+
+```php start.php connections```
+```php start.php stop ```
+```php start.php restart ```
+```php start.php reload ```
+
+## Documentation
+
+中文主页:[http://www.workerman.net](http://www.workerman.net)
+
+中文文档: [http://doc.workerman.net](http://doc.workerman.net)
+
+Documentation:[https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/src/SUMMARY.md)
+
+# Benchmarks
+https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l=zik073-1r
+
+
+## Other links with workerman
+
+[PHPSocket.IO](https://github.com/walkor/phpsocket.io)
+[php-socks5](https://github.com/walkor/php-socks5)
+[php-http-proxy](https://github.com/walkor/php-http-proxy)
+
+## Donate
+
+
+## LICENSE
+
+Workerman is released under the [MIT license](https://github.com/walkor/workerman/blob/master/MIT-LICENSE.txt).
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Timer.php b/addons/weliam_smartcity/vendor/workerman/workerman/Timer.php
new file mode 100644
index 0000000..348bb3a
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Timer.php
@@ -0,0 +1,213 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman;
+
+use Workerman\Events\EventInterface;
+use Workerman\Worker;
+use \Exception;
+
+/**
+ * Timer.
+ *
+ * example:
+ * Workerman\Timer::add($time_interval, callback, array($arg1, $arg2..));
+ */
+class Timer
+{
+ /**
+ * Tasks that based on ALARM signal.
+ * [
+ * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]],
+ * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]],
+ * ..
+ * ]
+ *
+ * @var array
+ */
+ protected static $_tasks = array();
+
+ /**
+ * event
+ *
+ * @var EventInterface
+ */
+ protected static $_event = null;
+
+ /**
+ * timer id
+ *
+ * @var int
+ */
+ protected static $_timerId = 0;
+
+ /**
+ * timer status
+ * [
+ * timer_id1 => bool,
+ * timer_id2 => bool,
+ * ....................,
+ * ]
+ *
+ * @var array
+ */
+ protected static $_status = array();
+
+ /**
+ * Init.
+ *
+ * @param EventInterface $event
+ * @return void
+ */
+ public static function init($event = null)
+ {
+ if ($event) {
+ self::$_event = $event;
+ return;
+ }
+ if (\function_exists('pcntl_signal')) {
+ \pcntl_signal(\SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false);
+ }
+ }
+
+ /**
+ * ALARM signal handler.
+ *
+ * @return void
+ */
+ public static function signalHandle()
+ {
+ if (!self::$_event) {
+ \pcntl_alarm(1);
+ self::tick();
+ }
+ }
+
+ /**
+ * Add a timer.
+ *
+ * @param float $time_interval
+ * @param callable $func
+ * @param mixed $args
+ * @param bool $persistent
+ * @return int|bool
+ */
+ public static function add($time_interval, $func, $args = array(), $persistent = true)
+ {
+ if ($time_interval <= 0) {
+ Worker::safeEcho(new Exception("bad time_interval"));
+ return false;
+ }
+
+ if ($args === null) {
+ $args = array();
+ }
+
+ if (self::$_event) {
+ return self::$_event->add($time_interval,
+ $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args);
+ }
+
+ if (!\is_callable($func)) {
+ Worker::safeEcho(new Exception("not callable"));
+ return false;
+ }
+
+ if (empty(self::$_tasks)) {
+ \pcntl_alarm(1);
+ }
+
+ $run_time = \time() + $time_interval;
+ if (!isset(self::$_tasks[$run_time])) {
+ self::$_tasks[$run_time] = array();
+ }
+
+ self::$_timerId = self::$_timerId == \PHP_INT_MAX ? 1 : ++self::$_timerId;
+ self::$_status[self::$_timerId] = true;
+ self::$_tasks[$run_time][self::$_timerId] = array($func, (array)$args, $persistent, $time_interval);
+
+ return self::$_timerId;
+ }
+
+
+ /**
+ * Tick.
+ *
+ * @return void
+ */
+ public static function tick()
+ {
+ if (empty(self::$_tasks)) {
+ \pcntl_alarm(0);
+ return;
+ }
+ $time_now = \time();
+ foreach (self::$_tasks as $run_time => $task_data) {
+ if ($time_now >= $run_time) {
+ foreach ($task_data as $index => $one_task) {
+ $task_func = $one_task[0];
+ $task_args = $one_task[1];
+ $persistent = $one_task[2];
+ $time_interval = $one_task[3];
+ try {
+ \call_user_func_array($task_func, $task_args);
+ } catch (\Exception $e) {
+ Worker::safeEcho($e);
+ }
+ if($persistent && !empty(self::$_status[$index])) {
+ $new_run_time = \time() + $time_interval;
+ if(!isset(self::$_tasks[$new_run_time])) self::$_tasks[$new_run_time] = array();
+ self::$_tasks[$new_run_time][$index] = array($task_func, (array)$task_args, $persistent, $time_interval);
+ }
+ }
+ unset(self::$_tasks[$run_time]);
+ }
+ }
+ }
+
+ /**
+ * Remove a timer.
+ *
+ * @param mixed $timer_id
+ * @return bool
+ */
+ public static function del($timer_id)
+ {
+ if (self::$_event) {
+ return self::$_event->del($timer_id, EventInterface::EV_TIMER);
+ }
+
+ foreach(self::$_tasks as $run_time => $task_data)
+ {
+ if(array_key_exists($timer_id, $task_data)) unset(self::$_tasks[$run_time][$timer_id]);
+ }
+
+ if(array_key_exists($timer_id, self::$_status)) unset(self::$_status[$timer_id]);
+
+ return true;
+ }
+
+ /**
+ * Remove all timers.
+ *
+ * @return void
+ */
+ public static function delAll()
+ {
+ self::$_tasks = self::$_status = array();
+ \pcntl_alarm(0);
+ if (self::$_event) {
+ self::$_event->clearAllTimer();
+ }
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/Worker.php b/addons/weliam_smartcity/vendor/workerman/workerman/Worker.php
new file mode 100644
index 0000000..1109e30
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/Worker.php
@@ -0,0 +1,2563 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman;
+require_once __DIR__ . '/Lib/Constants.php';
+
+use Workerman\Events\EventInterface;
+use Workerman\Connection\ConnectionInterface;
+use Workerman\Connection\TcpConnection;
+use Workerman\Connection\UdpConnection;
+use Workerman\Lib\Timer;
+use Workerman\Events\Select;
+use \Exception;
+
+/**
+ * Worker class
+ * A container for listening ports
+ */
+class Worker
+{
+ /**
+ * Version.
+ *
+ * @var string
+ */
+ const VERSION = '4.0.18';
+
+ /**
+ * Status starting.
+ *
+ * @var int
+ */
+ const STATUS_STARTING = 1;
+
+ /**
+ * Status running.
+ *
+ * @var int
+ */
+ const STATUS_RUNNING = 2;
+
+ /**
+ * Status shutdown.
+ *
+ * @var int
+ */
+ const STATUS_SHUTDOWN = 4;
+
+ /**
+ * Status reloading.
+ *
+ * @var int
+ */
+ const STATUS_RELOADING = 8;
+
+ /**
+ * After sending the restart command to the child process KILL_WORKER_TIMER_TIME seconds,
+ * if the process is still living then forced to kill.
+ *
+ * @var int
+ */
+ const KILL_WORKER_TIMER_TIME = 2;
+
+ /**
+ * Default backlog. Backlog is the maximum length of the queue of pending connections.
+ *
+ * @var int
+ */
+ const DEFAULT_BACKLOG = 102400;
+ /**
+ * Max udp package size.
+ *
+ * @var int
+ */
+ const MAX_UDP_PACKAGE_SIZE = 65535;
+
+ /**
+ * The safe distance for columns adjacent
+ *
+ * @var int
+ */
+ const UI_SAFE_LENGTH = 4;
+
+ /**
+ * Worker id.
+ *
+ * @var int
+ */
+ public $id = 0;
+
+ /**
+ * Name of the worker processes.
+ *
+ * @var string
+ */
+ public $name = 'none';
+
+ /**
+ * Number of worker processes.
+ *
+ * @var int
+ */
+ public $count = 1;
+
+ /**
+ * Unix user of processes, needs appropriate privileges (usually root).
+ *
+ * @var string
+ */
+ public $user = '';
+
+ /**
+ * Unix group of processes, needs appropriate privileges (usually root).
+ *
+ * @var string
+ */
+ public $group = '';
+
+ /**
+ * reloadable.
+ *
+ * @var bool
+ */
+ public $reloadable = true;
+
+ /**
+ * reuse port.
+ *
+ * @var bool
+ */
+ public $reusePort = false;
+
+ /**
+ * Emitted when worker processes start.
+ *
+ * @var callable
+ */
+ public $onWorkerStart = null;
+
+ /**
+ * Emitted when a socket connection is successfully established.
+ *
+ * @var callable
+ */
+ public $onConnect = null;
+
+ /**
+ * Emitted when data is received.
+ *
+ * @var callable
+ */
+ public $onMessage = null;
+
+ /**
+ * Emitted when the other end of the socket sends a FIN packet.
+ *
+ * @var callable
+ */
+ public $onClose = null;
+
+ /**
+ * Emitted when an error occurs with connection.
+ *
+ * @var callable
+ */
+ public $onError = null;
+
+ /**
+ * Emitted when the send buffer becomes full.
+ *
+ * @var callable
+ */
+ public $onBufferFull = null;
+
+ /**
+ * Emitted when the send buffer becomes empty.
+ *
+ * @var callable
+ */
+ public $onBufferDrain = null;
+
+ /**
+ * Emitted when worker processes stoped.
+ *
+ * @var callable
+ */
+ public $onWorkerStop = null;
+
+ /**
+ * Emitted when worker processes get reload signal.
+ *
+ * @var callable
+ */
+ public $onWorkerReload = null;
+
+ /**
+ * Transport layer protocol.
+ *
+ * @var string
+ */
+ public $transport = 'tcp';
+
+ /**
+ * Store all connections of clients.
+ *
+ * @var array
+ */
+ public $connections = array();
+
+ /**
+ * Application layer protocol.
+ *
+ * @var string
+ */
+ public $protocol = null;
+
+ /**
+ * Root path for autoload.
+ *
+ * @var string
+ */
+ protected $_autoloadRootPath = '';
+
+ /**
+ * Pause accept new connections or not.
+ *
+ * @var bool
+ */
+ protected $_pauseAccept = true;
+
+ /**
+ * Is worker stopping ?
+ * @var bool
+ */
+ public $stopping = false;
+
+ /**
+ * Daemonize.
+ *
+ * @var bool
+ */
+ public static $daemonize = false;
+
+ /**
+ * Stdout file.
+ *
+ * @var string
+ */
+ public static $stdoutFile = '/dev/null';
+
+ /**
+ * The file to store master process PID.
+ *
+ * @var string
+ */
+ public static $pidFile = '';
+
+ /**
+ * Log file.
+ *
+ * @var mixed
+ */
+ public static $logFile = '';
+
+ /**
+ * Global event loop.
+ *
+ * @var EventInterface
+ */
+ public static $globalEvent = null;
+
+ /**
+ * Emitted when the master process get reload signal.
+ *
+ * @var callable
+ */
+ public static $onMasterReload = null;
+
+ /**
+ * Emitted when the master process terminated.
+ *
+ * @var callable
+ */
+ public static $onMasterStop = null;
+
+ /**
+ * EventLoopClass
+ *
+ * @var string
+ */
+ public static $eventLoopClass = '';
+
+ /**
+ * Process title
+ *
+ * @var string
+ */
+ public static $processTitle = 'WorkerMan';
+
+ /**
+ * The PID of master process.
+ *
+ * @var int
+ */
+ protected static $_masterPid = 0;
+
+ /**
+ * Listening socket.
+ *
+ * @var resource
+ */
+ protected $_mainSocket = null;
+
+ /**
+ * Socket name. The format is like this http://0.0.0.0:80 .
+ *
+ * @var string
+ */
+ protected $_socketName = '';
+
+ /** parse from _socketName avoid parse again in master or worker
+ * LocalSocket The format is like tcp://0.0.0.0:8080
+ * @var string
+ */
+
+ protected $_localSocket=null;
+
+ /**
+ * Context of socket.
+ *
+ * @var resource
+ */
+ protected $_context = null;
+
+ /**
+ * All worker instances.
+ *
+ * @var Worker[]
+ */
+ protected static $_workers = array();
+
+ /**
+ * All worker processes pid.
+ * The format is like this [worker_id=>[pid=>pid, pid=>pid, ..], ..]
+ *
+ * @var array
+ */
+ protected static $_pidMap = array();
+
+ /**
+ * All worker processes waiting for restart.
+ * The format is like this [pid=>pid, pid=>pid].
+ *
+ * @var array
+ */
+ protected static $_pidsToRestart = array();
+
+ /**
+ * Mapping from PID to worker process ID.
+ * The format is like this [worker_id=>[0=>$pid, 1=>$pid, ..], ..].
+ *
+ * @var array
+ */
+ protected static $_idMap = array();
+
+ /**
+ * Current status.
+ *
+ * @var int
+ */
+ protected static $_status = self::STATUS_STARTING;
+
+ /**
+ * Maximum length of the worker names.
+ *
+ * @var int
+ */
+ protected static $_maxWorkerNameLength = 12;
+
+ /**
+ * Maximum length of the socket names.
+ *
+ * @var int
+ */
+ protected static $_maxSocketNameLength = 12;
+
+ /**
+ * Maximum length of the process user names.
+ *
+ * @var int
+ */
+ protected static $_maxUserNameLength = 12;
+
+ /**
+ * Maximum length of the Proto names.
+ *
+ * @var int
+ */
+ protected static $_maxProtoNameLength = 4;
+
+ /**
+ * Maximum length of the Processes names.
+ *
+ * @var int
+ */
+ protected static $_maxProcessesNameLength = 9;
+
+ /**
+ * Maximum length of the Status names.
+ *
+ * @var int
+ */
+ protected static $_maxStatusNameLength = 1;
+
+ /**
+ * The file to store status info of current worker process.
+ *
+ * @var string
+ */
+ protected static $_statisticsFile = '';
+
+ /**
+ * Start file.
+ *
+ * @var string
+ */
+ protected static $_startFile = '';
+
+ /**
+ * OS.
+ *
+ * @var string
+ */
+ protected static $_OS = \OS_TYPE_LINUX;
+
+ /**
+ * Processes for windows.
+ *
+ * @var array
+ */
+ protected static $_processForWindows = array();
+
+ /**
+ * Status info of current worker process.
+ *
+ * @var array
+ */
+ protected static $_globalStatistics = array(
+ 'start_timestamp' => 0,
+ 'worker_exit_info' => array()
+ );
+
+ /**
+ * Available event loops.
+ *
+ * @var array
+ */
+ protected static $_availableEventLoops = array(
+ 'event' => '\Workerman\Events\Event',
+ 'libevent' => '\Workerman\Events\Libevent'
+ );
+
+ /**
+ * PHP built-in protocols.
+ *
+ * @var array
+ */
+ protected static $_builtinTransports = array(
+ 'tcp' => 'tcp',
+ 'udp' => 'udp',
+ 'unix' => 'unix',
+ 'ssl' => 'tcp'
+ );
+
+ /**
+ * PHP built-in error types.
+ *
+ * @var array
+ */
+ protected static $_errorType = array(
+ \E_ERROR => 'E_ERROR', // 1
+ \E_WARNING => 'E_WARNING', // 2
+ \E_PARSE => 'E_PARSE', // 4
+ \E_NOTICE => 'E_NOTICE', // 8
+ \E_CORE_ERROR => 'E_CORE_ERROR', // 16
+ \E_CORE_WARNING => 'E_CORE_WARNING', // 32
+ \E_COMPILE_ERROR => 'E_COMPILE_ERROR', // 64
+ \E_COMPILE_WARNING => 'E_COMPILE_WARNING', // 128
+ \E_USER_ERROR => 'E_USER_ERROR', // 256
+ \E_USER_WARNING => 'E_USER_WARNING', // 512
+ \E_USER_NOTICE => 'E_USER_NOTICE', // 1024
+ \E_STRICT => 'E_STRICT', // 2048
+ \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', // 4096
+ \E_DEPRECATED => 'E_DEPRECATED', // 8192
+ \E_USER_DEPRECATED => 'E_USER_DEPRECATED' // 16384
+ );
+
+ /**
+ * Graceful stop or not.
+ *
+ * @var bool
+ */
+ protected static $_gracefulStop = false;
+
+ /**
+ * Standard output stream
+ * @var resource
+ */
+ protected static $_outputStream = null;
+
+ /**
+ * If $outputStream support decorated
+ * @var bool
+ */
+ protected static $_outputDecorated = null;
+
+ /**
+ * Run all worker instances.
+ *
+ * @return void
+ */
+ public static function runAll()
+ {
+ static::checkSapiEnv();
+ static::init();
+ static::parseCommand();
+ static::daemonize();
+ static::initWorkers();
+ static::installSignal();
+ static::saveMasterPid();
+ static::displayUI();
+ static::forkWorkers();
+ static::resetStd();
+ static::monitorWorkers();
+ }
+
+ /**
+ * Check sapi.
+ *
+ * @return void
+ */
+ protected static function checkSapiEnv()
+ {
+ // Only for cli.
+ if (\PHP_SAPI !== 'cli') {
+ exit("Only run in command line mode \n");
+ }
+ if (\DIRECTORY_SEPARATOR === '\\') {
+ self::$_OS = \OS_TYPE_WINDOWS;
+ }
+ }
+
+ /**
+ * Init.
+ *
+ * @return void
+ */
+ protected static function init()
+ {
+ \set_error_handler(function($code, $msg, $file, $line){
+ Worker::safeEcho("$msg in file $file on line $line\n");
+ });
+
+ // Start file.
+ $backtrace = \debug_backtrace();
+ static::$_startFile = $backtrace[\count($backtrace) - 1]['file'];
+
+
+ $unique_prefix = \str_replace('/', '_', static::$_startFile);
+
+ // Pid file.
+ if (empty(static::$pidFile)) {
+ static::$pidFile = __DIR__ . "/../$unique_prefix.pid";
+ }
+
+ // Log file.
+ if (empty(static::$logFile)) {
+ static::$logFile = __DIR__ . '/../workerman.log';
+ }
+ $log_file = (string)static::$logFile;
+ if (!\is_file($log_file)) {
+ \touch($log_file);
+ \chmod($log_file, 0622);
+ }
+
+ // State.
+ static::$_status = static::STATUS_STARTING;
+
+ // For statistics.
+ static::$_globalStatistics['start_timestamp'] = \time();
+ static::$_statisticsFile = \sys_get_temp_dir() . "/$unique_prefix.status";
+
+ // Process title.
+ static::setProcessTitle(static::$processTitle . ': master process start_file=' . static::$_startFile);
+
+ // Init data for worker id.
+ static::initId();
+
+ // Timer init.
+ Timer::init();
+ }
+
+ /**
+ * Lock.
+ *
+ * @return void
+ */
+ protected static function lock()
+ {
+ $fd = \fopen(static::$_startFile, 'r');
+ if ($fd && !flock($fd, LOCK_EX)) {
+ static::log('Workerman['.static::$_startFile.'] already running.');
+ exit;
+ }
+ }
+
+ /**
+ * Unlock.
+ *
+ * @return void
+ */
+ protected static function unlock()
+ {
+ $fd = \fopen(static::$_startFile, 'r');
+ $fd && flock($fd, \LOCK_UN);
+ }
+
+ /**
+ * Init All worker instances.
+ *
+ * @return void
+ */
+ protected static function initWorkers()
+ {
+ if (static::$_OS !== \OS_TYPE_LINUX) {
+ return;
+ }
+ foreach (static::$_workers as $worker) {
+ // Worker name.
+ if (empty($worker->name)) {
+ $worker->name = 'none';
+ }
+
+ // Get unix user of the worker process.
+ if (empty($worker->user)) {
+ $worker->user = static::getCurrentUser();
+ } else {
+ if (\posix_getuid() !== 0 && $worker->user !== static::getCurrentUser()) {
+ static::log('Warning: You must have the root privileges to change uid and gid.');
+ }
+ }
+
+ // Socket name.
+ $worker->socket = $worker->getSocketName();
+
+ // Status name.
+ $worker->status = ' [OK] ';
+
+ // Get column mapping for UI
+ foreach(static::getUiColumns() as $column_name => $prop){
+ !isset($worker->{$prop}) && $worker->{$prop} = 'NNNN';
+ $prop_length = \strlen($worker->{$prop});
+ $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength';
+ static::$$key = \max(static::$$key, $prop_length);
+ }
+
+ // Listen.
+ if (!$worker->reusePort) {
+ $worker->listen();
+ }
+ }
+ }
+
+ /**
+ * Reload all worker instances.
+ *
+ * @return void
+ */
+ public static function reloadAllWorkers()
+ {
+ static::init();
+ static::initWorkers();
+ static::displayUI();
+ static::$_status = static::STATUS_RELOADING;
+ }
+
+ /**
+ * Get all worker instances.
+ *
+ * @return array
+ */
+ public static function getAllWorkers()
+ {
+ return static::$_workers;
+ }
+
+ /**
+ * Get global event-loop instance.
+ *
+ * @return EventInterface
+ */
+ public static function getEventLoop()
+ {
+ return static::$globalEvent;
+ }
+
+ /**
+ * Get main socket resource
+ * @return resource
+ */
+ public function getMainSocket(){
+ return $this->_mainSocket;
+ }
+
+ /**
+ * Init idMap.
+ * return void
+ */
+ protected static function initId()
+ {
+ foreach (static::$_workers as $worker_id => $worker) {
+ $new_id_map = array();
+ $worker->count = $worker->count < 1 ? 1 : $worker->count;
+ for($key = 0; $key < $worker->count; $key++) {
+ $new_id_map[$key] = isset(static::$_idMap[$worker_id][$key]) ? static::$_idMap[$worker_id][$key] : 0;
+ }
+ static::$_idMap[$worker_id] = $new_id_map;
+ }
+ }
+
+ /**
+ * Get unix user of current porcess.
+ *
+ * @return string
+ */
+ protected static function getCurrentUser()
+ {
+ $user_info = \posix_getpwuid(\posix_getuid());
+ return $user_info['name'];
+ }
+
+ /**
+ * Display staring UI.
+ *
+ * @return void
+ */
+ protected static function displayUI()
+ {
+ global $argv;
+ if (\in_array('-q', $argv)) {
+ return;
+ }
+ if (static::$_OS !== \OS_TYPE_LINUX) {
+ static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n");
+ static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. \PHP_VERSION. "\r\n");
+ static::safeEcho("------------------------ WORKERS -------------------------------\r\n");
+ static::safeEcho("worker listen processes status\r\n");
+ return;
+ }
+
+ //show version
+ $line_version = 'Workerman version:' . static::VERSION . \str_pad('PHP version:', 22, ' ', \STR_PAD_LEFT) . \PHP_VERSION . \PHP_EOL;
+ !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', \strlen($line_version));
+ $total_length = static::getSingleLineTotalLength();
+ $line_one = '' . \str_pad(' WORKERMAN ', $total_length + \strlen(''), '-', \STR_PAD_BOTH) . ''. \PHP_EOL;
+ $line_two = \str_pad(' WORKERS ' , $total_length + \strlen(''), '-', \STR_PAD_BOTH) . \PHP_EOL;
+ static::safeEcho($line_one . $line_version . $line_two);
+
+ //Show title
+ $title = '';
+ foreach(static::getUiColumns() as $column_name => $prop){
+ $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength';
+ //just keep compatible with listen name
+ $column_name === 'socket' && $column_name = 'listen';
+ $title.= "{$column_name}" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($column_name));
+ }
+ $title && static::safeEcho($title . \PHP_EOL);
+
+ //Show content
+ foreach (static::$_workers as $worker) {
+ $content = '';
+ foreach(static::getUiColumns() as $column_name => $prop){
+ $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength';
+ \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches);
+ $place_holder_length = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0;
+ $content .= \str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length);
+ }
+ $content && static::safeEcho($content . \PHP_EOL);
+ }
+
+ //Show last line
+ $line_last = \str_pad('', static::getSingleLineTotalLength(), '-') . \PHP_EOL;
+ !empty($content) && static::safeEcho($line_last);
+
+ if (static::$daemonize) {
+ foreach ($argv as $index => $value) {
+ if ($value == '-d') {
+ unset($argv[$index]);
+ } elseif ($value == 'start' || $value == 'restart') {
+ $argv[$index] = 'stop';
+ }
+ }
+ static::safeEcho("Input \"php ".implode(' ', $argv)."\" to stop. Start success.\n\n");
+ } else {
+ static::safeEcho("Press Ctrl+C to stop. Start success.\n");
+ }
+ }
+
+ /**
+ * Get UI columns to be shown in terminal
+ *
+ * 1. $column_map: array('ui_column_name' => 'clas_property_name')
+ * 2. Consider move into configuration in future
+ *
+ * @return array
+ */
+ public static function getUiColumns()
+ {
+ return array(
+ 'proto' => 'transport',
+ 'user' => 'user',
+ 'worker' => 'name',
+ 'socket' => 'socket',
+ 'processes' => 'count',
+ 'status' => 'status',
+ );
+ }
+
+ /**
+ * Get single line total length for ui
+ *
+ * @return int
+ */
+ public static function getSingleLineTotalLength()
+ {
+ $total_length = 0;
+
+ foreach(static::getUiColumns() as $column_name => $prop){
+ $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength';
+ $total_length += static::$$key + static::UI_SAFE_LENGTH;
+ }
+
+ //keep beauty when show less colums
+ !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', 0);
+ $total_length <= LINE_VERSIOIN_LENGTH && $total_length = LINE_VERSIOIN_LENGTH;
+
+ return $total_length;
+ }
+
+ /**
+ * Parse command.
+ *
+ * @return void
+ */
+ protected static function parseCommand()
+ {
+ if (static::$_OS !== \OS_TYPE_LINUX) {
+ return;
+ }
+ global $argv;
+ // Check argv;
+ $start_file = $argv[0];
+ $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n";
+ $available_commands = array(
+ 'start',
+ 'stop',
+ 'restart',
+ 'reload',
+ 'status',
+ 'connections',
+ );
+ $available_mode = array(
+ '-d',
+ '-g'
+ );
+ $command = $mode = '';
+ foreach ($argv as $value) {
+ if (\in_array($value, $available_commands)) {
+ $command = $value;
+ } elseif (\in_array($value, $available_mode)) {
+ $mode = $value;
+ }
+ }
+
+ if (!$command) {
+ exit($usage);
+ }
+
+ // Start command.
+ $mode_str = '';
+ if ($command === 'start') {
+ if ($mode === '-d' || static::$daemonize) {
+ $mode_str = 'in DAEMON mode';
+ } else {
+ $mode_str = 'in DEBUG mode';
+ }
+ }
+ static::log("Workerman[$start_file] $command $mode_str");
+
+ // Get master process PID.
+ $master_pid = \is_file(static::$pidFile) ? \file_get_contents(static::$pidFile) : 0;
+ $master_is_alive = $master_pid && \posix_kill($master_pid, 0) && \posix_getpid() !== $master_pid;
+ // Master is still alive?
+ if ($master_is_alive) {
+ if ($command === 'start') {
+ static::log("Workerman[$start_file] already running");
+ exit;
+ }
+ } elseif ($command !== 'start' && $command !== 'restart') {
+ static::log("Workerman[$start_file] not run");
+ exit;
+ }
+
+ // execute command.
+ switch ($command) {
+ case 'start':
+ if ($mode === '-d') {
+ static::$daemonize = true;
+ }
+ break;
+ case 'status':
+ while (1) {
+ if (\is_file(static::$_statisticsFile)) {
+ @\unlink(static::$_statisticsFile);
+ }
+ // Master process will send SIGUSR2 signal to all child processes.
+ \posix_kill($master_pid, SIGUSR2);
+ // Sleep 1 second.
+ \sleep(1);
+ // Clear terminal.
+ if ($mode === '-d') {
+ static::safeEcho("\33[H\33[2J\33(B\33[m", true);
+ }
+ // Echo status data.
+ static::safeEcho(static::formatStatusData());
+ if ($mode !== '-d') {
+ exit(0);
+ }
+ static::safeEcho("\nPress Ctrl+C to quit.\n\n");
+ }
+ exit(0);
+ case 'connections':
+ if (\is_file(static::$_statisticsFile) && \is_writable(static::$_statisticsFile)) {
+ \unlink(static::$_statisticsFile);
+ }
+ // Master process will send SIGIO signal to all child processes.
+ \posix_kill($master_pid, SIGIO);
+ // Waiting amoment.
+ \usleep(500000);
+ // Display statisitcs data from a disk file.
+ if(\is_readable(static::$_statisticsFile)) {
+ \readfile(static::$_statisticsFile);
+ }
+ exit(0);
+ case 'restart':
+ case 'stop':
+ if ($mode === '-g') {
+ static::$_gracefulStop = true;
+ $sig = \SIGHUP;
+ static::log("Workerman[$start_file] is gracefully stopping ...");
+ } else {
+ static::$_gracefulStop = false;
+ $sig = \SIGINT;
+ static::log("Workerman[$start_file] is stopping ...");
+ }
+ // Send stop signal to master process.
+ $master_pid && \posix_kill($master_pid, $sig);
+ // Timeout.
+ $timeout = 5;
+ $start_time = \time();
+ // Check master process is still alive?
+ while (1) {
+ $master_is_alive = $master_pid && \posix_kill($master_pid, 0);
+ if ($master_is_alive) {
+ // Timeout?
+ if (!static::$_gracefulStop && \time() - $start_time >= $timeout) {
+ static::log("Workerman[$start_file] stop fail");
+ exit;
+ }
+ // Waiting amoment.
+ \usleep(10000);
+ continue;
+ }
+ // Stop success.
+ static::log("Workerman[$start_file] stop success");
+ if ($command === 'stop') {
+ exit(0);
+ }
+ if ($mode === '-d') {
+ static::$daemonize = true;
+ }
+ break;
+ }
+ break;
+ case 'reload':
+ if($mode === '-g'){
+ $sig = \SIGQUIT;
+ }else{
+ $sig = \SIGUSR1;
+ }
+ \posix_kill($master_pid, $sig);
+ exit;
+ default :
+ if (isset($command)) {
+ static::safeEcho('Unknown command: ' . $command . "\n");
+ }
+ exit($usage);
+ }
+ }
+
+ /**
+ * Format status data.
+ *
+ * @return string
+ */
+ protected static function formatStatusData()
+ {
+ static $total_request_cache = array();
+ if (!\is_readable(static::$_statisticsFile)) {
+ return '';
+ }
+ $info = \file(static::$_statisticsFile, \FILE_IGNORE_NEW_LINES);
+ if (!$info) {
+ return '';
+ }
+ $status_str = '';
+ $current_total_request = array();
+ $worker_info = \unserialize($info[0]);
+ \ksort($worker_info, SORT_NUMERIC);
+ unset($info[0]);
+ $data_waiting_sort = array();
+ $read_process_status = false;
+ $total_requests = 0;
+ $total_qps = 0;
+ $total_connections = 0;
+ $total_fails = 0;
+ $total_memory = 0;
+ $total_timers = 0;
+ $maxLen1 = static::$_maxSocketNameLength;
+ $maxLen2 = static::$_maxWorkerNameLength;
+ foreach($info as $key => $value) {
+ if (!$read_process_status) {
+ $status_str .= $value . "\n";
+ if (\preg_match('/^pid.*?memory.*?listening/', $value)) {
+ $read_process_status = true;
+ }
+ continue;
+ }
+ if(\preg_match('/^[0-9]+/', $value, $pid_math)) {
+ $pid = $pid_math[0];
+ $data_waiting_sort[$pid] = $value;
+ if(\preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) {
+ $total_memory += \intval(\str_ireplace('M','',$match[1]));
+ $maxLen1 = \max($maxLen1,\strlen($match[2]));
+ $maxLen2 = \max($maxLen2,\strlen($match[3]));
+ $total_connections += \intval($match[4]);
+ $total_fails += \intval($match[5]);
+ $total_timers += \intval($match[6]);
+ $current_total_request[$pid] = $match[7];
+ $total_requests += \intval($match[7]);
+ }
+ }
+ }
+ foreach($worker_info as $pid => $info) {
+ if (!isset($data_waiting_sort[$pid])) {
+ $status_str .= "$pid\t" . \str_pad('N/A', 7) . " "
+ . \str_pad($info['listen'], static::$_maxSocketNameLength) . " "
+ . \str_pad($info['name'], static::$_maxWorkerNameLength) . " "
+ . \str_pad('N/A', 11) . " " . \str_pad('N/A', 9) . " "
+ . \str_pad('N/A', 7) . " " . \str_pad('N/A', 13) . " N/A [busy] \n";
+ continue;
+ }
+ //$qps = isset($total_request_cache[$pid]) ? $current_total_request[$pid]
+ if (!isset($total_request_cache[$pid]) || !isset($current_total_request[$pid])) {
+ $qps = 0;
+ } else {
+ $qps = $current_total_request[$pid] - $total_request_cache[$pid];
+ $total_qps += $qps;
+ }
+ $status_str .= $data_waiting_sort[$pid]. " " . \str_pad($qps, 6) ." [idle]\n";
+ }
+ $total_request_cache = $current_total_request;
+ $status_str .= "----------------------------------------------PROCESS STATUS---------------------------------------------------\n";
+ $status_str .= "Summary\t" . \str_pad($total_memory.'M', 7) . " "
+ . \str_pad('-', $maxLen1) . " "
+ . \str_pad('-', $maxLen2) . " "
+ . \str_pad($total_connections, 11) . " " . \str_pad($total_fails, 9) . " "
+ . \str_pad($total_timers, 7) . " " . \str_pad($total_requests, 13) . " "
+ . \str_pad($total_qps,6)." [Summary] \n";
+ return $status_str;
+ }
+
+
+ /**
+ * Install signal handler.
+ *
+ * @return void
+ */
+ protected static function installSignal()
+ {
+ if (static::$_OS !== \OS_TYPE_LINUX) {
+ return;
+ }
+ $signalHandler = '\Workerman\Worker::signalHandler';
+ // stop
+ \pcntl_signal(\SIGINT, $signalHandler, false);
+ // stop
+ \pcntl_signal(\SIGTERM, $signalHandler, false);
+ // graceful stop
+ \pcntl_signal(\SIGHUP, $signalHandler, false);
+ // reload
+ \pcntl_signal(\SIGUSR1, $signalHandler, false);
+ // graceful reload
+ \pcntl_signal(\SIGQUIT, $signalHandler, false);
+ // status
+ \pcntl_signal(\SIGUSR2, $signalHandler, false);
+ // connection status
+ \pcntl_signal(\SIGIO, $signalHandler, false);
+ // ignore
+ \pcntl_signal(\SIGPIPE, \SIG_IGN, false);
+ }
+
+ /**
+ * Reinstall signal handler.
+ *
+ * @return void
+ */
+ protected static function reinstallSignal()
+ {
+ if (static::$_OS !== \OS_TYPE_LINUX) {
+ return;
+ }
+ $signalHandler = '\Workerman\Worker::signalHandler';
+ // uninstall stop signal handler
+ \pcntl_signal(\SIGINT, \SIG_IGN, false);
+ // uninstall stop signal handler
+ \pcntl_signal(\SIGTERM, \SIG_IGN, false);
+ // uninstall graceful stop signal handler
+ \pcntl_signal(\SIGHUP, \SIG_IGN, false);
+ // uninstall reload signal handler
+ \pcntl_signal(\SIGUSR1, \SIG_IGN, false);
+ // uninstall graceful reload signal handler
+ \pcntl_signal(\SIGQUIT, \SIG_IGN, false);
+ // uninstall status signal handler
+ \pcntl_signal(\SIGUSR2, \SIG_IGN, false);
+ // uninstall connections status signal handler
+ \pcntl_signal(\SIGIO, \SIG_IGN, false);
+ // reinstall stop signal handler
+ static::$globalEvent->add(\SIGINT, EventInterface::EV_SIGNAL, $signalHandler);
+ // reinstall graceful stop signal handler
+ static::$globalEvent->add(\SIGHUP, EventInterface::EV_SIGNAL, $signalHandler);
+ // reinstall reload signal handler
+ static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, $signalHandler);
+ // reinstall graceful reload signal handler
+ static::$globalEvent->add(\SIGQUIT, EventInterface::EV_SIGNAL, $signalHandler);
+ // reinstall status signal handler
+ static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, $signalHandler);
+ // reinstall connection status signal handler
+ static::$globalEvent->add(\SIGIO, EventInterface::EV_SIGNAL, $signalHandler);
+ }
+
+ /**
+ * Signal handler.
+ *
+ * @param int $signal
+ */
+ public static function signalHandler($signal)
+ {
+ switch ($signal) {
+ // Stop.
+ case \SIGINT:
+ case \SIGTERM:
+ static::$_gracefulStop = false;
+ static::stopAll();
+ break;
+ // Graceful stop.
+ case \SIGHUP:
+ static::$_gracefulStop = true;
+ static::stopAll();
+ break;
+ // Reload.
+ case \SIGQUIT:
+ case \SIGUSR1:
+ static::$_gracefulStop = $signal === \SIGQUIT;
+ static::$_pidsToRestart = static::getAllWorkerPids();
+ static::reload();
+ break;
+ // Show status.
+ case \SIGUSR2:
+ static::writeStatisticsToStatusFile();
+ break;
+ // Show connection status.
+ case \SIGIO:
+ static::writeConnectionsStatisticsToStatusFile();
+ break;
+ }
+ }
+
+ /**
+ * Run as deamon mode.
+ *
+ * @throws Exception
+ */
+ protected static function daemonize()
+ {
+ if (!static::$daemonize || static::$_OS !== \OS_TYPE_LINUX) {
+ return;
+ }
+ \umask(0);
+ $pid = \pcntl_fork();
+ if (-1 === $pid) {
+ throw new Exception('Fork fail');
+ } elseif ($pid > 0) {
+ exit(0);
+ }
+ if (-1 === \posix_setsid()) {
+ throw new Exception("Setsid fail");
+ }
+ // Fork again avoid SVR4 system regain the control of terminal.
+ $pid = \pcntl_fork();
+ if (-1 === $pid) {
+ throw new Exception("Fork fail");
+ } elseif (0 !== $pid) {
+ exit(0);
+ }
+ }
+
+ /**
+ * Redirect standard input and output.
+ *
+ * @throws Exception
+ */
+ public static function resetStd()
+ {
+ if (!static::$daemonize || static::$_OS !== \OS_TYPE_LINUX) {
+ return;
+ }
+ global $STDOUT, $STDERR;
+ $handle = \fopen(static::$stdoutFile, "a");
+ if ($handle) {
+ unset($handle);
+ \set_error_handler(function(){});
+ if ($STDOUT) {
+ \fclose($STDOUT);
+ }
+ if ($STDERR) {
+ \fclose($STDERR);
+ }
+ \fclose(\STDOUT);
+ \fclose(\STDERR);
+ $STDOUT = \fopen(static::$stdoutFile, "a");
+ $STDERR = \fopen(static::$stdoutFile, "a");
+ // change output stream
+ static::$_outputStream = null;
+ static::outputStream($STDOUT);
+ \restore_error_handler();
+ return;
+ }
+
+ throw new Exception('Can not open stdoutFile ' . static::$stdoutFile);
+ }
+
+ /**
+ * Save pid.
+ *
+ * @throws Exception
+ */
+ protected static function saveMasterPid()
+ {
+ if (static::$_OS !== \OS_TYPE_LINUX) {
+ return;
+ }
+
+ static::$_masterPid = \posix_getpid();
+ if (false === \file_put_contents(static::$pidFile, static::$_masterPid)) {
+ throw new Exception('can not save pid to ' . static::$pidFile);
+ }
+ }
+
+ /**
+ * Get event loop name.
+ *
+ * @return string
+ */
+ protected static function getEventLoopName()
+ {
+ if (static::$eventLoopClass) {
+ return static::$eventLoopClass;
+ }
+
+ if (!\class_exists('\Swoole\Event', false)) {
+ unset(static::$_availableEventLoops['swoole']);
+ }
+
+ $loop_name = '';
+ foreach (static::$_availableEventLoops as $name=>$class) {
+ if (\extension_loaded($name)) {
+ $loop_name = $name;
+ break;
+ }
+ }
+
+ if ($loop_name) {
+ if (\interface_exists('\React\EventLoop\LoopInterface')) {
+ switch ($loop_name) {
+ case 'libevent':
+ static::$eventLoopClass = '\Workerman\Events\React\ExtLibEventLoop';
+ break;
+ case 'event':
+ static::$eventLoopClass = '\Workerman\Events\React\ExtEventLoop';
+ break;
+ default :
+ static::$eventLoopClass = '\Workerman\Events\React\StreamSelectLoop';
+ break;
+ }
+ } else {
+ static::$eventLoopClass = static::$_availableEventLoops[$loop_name];
+ }
+ } else {
+ static::$eventLoopClass = \interface_exists('\React\EventLoop\LoopInterface') ? '\Workerman\Events\React\StreamSelectLoop' : '\Workerman\Events\Select';
+ }
+ return static::$eventLoopClass;
+ }
+
+ /**
+ * Get all pids of worker processes.
+ *
+ * @return array
+ */
+ protected static function getAllWorkerPids()
+ {
+ $pid_array = array();
+ foreach (static::$_pidMap as $worker_pid_array) {
+ foreach ($worker_pid_array as $worker_pid) {
+ $pid_array[$worker_pid] = $worker_pid;
+ }
+ }
+ return $pid_array;
+ }
+
+ /**
+ * Fork some worker processes.
+ *
+ * @return void
+ */
+ protected static function forkWorkers()
+ {
+ if (static::$_OS === \OS_TYPE_LINUX) {
+ static::forkWorkersForLinux();
+ } else {
+ static::forkWorkersForWindows();
+ }
+ }
+
+ /**
+ * Fork some worker processes.
+ *
+ * @return void
+ */
+ protected static function forkWorkersForLinux()
+ {
+
+ foreach (static::$_workers as $worker) {
+ if (static::$_status === static::STATUS_STARTING) {
+ if (empty($worker->name)) {
+ $worker->name = $worker->getSocketName();
+ }
+ $worker_name_length = \strlen($worker->name);
+ if (static::$_maxWorkerNameLength < $worker_name_length) {
+ static::$_maxWorkerNameLength = $worker_name_length;
+ }
+ }
+
+ while (\count(static::$_pidMap[$worker->workerId]) < $worker->count) {
+ static::forkOneWorkerForLinux($worker);
+ }
+ }
+ }
+
+ /**
+ * Fork some worker processes.
+ *
+ * @return void
+ */
+ protected static function forkWorkersForWindows()
+ {
+ $files = static::getStartFilesForWindows();
+ global $argv;
+ if(\in_array('-q', $argv) || \count($files) === 1)
+ {
+ if(\count(static::$_workers) > 1)
+ {
+ static::safeEcho("@@@ Error: multi workers init in one php file are not support @@@\r\n");
+ static::safeEcho("@@@ See http://doc.workerman.net/faq/multi-woker-for-windows.html @@@\r\n");
+ }
+ elseif(\count(static::$_workers) <= 0)
+ {
+ exit("@@@no worker inited@@@\r\n\r\n");
+ }
+
+ \reset(static::$_workers);
+ /** @var Worker $worker */
+ $worker = current(static::$_workers);
+
+ // Display UI.
+ static::safeEcho(\str_pad($worker->name, 21) . \str_pad($worker->getSocketName(), 36) . \str_pad($worker->count, 10) . "[ok]\n");
+ $worker->listen();
+ $worker->run();
+ exit("@@@child exit@@@\r\n");
+ }
+ else
+ {
+ static::$globalEvent = new \Workerman\Events\Select();
+ Timer::init(static::$globalEvent);
+ foreach($files as $start_file)
+ {
+ static::forkOneWorkerForWindows($start_file);
+ }
+ }
+ }
+
+ /**
+ * Get start files for windows.
+ *
+ * @return array
+ */
+ public static function getStartFilesForWindows() {
+ global $argv;
+ $files = array();
+ foreach($argv as $file)
+ {
+ if(\is_file($file))
+ {
+ $files[$file] = $file;
+ }
+ }
+ return $files;
+ }
+
+ /**
+ * Fork one worker process.
+ *
+ * @param string $start_file
+ */
+ public static function forkOneWorkerForWindows($start_file)
+ {
+ $start_file = \realpath($start_file);
+ $std_file = \sys_get_temp_dir() . '/'.\str_replace(array('/', "\\", ':'), '_', $start_file).'.out.txt';
+
+ $descriptorspec = array(
+ 0 => array('pipe', 'a'), // stdin
+ 1 => array('file', $std_file, 'w'), // stdout
+ 2 => array('file', $std_file, 'w') // stderr
+ );
+
+
+ $pipes = array();
+ $process = \proc_open("php \"$start_file\" -q", $descriptorspec, $pipes);
+ $std_handler = \fopen($std_file, 'a+');
+ \stream_set_blocking($std_handler, false);
+
+ if (empty(static::$globalEvent)) {
+ static::$globalEvent = new Select();
+ Timer::init(static::$globalEvent);
+ }
+ $timer_id = Timer::add(0.1, function()use($std_handler)
+ {
+ Worker::safeEcho(\fread($std_handler, 65535));
+ });
+
+ // 保存子进程句柄
+ static::$_processForWindows[$start_file] = array($process, $start_file, $timer_id);
+ }
+
+ /**
+ * check worker status for windows.
+ * @return void
+ */
+ public static function checkWorkerStatusForWindows()
+ {
+ foreach(static::$_processForWindows as $process_data)
+ {
+ $process = $process_data[0];
+ $start_file = $process_data[1];
+ $timer_id = $process_data[2];
+ $status = \proc_get_status($process);
+ if(isset($status['running']))
+ {
+ if(!$status['running'])
+ {
+ static::safeEcho("process $start_file terminated and try to restart\n");
+ Timer::del($timer_id);
+ \proc_close($process);
+ static::forkOneWorkerForWindows($start_file);
+ }
+ }
+ else
+ {
+ static::safeEcho("proc_get_status fail\n");
+ }
+ }
+ }
+
+
+ /**
+ * Fork one worker process.
+ *
+ * @param self $worker
+ * @throws Exception
+ */
+ protected static function forkOneWorkerForLinux(self $worker)
+ {
+ // Get available worker id.
+ $id = static::getId($worker->workerId, 0);
+ if ($id === false) {
+ return;
+ }
+ $pid = \pcntl_fork();
+ // For master process.
+ if ($pid > 0) {
+ static::$_pidMap[$worker->workerId][$pid] = $pid;
+ static::$_idMap[$worker->workerId][$id] = $pid;
+ } // For child processes.
+ elseif (0 === $pid) {
+ \srand();
+ \mt_srand();
+ if ($worker->reusePort) {
+ $worker->listen();
+ }
+ if (static::$_status === static::STATUS_STARTING) {
+ static::resetStd();
+ }
+ static::$_pidMap = array();
+ // Remove other listener.
+ foreach(static::$_workers as $key => $one_worker) {
+ if ($one_worker->workerId !== $worker->workerId) {
+ $one_worker->unlisten();
+ unset(static::$_workers[$key]);
+ }
+ }
+ Timer::delAll();
+ static::setProcessTitle(self::$processTitle . ': worker process ' . $worker->name . ' ' . $worker->getSocketName());
+ $worker->setUserAndGroup();
+ $worker->id = $id;
+ $worker->run();
+ if (strpos(static::$eventLoopClass, 'Workerman\Events\Swoole') !== false) {
+ exit(0);
+ }
+ $err = new Exception('event-loop exited');
+ static::log($err);
+ exit(250);
+ } else {
+ throw new Exception("forkOneWorker fail");
+ }
+ }
+
+ /**
+ * Get worker id.
+ *
+ * @param int $worker_id
+ * @param int $pid
+ *
+ * @return integer
+ */
+ protected static function getId($worker_id, $pid)
+ {
+ return \array_search($pid, static::$_idMap[$worker_id]);
+ }
+
+ /**
+ * Set unix user and group for current process.
+ *
+ * @return void
+ */
+ public function setUserAndGroup()
+ {
+ // Get uid.
+ $user_info = \posix_getpwnam($this->user);
+ if (!$user_info) {
+ static::log("Warning: User {$this->user} not exsits");
+ return;
+ }
+ $uid = $user_info['uid'];
+ // Get gid.
+ if ($this->group) {
+ $group_info = \posix_getgrnam($this->group);
+ if (!$group_info) {
+ static::log("Warning: Group {$this->group} not exsits");
+ return;
+ }
+ $gid = $group_info['gid'];
+ } else {
+ $gid = $user_info['gid'];
+ }
+
+ // Set uid and gid.
+ if ($uid !== \posix_getuid() || $gid !== \posix_getgid()) {
+ if (!\posix_setgid($gid) || !\posix_initgroups($user_info['name'], $gid) || !\posix_setuid($uid)) {
+ static::log("Warning: change gid or uid fail.");
+ }
+ }
+ }
+
+ /**
+ * Set process name.
+ *
+ * @param string $title
+ * @return void
+ */
+ protected static function setProcessTitle($title)
+ {
+ \set_error_handler(function(){});
+ // >=php 5.5
+ if (\function_exists('cli_set_process_title')) {
+ \cli_set_process_title($title);
+ } // Need proctitle when php<=5.5 .
+ elseif (\extension_loaded('proctitle') && \function_exists('setproctitle')) {
+ \setproctitle($title);
+ }
+ \restore_error_handler();
+ }
+
+ /**
+ * Monitor all child processes.
+ *
+ * @return void
+ */
+ protected static function monitorWorkers()
+ {
+ if (static::$_OS === \OS_TYPE_LINUX) {
+ static::monitorWorkersForLinux();
+ } else {
+ static::monitorWorkersForWindows();
+ }
+ }
+
+ /**
+ * Monitor all child processes.
+ *
+ * @return void
+ */
+ protected static function monitorWorkersForLinux()
+ {
+ static::$_status = static::STATUS_RUNNING;
+ while (1) {
+ // Calls signal handlers for pending signals.
+ \pcntl_signal_dispatch();
+ // Suspends execution of the current process until a child has exited, or until a signal is delivered
+ $status = 0;
+ $pid = \pcntl_wait($status, \WUNTRACED);
+ // Calls signal handlers for pending signals again.
+ \pcntl_signal_dispatch();
+ // If a child has already exited.
+ if ($pid > 0) {
+ // Find out which worker process exited.
+ foreach (static::$_pidMap as $worker_id => $worker_pid_array) {
+ if (isset($worker_pid_array[$pid])) {
+ $worker = static::$_workers[$worker_id];
+ // Exit status.
+ if ($status !== 0) {
+ static::log("worker[" . $worker->name . ":$pid] exit with status $status");
+ }
+
+ // For Statistics.
+ if (!isset(static::$_globalStatistics['worker_exit_info'][$worker_id][$status])) {
+ static::$_globalStatistics['worker_exit_info'][$worker_id][$status] = 0;
+ }
+ ++static::$_globalStatistics['worker_exit_info'][$worker_id][$status];
+
+ // Clear process data.
+ unset(static::$_pidMap[$worker_id][$pid]);
+
+ // Mark id is available.
+ $id = static::getId($worker_id, $pid);
+ static::$_idMap[$worker_id][$id] = 0;
+
+ break;
+ }
+ }
+ // Is still running state then fork a new worker process.
+ if (static::$_status !== static::STATUS_SHUTDOWN) {
+ static::forkWorkers();
+ // If reloading continue.
+ if (isset(static::$_pidsToRestart[$pid])) {
+ unset(static::$_pidsToRestart[$pid]);
+ static::reload();
+ }
+ }
+ }
+
+ // If shutdown state and all child processes exited then master process exit.
+ if (static::$_status === static::STATUS_SHUTDOWN && !static::getAllWorkerPids()) {
+ static::exitAndClearAll();
+ }
+ }
+ }
+
+ /**
+ * Monitor all child processes.
+ *
+ * @return void
+ */
+ protected static function monitorWorkersForWindows()
+ {
+ Timer::add(1, "\\Workerman\\Worker::checkWorkerStatusForWindows");
+
+ static::$globalEvent->loop();
+ }
+
+ /**
+ * Exit current process.
+ *
+ * @return void
+ */
+ protected static function exitAndClearAll()
+ {
+ foreach (static::$_workers as $worker) {
+ $socket_name = $worker->getSocketName();
+ if ($worker->transport === 'unix' && $socket_name) {
+ list(, $address) = \explode(':', $socket_name, 2);
+ @\unlink($address);
+ }
+ }
+ @\unlink(static::$pidFile);
+ static::log("Workerman[" . \basename(static::$_startFile) . "] has been stopped");
+ if (static::$onMasterStop) {
+ \call_user_func(static::$onMasterStop);
+ }
+ exit(0);
+ }
+
+ /**
+ * Execute reload.
+ *
+ * @return void
+ */
+ protected static function reload()
+ {
+ // For master process.
+ if (static::$_masterPid === \posix_getpid()) {
+ // Set reloading state.
+ if (static::$_status !== static::STATUS_RELOADING && static::$_status !== static::STATUS_SHUTDOWN) {
+ static::log("Workerman[" . \basename(static::$_startFile) . "] reloading");
+ static::$_status = static::STATUS_RELOADING;
+ // Try to emit onMasterReload callback.
+ if (static::$onMasterReload) {
+ try {
+ \call_user_func(static::$onMasterReload);
+ } catch (\Exception $e) {
+ static::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ static::log($e);
+ exit(250);
+ }
+ static::initId();
+ }
+ }
+
+ if (static::$_gracefulStop) {
+ $sig = \SIGQUIT;
+ } else {
+ $sig = \SIGUSR1;
+ }
+
+ // Send reload signal to all child processes.
+ $reloadable_pid_array = array();
+ foreach (static::$_pidMap as $worker_id => $worker_pid_array) {
+ $worker = static::$_workers[$worker_id];
+ if ($worker->reloadable) {
+ foreach ($worker_pid_array as $pid) {
+ $reloadable_pid_array[$pid] = $pid;
+ }
+ } else {
+ foreach ($worker_pid_array as $pid) {
+ // Send reload signal to a worker process which reloadable is false.
+ \posix_kill($pid, $sig);
+ }
+ }
+ }
+
+ // Get all pids that are waiting reload.
+ static::$_pidsToRestart = \array_intersect(static::$_pidsToRestart, $reloadable_pid_array);
+
+ // Reload complete.
+ if (empty(static::$_pidsToRestart)) {
+ if (static::$_status !== static::STATUS_SHUTDOWN) {
+ static::$_status = static::STATUS_RUNNING;
+ }
+ return;
+ }
+ // Continue reload.
+ $one_worker_pid = \current(static::$_pidsToRestart);
+ // Send reload signal to a worker process.
+ \posix_kill($one_worker_pid, $sig);
+ // If the process does not exit after static::KILL_WORKER_TIMER_TIME seconds try to kill it.
+ if(!static::$_gracefulStop){
+ Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($one_worker_pid, \SIGKILL), false);
+ }
+ } // For child processes.
+ else {
+ \reset(static::$_workers);
+ $worker = \current(static::$_workers);
+ // Try to emit onWorkerReload callback.
+ if ($worker->onWorkerReload) {
+ try {
+ \call_user_func($worker->onWorkerReload, $worker);
+ } catch (\Exception $e) {
+ static::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ static::log($e);
+ exit(250);
+ }
+ }
+
+ if ($worker->reloadable) {
+ static::stopAll();
+ }
+ }
+ }
+
+ /**
+ * Stop.
+ *
+ * @return void
+ */
+ public static function stopAll()
+ {
+ static::$_status = static::STATUS_SHUTDOWN;
+ // For master process.
+ if (static::$_masterPid === \posix_getpid()) {
+ static::log("Workerman[" . \basename(static::$_startFile) . "] stopping ...");
+ $worker_pid_array = static::getAllWorkerPids();
+ // Send stop signal to all child processes.
+ if (static::$_gracefulStop) {
+ $sig = \SIGHUP;
+ } else {
+ $sig = \SIGINT;
+ }
+ foreach ($worker_pid_array as $worker_pid) {
+ \posix_kill($worker_pid, $sig);
+ if(!static::$_gracefulStop){
+ Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($worker_pid, \SIGKILL), false);
+ }
+ }
+ Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning");
+ // Remove statistics file.
+ if (\is_file(static::$_statisticsFile)) {
+ @\unlink(static::$_statisticsFile);
+ }
+ } // For child processes.
+ else {
+ // Execute exit.
+ foreach (static::$_workers as $worker) {
+ if(!$worker->stopping){
+ $worker->stop();
+ $worker->stopping = true;
+ }
+ }
+ if (!static::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) {
+ static::$_workers = array();
+ if (static::$globalEvent) {
+ static::$globalEvent->destroy();
+ }
+
+ try {
+ exit(0);
+ } catch (Exception $e) {
+
+ }
+ }
+ }
+ }
+
+ /**
+ * check if child processes is really running
+ */
+ public static function checkIfChildRunning()
+ {
+ foreach (static::$_pidMap as $worker_id => $worker_pid_array) {
+ foreach ($worker_pid_array as $pid => $worker_pid) {
+ if (!\posix_kill($pid, 0)) {
+ unset(static::$_pidMap[$worker_id][$pid]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get process status.
+ *
+ * @return number
+ */
+ public static function getStatus()
+ {
+ return static::$_status;
+ }
+
+ /**
+ * If stop gracefully.
+ *
+ * @return bool
+ */
+ public static function getGracefulStop()
+ {
+ return static::$_gracefulStop;
+ }
+
+ /**
+ * Write statistics data to disk.
+ *
+ * @return void
+ */
+ protected static function writeStatisticsToStatusFile()
+ {
+ // For master process.
+ if (static::$_masterPid === \posix_getpid()) {
+ $all_worker_info = array();
+ foreach(static::$_pidMap as $worker_id => $pid_array) {
+ /** @var /Workerman/Worker $worker */
+ $worker = static::$_workers[$worker_id];
+ foreach($pid_array as $pid) {
+ $all_worker_info[$pid] = array('name' => $worker->name, 'listen' => $worker->getSocketName());
+ }
+ }
+
+ \file_put_contents(static::$_statisticsFile, \serialize($all_worker_info)."\n", \FILE_APPEND);
+ $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), array(2)) : array('-', '-', '-');
+ \file_put_contents(static::$_statisticsFile,
+ "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", \FILE_APPEND);
+ \file_put_contents(static::$_statisticsFile,
+ 'Workerman version:' . static::VERSION . " PHP version:" . \PHP_VERSION . "\n", \FILE_APPEND);
+ \file_put_contents(static::$_statisticsFile, 'start time:' . \date('Y-m-d H:i:s',
+ static::$_globalStatistics['start_timestamp']) . ' run ' . \floor((\time() - static::$_globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . \floor(((\time() - static::$_globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n",
+ FILE_APPEND);
+ $load_str = 'load average: ' . \implode(", ", $loadavg);
+ \file_put_contents(static::$_statisticsFile,
+ \str_pad($load_str, 33) . 'event-loop:' . static::getEventLoopName() . "\n", \FILE_APPEND);
+ \file_put_contents(static::$_statisticsFile,
+ \count(static::$_pidMap) . ' workers ' . \count(static::getAllWorkerPids()) . " processes\n",
+ \FILE_APPEND);
+ \file_put_contents(static::$_statisticsFile,
+ \str_pad('worker_name', static::$_maxWorkerNameLength) . " exit_status exit_count\n", \FILE_APPEND);
+ foreach (static::$_pidMap as $worker_id => $worker_pid_array) {
+ $worker = static::$_workers[$worker_id];
+ if (isset(static::$_globalStatistics['worker_exit_info'][$worker_id])) {
+ foreach (static::$_globalStatistics['worker_exit_info'][$worker_id] as $worker_exit_status => $worker_exit_count) {
+ \file_put_contents(static::$_statisticsFile,
+ \str_pad($worker->name, static::$_maxWorkerNameLength) . " " . \str_pad($worker_exit_status,
+ 16) . " $worker_exit_count\n", \FILE_APPEND);
+ }
+ } else {
+ \file_put_contents(static::$_statisticsFile,
+ \str_pad($worker->name, static::$_maxWorkerNameLength) . " " . \str_pad(0, 16) . " 0\n",
+ \FILE_APPEND);
+ }
+ }
+ \file_put_contents(static::$_statisticsFile,
+ "----------------------------------------------PROCESS STATUS---------------------------------------------------\n",
+ \FILE_APPEND);
+ \file_put_contents(static::$_statisticsFile,
+ "pid\tmemory " . \str_pad('listening', static::$_maxSocketNameLength) . " " . \str_pad('worker_name',
+ static::$_maxWorkerNameLength) . " connections " . \str_pad('send_fail', 9) . " "
+ . \str_pad('timers', 8) . \str_pad('total_request', 13) ." qps status\n", \FILE_APPEND);
+
+ \chmod(static::$_statisticsFile, 0722);
+
+ foreach (static::getAllWorkerPids() as $worker_pid) {
+ \posix_kill($worker_pid, \SIGUSR2);
+ }
+ return;
+ }
+
+ // For child processes.
+ \reset(static::$_workers);
+ /** @var \Workerman\Worker $worker */
+ $worker = current(static::$_workers);
+ $worker_status_str = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7)
+ . " " . \str_pad($worker->getSocketName(), static::$_maxSocketNameLength) . " "
+ . \str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$_maxWorkerNameLength)
+ . " ";
+ $worker_status_str .= \str_pad(ConnectionInterface::$statistics['connection_count'], 11)
+ . " " . \str_pad(ConnectionInterface::$statistics['send_fail'], 9)
+ . " " . \str_pad(static::$globalEvent->getTimerCount(), 7)
+ . " " . \str_pad(ConnectionInterface::$statistics['total_request'], 13) . "\n";
+ \file_put_contents(static::$_statisticsFile, $worker_status_str, \FILE_APPEND);
+ }
+
+ /**
+ * Write statistics data to disk.
+ *
+ * @return void
+ */
+ protected static function writeConnectionsStatisticsToStatusFile()
+ {
+ // For master process.
+ if (static::$_masterPid === \posix_getpid()) {
+ \file_put_contents(static::$_statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", \FILE_APPEND);
+ \file_put_contents(static::$_statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", \FILE_APPEND);
+ \chmod(static::$_statisticsFile, 0722);
+ foreach (static::getAllWorkerPids() as $worker_pid) {
+ \posix_kill($worker_pid, \SIGIO);
+ }
+ return;
+ }
+
+ // For child processes.
+ $bytes_format = function($bytes)
+ {
+ if($bytes > 1024*1024*1024*1024) {
+ return round($bytes/(1024*1024*1024*1024), 1)."TB";
+ }
+ if($bytes > 1024*1024*1024) {
+ return round($bytes/(1024*1024*1024), 1)."GB";
+ }
+ if($bytes > 1024*1024) {
+ return round($bytes/(1024*1024), 1)."MB";
+ }
+ if($bytes > 1024) {
+ return round($bytes/(1024), 1)."KB";
+ }
+ return $bytes."B";
+ };
+
+ $pid = \posix_getpid();
+ $str = '';
+ \reset(static::$_workers);
+ $current_worker = current(static::$_workers);
+ $default_worker_name = $current_worker->name;
+
+ /** @var \Workerman\Worker $worker */
+ foreach(TcpConnection::$connections as $connection) {
+ /** @var \Workerman\Connection\TcpConnection $connection */
+ $transport = $connection->transport;
+ $ipv4 = $connection->isIpV4() ? ' 1' : ' 0';
+ $ipv6 = $connection->isIpV6() ? ' 1' : ' 0';
+ $recv_q = $bytes_format($connection->getRecvBufferQueueSize());
+ $send_q = $bytes_format($connection->getSendBufferQueueSize());
+ $local_address = \trim($connection->getLocalAddress());
+ $remote_address = \trim($connection->getRemoteAddress());
+ $state = $connection->getStatus(false);
+ $bytes_read = $bytes_format($connection->bytesRead);
+ $bytes_written = $bytes_format($connection->bytesWritten);
+ $id = $connection->id;
+ $protocol = $connection->protocol ? $connection->protocol : $connection->transport;
+ $pos = \strrpos($protocol, '\\');
+ if ($pos) {
+ $protocol = \substr($protocol, $pos+1);
+ }
+ if (\strlen($protocol) > 15) {
+ $protocol = \substr($protocol, 0, 13) . '..';
+ }
+ $worker_name = isset($connection->worker) ? $connection->worker->name : $default_worker_name;
+ if (\strlen($worker_name) > 14) {
+ $worker_name = \substr($worker_name, 0, 12) . '..';
+ }
+ $str .= \str_pad($pid, 9) . \str_pad($worker_name, 16) . \str_pad($id, 10) . \str_pad($transport, 8)
+ . \str_pad($protocol, 16) . \str_pad($ipv4, 7) . \str_pad($ipv6, 7) . \str_pad($recv_q, 13)
+ . \str_pad($send_q, 13) . \str_pad($bytes_read, 13) . \str_pad($bytes_written, 13) . ' '
+ . \str_pad($state, 14) . ' ' . \str_pad($local_address, 22) . ' ' . \str_pad($remote_address, 22) ."\n";
+ }
+ if ($str) {
+ \file_put_contents(static::$_statisticsFile, $str, \FILE_APPEND);
+ }
+ }
+
+ /**
+ * Check errors when current process exited.
+ *
+ * @return void
+ */
+ public static function checkErrors()
+ {
+ if (static::STATUS_SHUTDOWN !== static::$_status) {
+ $error_msg = static::$_OS === \OS_TYPE_LINUX ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated';
+ $errors = error_get_last();
+ if ($errors && ($errors['type'] === \E_ERROR ||
+ $errors['type'] === \E_PARSE ||
+ $errors['type'] === \E_CORE_ERROR ||
+ $errors['type'] === \E_COMPILE_ERROR ||
+ $errors['type'] === \E_RECOVERABLE_ERROR)
+ ) {
+ $error_msg .= ' with ERROR: ' . static::getErrorType($errors['type']) . " \"{$errors['message']} in {$errors['file']} on line {$errors['line']}\"";
+ }
+ static::log($error_msg);
+ }
+ }
+
+ /**
+ * Get error message by error code.
+ *
+ * @param integer $type
+ * @return string
+ */
+ protected static function getErrorType($type)
+ {
+ if(isset(self::$_errorType[$type])) {
+ return self::$_errorType[$type];
+ }
+
+ return '';
+ }
+
+ /**
+ * Log.
+ *
+ * @param string $msg
+ * @return void
+ */
+ public static function log($msg)
+ {
+ $msg = $msg . "\n";
+ if (!static::$daemonize) {
+ static::safeEcho($msg);
+ }
+ \file_put_contents((string)static::$logFile, \date('Y-m-d H:i:s') . ' ' . 'pid:'
+ . (static::$_OS === \OS_TYPE_LINUX ? \posix_getpid() : 1) . ' ' . $msg, \FILE_APPEND | \LOCK_EX);
+ }
+
+ /**
+ * Safe Echo.
+ * @param string $msg
+ * @param bool $decorated
+ * @return bool
+ */
+ public static function safeEcho($msg, $decorated = false)
+ {
+ $stream = static::outputStream();
+ if (!$stream) {
+ return false;
+ }
+ if (!$decorated) {
+ $line = $white = $green = $end = '';
+ if (static::$_outputDecorated) {
+ $line = "\033[1A\n\033[K";
+ $white = "\033[47;30m";
+ $green = "\033[32;40m";
+ $end = "\033[0m";
+ }
+ $msg = \str_replace(array('', '', ''), array($line, $white, $green), $msg);
+ $msg = \str_replace(array('', '', ''), $end, $msg);
+ } elseif (!static::$_outputDecorated) {
+ return false;
+ }
+ \fwrite($stream, $msg);
+ \fflush($stream);
+ return true;
+ }
+
+ /**
+ * @param null $stream
+ * @return bool|resource
+ */
+ private static function outputStream($stream = null)
+ {
+ if (!$stream) {
+ $stream = static::$_outputStream ? static::$_outputStream : \STDOUT;
+ }
+ if (!$stream || !\is_resource($stream) || 'stream' !== \get_resource_type($stream)) {
+ return false;
+ }
+ $stat = \fstat($stream);
+ if (!$stat) {
+ return false;
+ }
+ if (($stat['mode'] & 0170000) === 0100000) {
+ // file
+ static::$_outputDecorated = false;
+ } else {
+ static::$_outputDecorated =
+ static::$_OS === \OS_TYPE_LINUX &&
+ \function_exists('posix_isatty') &&
+ \posix_isatty($stream);
+ }
+ return static::$_outputStream = $stream;
+ }
+
+ /**
+ * Construct.
+ *
+ * @param string $socket_name
+ * @param array $context_option
+ */
+ public function __construct($socket_name = '', array $context_option = array())
+ {
+ // Save all worker instances.
+ $this->workerId = \spl_object_hash($this);
+ static::$_workers[$this->workerId] = $this;
+ static::$_pidMap[$this->workerId] = array();
+
+ // Get autoload root path.
+ $backtrace = \debug_backtrace();
+ $this->_autoloadRootPath = \dirname($backtrace[0]['file']);
+ Autoloader::setRootPath($this->_autoloadRootPath);
+
+ // Context for socket.
+ if ($socket_name) {
+ $this->_socketName = $socket_name;
+ if (!isset($context_option['socket']['backlog'])) {
+ $context_option['socket']['backlog'] = static::DEFAULT_BACKLOG;
+ }
+ $this->_context = \stream_context_create($context_option);
+ }
+
+ // Turn reusePort on.
+ if (static::$_OS === \OS_TYPE_LINUX // if linux
+ && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0
+ && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS
+ && strpos($socket_name,'unix') !== 0) { // if not unix socket
+
+ $this->reusePort = true;
+ }
+ }
+
+
+ /**
+ * Listen.
+ *
+ * @throws Exception
+ */
+ public function listen()
+ {
+ if (!$this->_socketName) {
+ return;
+ }
+
+ // Autoload.
+ Autoloader::setRootPath($this->_autoloadRootPath);
+
+ if (!$this->_mainSocket) {
+
+ $local_socket = $this->parseSocketAddress();
+
+ // Flag.
+ $flags = $this->transport === 'udp' ? \STREAM_SERVER_BIND : \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN;
+ $errno = 0;
+ $errmsg = '';
+ // SO_REUSEPORT.
+ if ($this->reusePort) {
+ \stream_context_set_option($this->_context, 'socket', 'so_reuseport', 1);
+ }
+
+ // Create an Internet or Unix domain server socket.
+ $this->_mainSocket = \stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context);
+ if (!$this->_mainSocket) {
+ throw new Exception($errmsg);
+ }
+
+ if ($this->transport === 'ssl') {
+ \stream_socket_enable_crypto($this->_mainSocket, false);
+ } elseif ($this->transport === 'unix') {
+ $socket_file = \substr($local_socket, 7);
+ if ($this->user) {
+ \chown($socket_file, $this->user);
+ }
+ if ($this->group) {
+ \chgrp($socket_file, $this->group);
+ }
+ }
+
+ // Try to open keepalive for tcp and disable Nagle algorithm.
+ if (\function_exists('socket_import_stream') && static::$_builtinTransports[$this->transport] === 'tcp') {
+ \set_error_handler(function(){});
+ $socket = \socket_import_stream($this->_mainSocket);
+ \socket_set_option($socket, \SOL_SOCKET, \SO_KEEPALIVE, 1);
+ \socket_set_option($socket, \SOL_TCP, \TCP_NODELAY, 1);
+ \restore_error_handler();
+ }
+
+ // Non blocking.
+ \stream_set_blocking($this->_mainSocket, false);
+ }
+
+ $this->resumeAccept();
+ }
+
+ /**
+ * Unlisten.
+ *
+ * @return void
+ */
+ public function unlisten() {
+ $this->pauseAccept();
+ if ($this->_mainSocket) {
+ \set_error_handler(function(){});
+ \fclose($this->_mainSocket);
+ \restore_error_handler();
+ $this->_mainSocket = null;
+ }
+ }
+
+ /**
+ * Parse local socket address.
+ *
+ * @throws Exception
+ */
+ protected function parseSocketAddress() {
+ if (!$this->_socketName) {
+ return;
+ }
+ // Get the application layer communication protocol and listening address.
+ list($scheme, $address) = \explode(':', $this->_socketName, 2);
+ // Check application layer protocol class.
+ if (!isset(static::$_builtinTransports[$scheme])) {
+ $scheme = \ucfirst($scheme);
+ $this->protocol = \substr($scheme,0,1)==='\\' ? $scheme : 'Protocols\\' . $scheme;
+ if (!\class_exists($this->protocol)) {
+ $this->protocol = "Workerman\\Protocols\\$scheme";
+ if (!\class_exists($this->protocol)) {
+ throw new Exception("class \\Protocols\\$scheme not exist");
+ }
+ }
+
+ if (!isset(static::$_builtinTransports[$this->transport])) {
+ throw new Exception('Bad worker->transport ' . \var_export($this->transport, true));
+ }
+ } else {
+ $this->transport = $scheme;
+ }
+ //local socket
+ return static::$_builtinTransports[$this->transport] . ":" . $address;
+ }
+
+ /**
+ * Pause accept new connections.
+ *
+ * @return void
+ */
+ public function pauseAccept()
+ {
+ if (static::$globalEvent && false === $this->_pauseAccept && $this->_mainSocket) {
+ static::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ);
+ $this->_pauseAccept = true;
+ }
+ }
+
+ /**
+ * Resume accept new connections.
+ *
+ * @return void
+ */
+ public function resumeAccept()
+ {
+ // Register a listener to be notified when server socket is ready to read.
+ if (static::$globalEvent && true === $this->_pauseAccept && $this->_mainSocket) {
+ if ($this->transport !== 'udp') {
+ static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection'));
+ } else {
+ static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection'));
+ }
+ $this->_pauseAccept = false;
+ }
+ }
+
+ /**
+ * Get socket name.
+ *
+ * @return string
+ */
+ public function getSocketName()
+ {
+ return $this->_socketName ? \lcfirst($this->_socketName) : 'none';
+ }
+
+ /**
+ * Run worker instance.
+ *
+ * @return void
+ */
+ public function run()
+ {
+ //Update process state.
+ static::$_status = static::STATUS_RUNNING;
+
+ // Register shutdown function for checking errors.
+ \register_shutdown_function(array("\\Workerman\\Worker", 'checkErrors'));
+
+ // Set autoload root path.
+ Autoloader::setRootPath($this->_autoloadRootPath);
+
+ // Create a global event loop.
+ if (!static::$globalEvent) {
+ $event_loop_class = static::getEventLoopName();
+ static::$globalEvent = new $event_loop_class;
+ $this->resumeAccept();
+ }
+
+ // Reinstall signal.
+ static::reinstallSignal();
+
+ // Init Timer.
+ Timer::init(static::$globalEvent);
+
+ // Set an empty onMessage callback.
+ if (empty($this->onMessage)) {
+ $this->onMessage = function () {};
+ }
+
+ \restore_error_handler();
+
+ // Try to emit onWorkerStart callback.
+ if ($this->onWorkerStart) {
+ try {
+ \call_user_func($this->onWorkerStart, $this);
+ } catch (\Exception $e) {
+ static::log($e);
+ // Avoid rapid infinite loop exit.
+ sleep(1);
+ exit(250);
+ } catch (\Error $e) {
+ static::log($e);
+ // Avoid rapid infinite loop exit.
+ sleep(1);
+ exit(250);
+ }
+ }
+
+ // Main loop.
+ static::$globalEvent->loop();
+ }
+
+ /**
+ * Stop current worker instance.
+ *
+ * @return void
+ */
+ public function stop()
+ {
+ // Try to emit onWorkerStop callback.
+ if ($this->onWorkerStop) {
+ try {
+ \call_user_func($this->onWorkerStop, $this);
+ } catch (\Exception $e) {
+ static::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ static::log($e);
+ exit(250);
+ }
+ }
+ // Remove listener for server socket.
+ $this->unlisten();
+ // Close all connections for the worker.
+ if (!static::$_gracefulStop) {
+ foreach ($this->connections as $connection) {
+ $connection->close();
+ }
+ }
+ // Clear callback.
+ $this->onMessage = $this->onClose = $this->onError = $this->onBufferDrain = $this->onBufferFull = null;
+ }
+
+ /**
+ * Accept a connection.
+ *
+ * @param resource $socket
+ * @return void
+ */
+ public function acceptConnection($socket)
+ {
+ // Accept a connection on server socket.
+ \set_error_handler(function(){});
+ $new_socket = \stream_socket_accept($socket, 0, $remote_address);
+ \restore_error_handler();
+
+ // Thundering herd.
+ if (!$new_socket) {
+ return;
+ }
+
+ // TcpConnection.
+ $connection = new TcpConnection($new_socket, $remote_address);
+ $this->connections[$connection->id] = $connection;
+ $connection->worker = $this;
+ $connection->protocol = $this->protocol;
+ $connection->transport = $this->transport;
+ $connection->onMessage = $this->onMessage;
+ $connection->onClose = $this->onClose;
+ $connection->onError = $this->onError;
+ $connection->onBufferDrain = $this->onBufferDrain;
+ $connection->onBufferFull = $this->onBufferFull;
+
+ // Try to emit onConnect callback.
+ if ($this->onConnect) {
+ try {
+ \call_user_func($this->onConnect, $connection);
+ } catch (\Exception $e) {
+ static::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ static::log($e);
+ exit(250);
+ }
+ }
+ }
+
+ /**
+ * For udp package.
+ *
+ * @param resource $socket
+ * @return bool
+ */
+ public function acceptUdpConnection($socket)
+ {
+ \set_error_handler(function(){});
+ $recv_buffer = \stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remote_address);
+ \restore_error_handler();
+ if (false === $recv_buffer || empty($remote_address)) {
+ return false;
+ }
+ // UdpConnection.
+ $connection = new UdpConnection($socket, $remote_address);
+ $connection->protocol = $this->protocol;
+ if ($this->onMessage) {
+ try {
+ if ($this->protocol !== null) {
+ /** @var \Workerman\Protocols\ProtocolInterface $parser */
+ $parser = $this->protocol;
+ if ($parser && \method_exists($parser, 'input')) {
+ while ($recv_buffer !== '') {
+ $len = $parser::input($recv_buffer, $connection);
+ if ($len === 0)
+ return true;
+ $package = \substr($recv_buffer, 0, $len);
+ $recv_buffer = \substr($recv_buffer, $len);
+ $data = $parser::decode($package, $connection);
+ if ($data === false)
+ continue;
+ \call_user_func($this->onMessage, $connection, $data);
+ }
+ } else {
+ $data = $parser::decode($recv_buffer, $connection);
+ // Discard bad packets.
+ if ($data === false)
+ return true;
+ \call_user_func($this->onMessage, $connection, $data);
+ }
+ } else {
+ \call_user_func($this->onMessage, $connection, $recv_buffer);
+ }
+ ++ConnectionInterface::$statistics['total_request'];
+ } catch (\Exception $e) {
+ static::log($e);
+ exit(250);
+ } catch (\Error $e) {
+ static::log($e);
+ exit(250);
+ }
+ }
+ return true;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/workerman/workerman/composer.json b/addons/weliam_smartcity/vendor/workerman/workerman/composer.json
new file mode 100644
index 0000000..fdd4808
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/workerman/workerman/composer.json
@@ -0,0 +1,38 @@
+{
+ "name": "workerman/workerman",
+ "type": "library",
+ "keywords": [
+ "event-loop",
+ "asynchronous"
+ ],
+ "homepage": "http://www.workerman.net",
+ "license": "MIT",
+ "description": "An asynchronous event driven PHP framework for easily building fast, scalable network applications.",
+ "authors": [
+ {
+ "name": "walkor",
+ "email": "walkor@workerman.net",
+ "homepage": "http://www.workerman.net",
+ "role": "Developer"
+ }
+ ],
+ "support": {
+ "email": "walkor@workerman.net",
+ "issues": "https://github.com/walkor/workerman/issues",
+ "forum": "http://wenda.workerman.net/",
+ "wiki": "http://doc.workerman.net/",
+ "source": "https://github.com/walkor/workerman"
+ },
+ "require": {
+ "php": ">=5.3"
+ },
+ "suggest": {
+ "ext-event": "For better performance. "
+ },
+ "autoload": {
+ "psr-4": {
+ "Workerman\\": "./"
+ }
+ },
+ "minimum-stability": "dev"
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/.github/ISSUE_TEMPLATE/bug-report.md b/addons/weliam_smartcity/vendor/yansongda/pay/.github/ISSUE_TEMPLATE/bug-report.md
new file mode 100644
index 0000000..a4fc9ad
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/.github/ISSUE_TEMPLATE/bug-report.md
@@ -0,0 +1,23 @@
+---
+name: Bug Report
+about: Bug report
+
+---
+
+## 包版本号
+
+
+## 问题描述
+
+
+## 你的代码
+
+
+## 报错详情
+
+
+## sdk 日志
+
+
+## nginx/apache 日志
+> 涉及到 异步通知、同步通知 的问题,请贴出来
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/.github/ISSUE_TEMPLATE/feature_request.md b/addons/weliam_smartcity/vendor/yansongda/pay/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..066b2d9
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,17 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/.gitignore b/addons/weliam_smartcity/vendor/yansongda/pay/.gitignore
new file mode 100644
index 0000000..6de499c
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/.gitignore
@@ -0,0 +1,4 @@
+/vendor
+composer.lock
+*.DS_Store
+.idea
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/LICENSE b/addons/weliam_smartcity/vendor/yansongda/pay/LICENSE
new file mode 100644
index 0000000..6ceb153
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 yansongda
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/README.md b/addons/weliam_smartcity/vendor/yansongda/pay/README.md
new file mode 100644
index 0000000..91334c5
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/README.md
@@ -0,0 +1,307 @@
+Pay
+
+
+
+
+
+
+
+
+
+
+
+该文档为 v2.x 版本,如果您想找 v1.x 版本文档,请点击[https://github.com/yansongda/pay/tree/v1.x](https://github.com/yansongda/pay/tree/v1.x)
+
+**注意:v1.x 与 v2.x 版本不兼容**
+
+
+开发了多次支付宝与微信支付后,很自然产生一种反感,惰性又来了,想在网上找相关的轮子,可是一直没有找到一款自己觉得逞心如意的,要么使用起来太难理解,要么文件结构太杂乱,只有自己撸起袖子干了。
+
+**!!请先熟悉 支付宝/微信 说明文档!!请具有基本的 debug 能力!!**
+
+欢迎 Star,欢迎 PR!
+
+laravel 扩展包请 [传送至这里](https://github.com/yansongda/laravel-pay)
+
+QQ交流群:690027516
+
+## 特点
+- 丰富的事件系统
+- 命名不那么乱七八糟
+- 隐藏开发者不需要关注的细节
+- 根据支付宝、微信最新 API 开发而成
+- 高度抽象的类,免去各种拼json与xml的痛苦
+- 符合 PSR 标准,你可以各种方便的与你的框架集成
+- 文件结构清晰易理解,可以随心所欲添加本项目中没有的支付网关
+- 方法使用更优雅,不必再去研究那些奇怪的的方法名或者类名是做啥用的
+
+
+## 运行环境
+- PHP 7.0+ (v2.8.0 开始 >= 7.1.3)
+- composer
+
+> php5 请使用 v1.x 版本[https://github.com/yansongda/pay/tree/v1.x](https://github.com/yansongda/pay/tree/v1.x)
+
+
+## 支持的支付方法
+### 1、支付宝
+- 电脑支付
+- 手机网站支付
+- APP 支付
+- 刷卡支付
+- 扫码支付
+- 账户转账
+- 小程序支付
+
+| method | 描述 |
+| :-------: | :-------: |
+| web | 电脑支付 |
+| wap | 手机网站支付 |
+| app | APP 支付 |
+| pos | 刷卡支付 |
+| scan | 扫码支付 |
+| transfer | 帐户转账 |
+| mini | 小程序支付 |
+
+### 2、微信
+- 公众号支付
+- 小程序支付
+- H5 支付
+- 扫码支付
+- 刷卡支付
+- APP 支付
+- 企业付款
+- 普通红包
+- 分裂红包
+
+| method | 描述 |
+| :-----: | :-------: |
+| mp | 公众号支付 |
+| miniapp | 小程序支付 |
+| wap | H5 支付 |
+| scan | 扫码支付 |
+| pos | 刷卡支付 |
+| app | APP 支付 |
+| transfer | 企业付款 |
+| redpack | 普通红包 |
+| groupRedpack | 分裂红包 |
+
+## 支持的方法
+所有网关均支持以下方法
+
+- find(array/string $order)
+说明:查找订单接口
+参数:`$order` 为 `string` 类型时,请传入系统订单号,对应支付宝或微信中的 `out_trade_no`; `array` 类型时,参数请参考支付宝或微信官方文档。
+返回:查询成功,返回 `Yansongda\Supports\Collection` 实例,可以通过 `$colletion->xxx` 或 `$collection['xxx']` 访问服务器返回的数据。
+异常:`GatewayException` 或 `InvalidSignException`
+
+- refund(array $order)
+说明:退款接口
+参数:`$order` 数组格式,退款参数。
+返回:退款成功,返回 `Yansongda\Supports\Collection` 实例,可以通过 `$colletion->xxx` 或 `$collection['xxx']` 访问服务器返回的数据。
+异常:`GatewayException` 或 `InvalidSignException`
+
+- cancel(array/string $order)
+说明:取消订单接口
+参数:`$order` 为 `string` 类型时,请传入系统订单号,对应支付宝或微信中的 `out_trade_no`; `array` 类型时,参数请参考支付宝或微信官方文档。
+返回:取消成功,返回 `Yansongda\Supports\Collection` 实例,可以通过 `$colletion->xxx` 或 `$collection['xxx']` 访问服务器返回的数据。
+异常:`GatewayException` 或 `InvalidSignException`
+
+- close(array/string $order)
+说明:关闭订单接口
+参数:`$order` 为 `string` 类型时,请传入系统订单号,对应支付宝或微信中的 `out_trade_no`; `array` 类型时,参数请参考支付宝或微信官方文档。
+返回:关闭成功,返回 `Yansongda\Supports\Collection` 实例,可以通过 `$colletion->xxx` 或 `$collection['xxx']` 访问服务器返回的数据。
+异常:`GatewayException` 或 `InvalidSignException`
+
+- verify()
+说明:验证服务器返回消息是否合法
+返回:验证成功,返回 `Yansongda\Supports\Collection` 实例,可以通过 `$colletion->xxx` 或 `$collection['xxx']` 访问服务器返回的数据。
+异常:`GatewayException` 或 `InvalidSignException`
+
+- PAYMETHOD(array $order)
+说明:进行支付;具体支付方法名称请参考「支持的支付方法」一栏
+返回:成功,返回 `Yansongda\Supports\Collection` 实例,可以通过 `$colletion->xxx` 或 `$collection['xxx']` 访问服务器返回的数据或 `Symfony\Component\HttpFoundation\Response` 实例,可通过 `return $response->send()`(laravel 框架中直接 `return $response`) 返回,具体请参考文档。
+异常:`GatewayException` 或 `InvalidSignException`
+
+## 安装
+```shell
+composer require yansongda/pay -vvv
+```
+
+## 使用说明
+
+### 支付宝
+```php
+ '2016082000295641',
+ 'notify_url' => 'http://yansongda.cn/notify.php',
+ 'return_url' => 'http://yansongda.cn/return.php',
+ 'ali_public_key' => 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuWJKrQ6SWvS6niI+4vEVZiYfjkCfLQfoFI2nCp9ZLDS42QtiL4Ccyx8scgc3nhVwmVRte8f57TFvGhvJD0upT4O5O/lRxmTjechXAorirVdAODpOu0mFfQV9y/T9o9hHnU+VmO5spoVb3umqpq6D/Pt8p25Yk852/w01VTIczrXC4QlrbOEe3sr1E9auoC7rgYjjCO6lZUIDjX/oBmNXZxhRDrYx4Yf5X7y8FRBFvygIE2FgxV4Yw+SL3QAa2m5MLcbusJpxOml9YVQfP8iSurx41PvvXUMo49JG3BDVernaCYXQCoUJv9fJwbnfZd7J5YByC+5KM4sblJTq7bXZWQIDAQAB',
+ // 加密方式: **RSA2**
+ 'private_key' => 'MIIEpAIBAAKCAQEAs6+F2leOgOrvj9jTeDhb5q46GewOjqLBlGSs/bVL4Z3fMr3p+Q1Tux/6uogeVi/eHd84xvQdfpZ87A1SfoWnEGH5z15yorccxSOwWUI+q8gz51IWqjgZxhWKe31BxNZ+prnQpyeMBtE25fXp5nQZ/pftgePyUUvUZRcAUisswntobDQKbwx28VCXw5XB2A+lvYEvxmMv/QexYjwKK4M54j435TuC3UctZbnuynSPpOmCu45ZhEYXd4YMsGMdZE5/077ZU1aU7wx/gk07PiHImEOCDkzqsFo0Buc/knGcdOiUDvm2hn2y1XvwjyFOThsqCsQYi4JmwZdRa8kvOf57nwIDAQABAoIBAQCw5QCqln4VTrTvcW+msB1ReX57nJgsNfDLbV2dG8mLYQemBa9833DqDK6iynTLNq69y88ylose33o2TVtEccGp8Dqluv6yUAED14G6LexS43KtrXPgugAtsXE253ZDGUNwUggnN1i0MW2RcMqHdQ9ORDWvJUCeZj/AEafgPN8AyiLrZeL07jJz/uaRfAuNqkImCVIarKUX3HBCjl9TpuoMjcMhz/MsOmQ0agtCatO1eoH1sqv5Odvxb1i59c8Hvq/mGEXyRuoiDo05SE6IyXYXr84/Nf2xvVNHNQA6kTckj8shSi+HGM4mO1Y4Pbb7XcnxNkT0Inn6oJMSiy56P+CpAoGBAO1O+5FE1ZuVGuLb48cY+0lHCD+nhSBd66B5FrxgPYCkFOQWR7pWyfNDBlmO3SSooQ8TQXA25blrkDxzOAEGX57EPiipXr/hy5e+WNoukpy09rsO1TMsvC+v0FXLvZ+TIAkqfnYBgaT56ku7yZ8aFGMwdCPL7WJYAwUIcZX8wZ3dAoGBAMHWplAqhe4bfkGOEEpfs6VvEQxCqYMYVyR65K0rI1LiDZn6Ij8fdVtwMjGKFSZZTspmsqnbbuCE/VTyDzF4NpAxdm3cBtZACv1Lpu2Om+aTzhK2PI6WTDVTKAJBYegXaahBCqVbSxieR62IWtmOMjggTtAKWZ1P5LQcRwdkaB2rAoGAWnAPT318Kp7YcDx8whOzMGnxqtCc24jvk2iSUZgb2Dqv+3zCOTF6JUsV0Guxu5bISoZ8GdfSFKf5gBAo97sGFeuUBMsHYPkcLehM1FmLZk1Q+ljcx3P1A/ds3kWXLolTXCrlpvNMBSN5NwOKAyhdPK/qkvnUrfX8sJ5XK2H4J8ECgYAGIZ0HIiE0Y+g9eJnpUFelXvsCEUW9YNK4065SD/BBGedmPHRC3OLgbo8X5A9BNEf6vP7fwpIiRfKhcjqqzOuk6fueA/yvYD04v+Da2MzzoS8+hkcqF3T3pta4I4tORRdRfCUzD80zTSZlRc/h286Y2eTETd+By1onnFFe2X01mwKBgQDaxo4PBcLL2OyVT5DoXiIdTCJ8KNZL9+kV1aiBuOWxnRgkDjPngslzNa1bK+klGgJNYDbQqohKNn1HeFX3mYNfCUpuSnD2Yag53Dd/1DLO+NxzwvTu4D6DCUnMMMBVaF42ig31Bs0jI3JQZVqeeFzSET8fkoFopJf3G6UXlrIEAQ==',
+ 'log' => [ // optional
+ 'file' => './logs/alipay.log',
+ 'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug
+ 'type' => 'single', // optional, 可选 daily.
+ 'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
+ ],
+ 'http' => [ // optional
+ 'timeout' => 5.0,
+ 'connect_timeout' => 5.0,
+ // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
+ ],
+ 'mode' => 'dev', // optional,设置此参数,将进入沙箱模式
+ ];
+
+ public function index()
+ {
+ $order = [
+ 'out_trade_no' => time(),
+ 'total_amount' => '1',
+ 'subject' => 'test subject - 测试',
+ ];
+
+ $alipay = Pay::alipay($this->config)->web($order);
+
+ return $alipay->send();// laravel 框架中请直接 `return $alipay`
+ }
+
+ public function return()
+ {
+ $data = Pay::alipay($this->config)->verify(); // 是的,验签就这么简单!
+
+ // 订单号:$data->out_trade_no
+ // 支付宝交易号:$data->trade_no
+ // 订单总金额:$data->total_amount
+ }
+
+ public function notify()
+ {
+ $alipay = Pay::alipay($this->config);
+
+ try{
+ $data = $alipay->verify(); // 是的,验签就这么简单!
+
+ // 请自行对 trade_status 进行判断及其它逻辑进行判断,在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。
+ // 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号;
+ // 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额);
+ // 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email);
+ // 4、验证app_id是否为该商户本身。
+ // 5、其它业务逻辑情况
+
+ Log::debug('Alipay notify', $data->all());
+ } catch (\Exception $e) {
+ // $e->getMessage();
+ }
+
+ return $alipay->success()->send();// laravel 框架中请直接 `return $alipay->success()`
+ }
+}
+```
+
+### 微信
+```php
+ 'wxb3fxxxxxxxxxxx', // APP APPID
+ 'app_id' => 'wxb3fxxxxxxxxxxx', // 公众号 APPID
+ 'miniapp_id' => 'wxb3fxxxxxxxxxxx', // 小程序 APPID
+ 'mch_id' => '14577xxxx',
+ 'key' => 'mF2suE9sU6Mk1Cxxxxxxxxxxx',
+ 'notify_url' => 'http://yanda.net.cn/notify.php',
+ 'cert_client' => './cert/apiclient_cert.pem', // optional,退款等情况时用到
+ 'cert_key' => './cert/apiclient_key.pem',// optional,退款等情况时用到
+ 'log' => [ // optional
+ 'file' => './logs/wechat.log',
+ 'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug
+ 'type' => 'single', // optional, 可选 daily.
+ 'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
+ ],
+ 'http' => [ // optional
+ 'timeout' => 5.0,
+ 'connect_timeout' => 5.0,
+ // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
+ ],
+ 'mode' => 'dev', // optional, dev/hk;当为 `hk` 时,为香港 gateway。
+ ];
+
+ public function index()
+ {
+ $order = [
+ 'out_trade_no' => time(),
+ 'total_fee' => '1', // **单位:分**
+ 'body' => 'test body - 测试',
+ 'openid' => 'onkVf1FjWS5SBIixxxxxxx',
+ ];
+
+ $pay = Pay::wechat($this->config)->mp($order);
+
+ // $pay->appId
+ // $pay->timeStamp
+ // $pay->nonceStr
+ // $pay->package
+ // $pay->signType
+ }
+
+ public function notify()
+ {
+ $pay = Pay::wechat($this->config);
+
+ try{
+ $data = $pay->verify(); // 是的,验签就这么简单!
+
+ Log::debug('Wechat notify', $data->all());
+ } catch (\Exception $e) {
+ // $e->getMessage();
+ }
+
+ return $pay->success()->send();// laravel 框架中请直接 `return $pay->success()`
+ }
+}
+```
+
+## 事件系统
+[请见详细文档](http://pay.yansongda.cn)
+
+## 详细文档
+[详细说明文档](http://pay.yansongda.cn)
+
+## 错误
+如果在调用相关支付网关 API 时有错误产生,会抛出 `GatewayException`,`InvalidSignException` 错误,可以通过 `$e->getMessage()` 查看,同时,也可通过 `$e->raw` 查看调用 API 后返回的原始数据,该值为数组格式。
+
+### 所有异常
+
+* Yansongda\Pay\Exceptions\InvalidGatewayException ,表示使用了除本 SDK 支持的支付网关。
+* Yansongda\Pay\Exceptions\InvalidSignException ,表示验签失败。
+* Yansongda\Pay\Exceptions\InvalidConfigException ,表示缺少配置参数,如,`ali_public_key`, `private_key` 等。
+* Yansongda\Pay\Exceptions\GatewayException ,表示支付宝/微信服务器返回的数据非正常结果,例如,参数错误,对账单不存在等。
+
+
+## 代码贡献
+由于测试及使用环境的限制,本项目中只开发了「支付宝」和「微信支付」的相关支付网关。
+
+如果您有其它支付网关的需求,或者发现本项目中需要改进的代码,**_欢迎 Fork 并提交 PR!_**
+
+## 赏一杯咖啡吧
+
+
+
+## LICENSE
+MIT
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/composer.json b/addons/weliam_smartcity/vendor/yansongda/pay/composer.json
new file mode 100644
index 0000000..f61faac
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/composer.json
@@ -0,0 +1,41 @@
+{
+ "name": "yansongda/pay",
+ "description": "专注 Alipay 和 WeChat 的支付扩展包",
+ "keywords": ["alipay", "wechat", "pay"],
+ "type": "library",
+ "support": {
+ "issues": "https://github.com/yansongda/pay/issues",
+ "source": "https://github.com/yansongda/pay"
+ },
+ "authors": [
+ {
+ "name": "yansongda",
+ "email": "me@yansongda.cn"
+ }
+ ],
+ "require": {
+ "php": ">=7.1.3",
+ "ext-openssl": "*",
+ "ext-simplexml":"*",
+ "ext-libxml": "*",
+ "ext-json": "*",
+ "yansongda/supports": "^1.8",
+ "symfony/http-foundation": "^4.0",
+ "symfony/event-dispatcher": "^4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.5",
+ "mockery/mockery": "^1.2"
+ },
+ "autoload": {
+ "psr-4": {
+ "Yansongda\\Pay\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Yansongda\\Pay\\Tests\\": "tests"
+ }
+ },
+ "license": "MIT"
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/phpunit.xml.dist b/addons/weliam_smartcity/vendor/yansongda/pay/phpunit.xml.dist
new file mode 100644
index 0000000..e47284c
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/phpunit.xml.dist
@@ -0,0 +1,21 @@
+
+
+
+
+ ./tests/
+
+
+
+
+ src/
+
+
+
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Contracts/GatewayApplicationInterface.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Contracts/GatewayApplicationInterface.php
new file mode 100644
index 0000000..72cd480
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Contracts/GatewayApplicationInterface.php
@@ -0,0 +1,87 @@
+
+ *
+ * @param string $gateway
+ * @param array $params
+ *
+ * @return Collection|Response
+ */
+ public function pay($gateway, $params);
+
+ /**
+ * Query an order.
+ *
+ * @author yansongda
+ *
+ * @param string|array $order
+ * @param string $type
+ *
+ * @return Collection
+ */
+ public function find($order, string $type);
+
+ /**
+ * Refund an order.
+ *
+ * @author yansongda
+ *
+ * @param array $order
+ *
+ * @return Collection
+ */
+ public function refund(array $order);
+
+ /**
+ * Cancel an order.
+ *
+ * @author yansongda
+ *
+ * @param string|array $order
+ *
+ * @return Collection
+ */
+ public function cancel($order);
+
+ /**
+ * Close an order.
+ *
+ * @author yansongda
+ *
+ * @param string|array $order
+ *
+ * @return Collection
+ */
+ public function close($order);
+
+ /**
+ * Verify a request.
+ *
+ * @author yansongda
+ *
+ * @param string|array|null $content
+ * @param bool $refund
+ *
+ * @return Collection
+ */
+ public function verify($content, bool $refund);
+
+ /**
+ * Echo success to server.
+ *
+ * @author yansongda
+ *
+ * @return Response
+ */
+ public function success();
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Contracts/GatewayInterface.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Contracts/GatewayInterface.php
new file mode 100644
index 0000000..fb165ab
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Contracts/GatewayInterface.php
@@ -0,0 +1,21 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @return Collection|Response
+ */
+ public function pay($endpoint, array $payload);
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Events.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events.php
new file mode 100644
index 0000000..e6f6dec
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events.php
@@ -0,0 +1,106 @@
+
+ *
+ * @method static Event dispatch(Event $event) Dispatches an event to all registered listeners
+ * @method static array getListeners($eventName = null) Gets the listeners of a specific event or all listeners sorted by descending priority.
+ * @method static int|void getListenerPriority($eventName, $listener) Gets the listener priority for a specific event.
+ * @method static bool hasListeners($eventName = null) Checks whether an event has any registered listeners.
+ * @method static void addListener($eventName, $listener, $priority = 0) Adds an event listener that listens on the specified events.
+ * @method static removeListener($eventName, $listener) Removes an event listener from the specified events.
+ * @method static void addSubscriber(EventSubscriberInterface $subscriber) Adds an event subscriber.
+ * @method static void removeSubscriber(EventSubscriberInterface $subscriber)
+ */
+class Events
+{
+ /**
+ * dispatcher.
+ *
+ * @var EventDispatcher
+ */
+ protected static $dispatcher;
+
+ /**
+ * Forward call.
+ *
+ * @author yansongda
+ *
+ * @param string $method
+ * @param array $args
+ *
+ * @throws Exception
+ *
+ * @return mixed
+ */
+ public static function __callStatic($method, $args)
+ {
+ return call_user_func_array([self::getDispatcher(), $method], $args);
+ }
+
+ /**
+ * Forward call.
+ *
+ * @author yansongda
+ *
+ * @param string $method
+ * @param array $args
+ *
+ * @throws Exception
+ *
+ * @return mixed
+ */
+ public function __call($method, $args)
+ {
+ return call_user_func_array([self::getDispatcher(), $method], $args);
+ }
+
+ /**
+ * setDispatcher.
+ *
+ * @author yansongda
+ *
+ * @param EventDispatcher $dispatcher
+ *
+ * @return void
+ */
+ public static function setDispatcher(EventDispatcher $dispatcher)
+ {
+ self::$dispatcher = $dispatcher;
+ }
+
+ /**
+ * getDispatcher.
+ *
+ * @author yansongda
+ *
+ * @return EventDispatcher
+ */
+ public static function getDispatcher(): EventDispatcher
+ {
+ if (self::$dispatcher) {
+ return self::$dispatcher;
+ }
+
+ return self::$dispatcher = self::createDispatcher();
+ }
+
+ /**
+ * createDispatcher.
+ *
+ * @author yansongda
+ *
+ * @return EventDispatcher
+ */
+ public static function createDispatcher(): EventDispatcher
+ {
+ return new EventDispatcher();
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/ApiRequested.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/ApiRequested.php
new file mode 100644
index 0000000..20eb3d5
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/ApiRequested.php
@@ -0,0 +1,36 @@
+endpoint = $endpoint;
+ $this->result = $result;
+
+ parent::__construct($driver, $gateway);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/ApiRequesting.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/ApiRequesting.php
new file mode 100644
index 0000000..499746a
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/ApiRequesting.php
@@ -0,0 +1,36 @@
+endpoint = $endpoint;
+ $this->payload = $payload;
+
+ parent::__construct($driver, $gateway);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/Event.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/Event.php
new file mode 100644
index 0000000..9d1c502
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/Event.php
@@ -0,0 +1,43 @@
+
+ *
+ * @param string $driver
+ * @param string $gateway
+ */
+ public function __construct(string $driver, string $gateway)
+ {
+ $this->driver = $driver;
+ $this->gateway = $gateway;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/MethodCalled.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/MethodCalled.php
new file mode 100644
index 0000000..424b99b
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/MethodCalled.php
@@ -0,0 +1,38 @@
+
+ *
+ * @param string $driver
+ * @param string $gateway
+ * @param string $endpoint
+ * @param array $payload
+ */
+ public function __construct(string $driver, string $gateway, string $endpoint, array $payload = [])
+ {
+ $this->endpoint = $endpoint;
+ $this->payload = $payload;
+
+ parent::__construct($driver, $gateway);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/PayStarted.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/PayStarted.php
new file mode 100644
index 0000000..c7f2c0f
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/PayStarted.php
@@ -0,0 +1,36 @@
+endpoint = $endpoint;
+ $this->payload = $payload;
+
+ parent::__construct($driver, $gateway);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/PayStarting.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/PayStarting.php
new file mode 100644
index 0000000..c44a540
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/PayStarting.php
@@ -0,0 +1,27 @@
+params = $params;
+
+ parent::__construct($driver, $gateway);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/RequestReceived.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/RequestReceived.php
new file mode 100644
index 0000000..d37c461
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/RequestReceived.php
@@ -0,0 +1,29 @@
+
+ *
+ * @param string $driver
+ * @param string $gateway
+ * @param array $data
+ */
+ public function __construct(string $driver, string $gateway, array $data)
+ {
+ $this->data = $data;
+
+ parent::__construct($driver, $gateway);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/SignFailed.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/SignFailed.php
new file mode 100644
index 0000000..8311864
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Events/SignFailed.php
@@ -0,0 +1,29 @@
+
+ *
+ * @param string $driver
+ * @param string $gateway
+ * @param array $data
+ */
+ public function __construct(string $driver, string $gateway, array $data)
+ {
+ $this->data = $data;
+
+ parent::__construct($driver, $gateway);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/BusinessException.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/BusinessException.php
new file mode 100644
index 0000000..8e94a4f
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/BusinessException.php
@@ -0,0 +1,19 @@
+
+ *
+ * @param string $message
+ * @param array|string $raw
+ */
+ public function __construct($message, $raw = [])
+ {
+ parent::__construct('ERROR_BUSINESS: '.$message, $raw, self::ERROR_BUSINESS);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/Exception.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/Exception.php
new file mode 100644
index 0000000..b5ddd0d
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/Exception.php
@@ -0,0 +1,44 @@
+
+ *
+ * @param string $message
+ * @param array|string $raw
+ * @param int|string $code
+ */
+ public function __construct($message = '', $raw = [], $code = self::UNKNOWN_ERROR)
+ {
+ $message = $message === '' ? 'Unknown Error' : $message;
+ $this->raw = is_array($raw) ? $raw : [$raw];
+
+ parent::__construct($message, intval($code));
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/GatewayException.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/GatewayException.php
new file mode 100644
index 0000000..e844801
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/GatewayException.php
@@ -0,0 +1,20 @@
+
+ *
+ * @param string $message
+ * @param array|string $raw
+ * @param int $code
+ */
+ public function __construct($message, $raw = [], $code = self::ERROR_GATEWAY)
+ {
+ parent::__construct('ERROR_GATEWAY: '.$message, $raw, $code);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/InvalidArgumentException.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/InvalidArgumentException.php
new file mode 100644
index 0000000..2ecb16b
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/InvalidArgumentException.php
@@ -0,0 +1,19 @@
+
+ *
+ * @param string $message
+ * @param array|string $raw
+ */
+ public function __construct($message, $raw = [])
+ {
+ parent::__construct('INVALID_ARGUMENT: '.$message, $raw, self::INVALID_ARGUMENT);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/InvalidConfigException.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/InvalidConfigException.php
new file mode 100644
index 0000000..5719310
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/InvalidConfigException.php
@@ -0,0 +1,19 @@
+
+ *
+ * @param string $message
+ * @param array|string $raw
+ */
+ public function __construct($message, $raw = [])
+ {
+ parent::__construct('INVALID_CONFIG: '.$message, $raw, self::INVALID_CONFIG);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/InvalidGatewayException.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/InvalidGatewayException.php
new file mode 100644
index 0000000..3f4067d
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/InvalidGatewayException.php
@@ -0,0 +1,19 @@
+
+ *
+ * @param string $message
+ * @param array|string $raw
+ */
+ public function __construct($message, $raw = [])
+ {
+ parent::__construct('INVALID_GATEWAY: '.$message, $raw, self::INVALID_GATEWAY);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/InvalidSignException.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/InvalidSignException.php
new file mode 100644
index 0000000..135c8a5
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Exceptions/InvalidSignException.php
@@ -0,0 +1,19 @@
+
+ *
+ * @param string $message
+ * @param array|string $raw
+ */
+ public function __construct($message, $raw = [])
+ {
+ parent::__construct('INVALID_SIGN: '.$message, $raw, self::INVALID_SIGN);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay.php
new file mode 100644
index 0000000..ebd9038
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay.php
@@ -0,0 +1,446 @@
+ 'https://openapi.alipay.com/gateway.do?charset=utf-8',
+ self::MODE_DEV => 'https://openapi.alipaydev.com/gateway.do?charset=utf-8',
+ ];
+
+ /**
+ * Alipay payload.
+ *
+ * @var array
+ */
+ protected $payload;
+
+ /**
+ * Alipay gateway.
+ *
+ * @var string
+ */
+ protected $gateway;
+
+ /**
+ * extends.
+ *
+ * @var array
+ */
+ protected $extends;
+
+ /**
+ * Bootstrap.
+ *
+ * @author yansongda
+ *
+ * @param Config $config
+ */
+ public function __construct(Config $config)
+ {
+ $this->gateway = Support::create($config)->getBaseUri();
+ $this->payload = [
+ 'app_id' => $config->get('app_id'),
+ 'method' => '',
+ 'format' => 'JSON',
+ 'charset' => 'utf-8',
+ 'sign_type' => 'RSA2',
+ 'version' => '1.0',
+ 'return_url' => $config->get('return_url'),
+ 'notify_url' => $config->get('notify_url'),
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'sign' => '',
+ 'biz_content' => '',
+ 'app_auth_token' => $config->get('app_auth_token'),
+ 'app_cert_sn' => $config->get('app_cert_sn'),
+ 'alipay_root_cert_sn' => $config->get('alipay_root_cert_sn'),
+
+ ];
+ }
+
+ /**
+ * Magic pay.
+ *
+ * @author yansongda
+ *
+ * @param string $method
+ * @param array $params
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidConfigException
+ * @throws InvalidGatewayException
+ * @throws InvalidSignException
+ *
+ * @return Response|Collection
+ */
+ public function __call($method, $params)
+ {
+ if (isset($this->extends[$method])) {
+ return $this->makeExtend($method, ...$params);
+ }
+
+ return $this->pay($method, ...$params);
+ }
+
+ /**
+ * Pay an order.
+ *
+ * @author yansongda
+ *
+ * @param string $gateway
+ * @param array $params
+ *
+ * @throws InvalidGatewayException
+ *
+ * @return Response|Collection
+ */
+ public function pay($gateway, $params = [])
+ {
+ Events::dispatch(new Events\PayStarting('Alipay', $gateway, $params));
+
+ $this->payload['return_url'] = $params['return_url'] ?? $this->payload['return_url'];
+ $this->payload['notify_url'] = $params['notify_url'] ?? $this->payload['notify_url'];
+
+ unset($params['return_url'], $params['notify_url']);
+
+ $this->payload['biz_content'] = json_encode($params);
+
+ $gateway = get_class($this).'\\'.Str::studly($gateway).'Gateway';
+
+ if (class_exists($gateway)) {
+ return $this->makePay($gateway);
+ }
+
+ throw new InvalidGatewayException("Pay Gateway [{$gateway}] not exists");
+ }
+
+ /**
+ * Verify sign.
+ *
+ * @author yansongda
+ *
+ * @param null|array $data
+ * @param bool $refund
+ *
+ * @throws InvalidSignException
+ * @throws InvalidConfigException
+ *
+ * @return Collection
+ */
+ public function verify($data = null, bool $refund = false): Collection
+ {
+ if (is_null($data)) {
+ $request = Request::createFromGlobals();
+
+ $data = $request->request->count() > 0 ? $request->request->all() : $request->query->all();
+ }
+
+ if (isset($data['fund_bill_list'])) {
+ $data['fund_bill_list'] = htmlspecialchars_decode($data['fund_bill_list']);
+ }
+
+ Events::dispatch(new Events\RequestReceived('Alipay', '', $data));
+
+ if (Support::verifySign($data)) {
+ return new Collection($data);
+ }
+
+ Events::dispatch(new Events\SignFailed('Alipay', '', $data));
+
+ throw new InvalidSignException('Alipay Sign Verify FAILED', $data);
+ }
+
+ /**
+ * Query an order.
+ *
+ * @author yansongda
+ *
+ * @param string|array $order
+ * @param string $type
+ *
+ * @throws GatewayException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function find($order, string $type = 'wap'): Collection
+ {
+ $gateway = get_class($this).'\\'.Str::studly($type).'Gateway';
+
+ if (!class_exists($gateway) || !is_callable([new $gateway(), 'find'])) {
+ throw new GatewayException("{$gateway} Done Not Exist Or Done Not Has FIND Method");
+ }
+
+ $config = call_user_func([new $gateway(), 'find'], $order);
+
+ $this->payload['method'] = $config['method'];
+ $this->payload['biz_content'] = $config['biz_content'];
+ $this->payload['sign'] = Support::generateSign($this->payload);
+
+ Events::dispatch(new Events\MethodCalled('Alipay', 'Find', $this->gateway, $this->payload));
+
+ return Support::requestApi($this->payload);
+ }
+
+ /**
+ * Refund an order.
+ *
+ * @author yansongda
+ *
+ * @param array $order
+ *
+ * @throws GatewayException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function refund(array $order): Collection
+ {
+ $this->payload['method'] = 'alipay.trade.refund';
+ $this->payload['biz_content'] = json_encode($order);
+ $this->payload['sign'] = Support::generateSign($this->payload);
+
+ Events::dispatch(new Events\MethodCalled('Alipay', 'Refund', $this->gateway, $this->payload));
+
+ return Support::requestApi($this->payload);
+ }
+
+ /**
+ * Cancel an order.
+ *
+ * @author yansongda
+ *
+ * @param array|string $order
+ *
+ * @throws GatewayException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function cancel($order): Collection
+ {
+ $this->payload['method'] = 'alipay.trade.cancel';
+ $this->payload['biz_content'] = json_encode(is_array($order) ? $order : ['out_trade_no' => $order]);
+ $this->payload['sign'] = Support::generateSign($this->payload);
+
+ Events::dispatch(new Events\MethodCalled('Alipay', 'Cancel', $this->gateway, $this->payload));
+
+ return Support::requestApi($this->payload);
+ }
+
+ /**
+ * Close an order.
+ *
+ * @param string|array $order
+ *
+ * @author yansongda
+ *
+ * @throws GatewayException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function close($order): Collection
+ {
+ $this->payload['method'] = 'alipay.trade.close';
+ $this->payload['biz_content'] = json_encode(is_array($order) ? $order : ['out_trade_no' => $order]);
+ $this->payload['sign'] = Support::generateSign($this->payload);
+
+ Events::dispatch(new Events\MethodCalled('Alipay', 'Close', $this->gateway, $this->payload));
+
+ return Support::requestApi($this->payload);
+ }
+
+ /**
+ * Download bill.
+ *
+ * @author yansongda
+ *
+ * @param string|array $bill
+ *
+ * @throws GatewayException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ *
+ * @return string
+ */
+ public function download($bill): string
+ {
+ $this->payload['method'] = 'alipay.data.dataservice.bill.downloadurl.query';
+ $this->payload['biz_content'] = json_encode(is_array($bill) ? $bill : ['bill_type' => 'trade', 'bill_date' => $bill]);
+ $this->payload['sign'] = Support::generateSign($this->payload);
+
+ Events::dispatch(new Events\MethodCalled('Alipay', 'Download', $this->gateway, $this->payload));
+
+ $result = Support::requestApi($this->payload);
+
+ return ($result instanceof Collection) ? $result->get('bill_download_url') : '';
+ }
+
+ /**
+ * Reply success to alipay.
+ *
+ * @author yansongda
+ *
+ * @return Response
+ */
+ public function success(): Response
+ {
+ Events::dispatch(new Events\MethodCalled('Alipay', 'Success', $this->gateway));
+
+ return Response::create('success');
+ }
+
+ /**
+ * extend.
+ *
+ * @author yansongda
+ *
+ * @param string $method
+ * @param callable $function
+ * @param bool $now
+ *
+ * @throws GatewayException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ * @throws InvalidArgumentException
+ *
+ * @return Collection|null
+ */
+ public function extend(string $method, callable $function, bool $now = true): ?Collection
+ {
+ if (!$now && !method_exists($this, $method)) {
+ $this->extends[$method] = $function;
+
+ return null;
+ }
+
+ $customize = $function($this->payload);
+
+ if (!is_array($customize) && !($customize instanceof Collection)) {
+ throw new InvalidArgumentException('Return Type Must Be Array Or Collection');
+ }
+
+ Events::dispatch(new Events\MethodCalled('Alipay', 'extend', $this->gateway, $customize));
+
+ if (is_array($customize)) {
+ $this->payload = $customize;
+ $this->payload['sign'] = Support::generateSign($this->payload);
+
+ return Support::requestApi($this->payload);
+ }
+
+ return $customize;
+ }
+
+ /**
+ * Make pay gateway.
+ *
+ * @author yansongda
+ *
+ * @param string $gateway
+ *
+ * @throws InvalidGatewayException
+ *
+ * @return Response|Collection
+ */
+ protected function makePay(string $gateway)
+ {
+ $app = new $gateway();
+
+ if ($app instanceof GatewayInterface) {
+ return $app->pay($this->gateway, array_filter($this->payload, function ($value) {
+ return $value !== '' && !is_null($value);
+ }));
+ }
+
+ throw new InvalidGatewayException("Pay Gateway [{$gateway}] Must Be An Instance Of GatewayInterface");
+ }
+
+ /**
+ * makeExtend.
+ *
+ * @author yansongda
+ *
+ * @param string $method
+ * @param array $params
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ protected function makeExtend(string $method, array ...$params): Collection
+ {
+ $params = count($params) >= 1 ? $params[0] : $params;
+
+ $function = $this->extends[$method];
+
+ $customize = $function($this->payload, $params);
+
+ if (!is_array($customize) && !($customize instanceof Collection)) {
+ throw new InvalidArgumentException('Return Type Must Be Array Or Collection');
+ }
+
+ Events::dispatch(new Events\MethodCalled(
+ 'Alipay',
+ 'extend - '.$method,
+ $this->gateway,
+ is_array($customize) ? $customize : $customize->toArray()
+ ));
+
+ if (is_array($customize)) {
+ $this->payload = $customize;
+ $this->payload['sign'] = Support::generateSign($this->payload);
+
+ return Support::requestApi($this->payload);
+ }
+
+ return $customize;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/AppGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/AppGateway.php
new file mode 100644
index 0000000..19b00a4
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/AppGateway.php
@@ -0,0 +1,37 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws InvalidConfigException
+ *
+ * @return Response
+ */
+ public function pay($endpoint, array $payload): Response
+ {
+ $payload['method'] = 'alipay.trade.app.pay';
+ $payload['biz_content'] = json_encode(array_merge(
+ json_decode($payload['biz_content'], true),
+ ['product_code' => 'QUICK_MSECURITY_PAY']
+ ));
+ $payload['sign'] = Support::generateSign($payload);
+
+ Events::dispatch(new Events\PayStarted('Alipay', 'App', $endpoint, $payload));
+
+ return Response::create(http_build_query($payload));
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/MiniGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/MiniGateway.php
new file mode 100644
index 0000000..1fcf260
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/MiniGateway.php
@@ -0,0 +1,45 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ *
+ * @link https://docs.alipay.com/mini/introduce/pay
+ *
+ * @return Collection
+ */
+ public function pay($endpoint, array $payload): Collection
+ {
+ if (empty(json_decode($payload['biz_content'], true)['buyer_id'])) {
+ throw new InvalidArgumentException('buyer_id required');
+ }
+
+ $payload['method'] = 'alipay.trade.create';
+ $payload['sign'] = Support::generateSign($payload);
+
+ Events::dispatch(new Events\PayStarted('Alipay', 'Mini', $endpoint, $payload));
+
+ return Support::requestApi($payload);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/PosGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/PosGateway.php
new file mode 100644
index 0000000..40c345b
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/PosGateway.php
@@ -0,0 +1,44 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function pay($endpoint, array $payload): Collection
+ {
+ $payload['method'] = 'alipay.trade.pay';
+ $payload['biz_content'] = json_encode(array_merge(
+ json_decode($payload['biz_content'], true),
+ [
+ 'product_code' => 'FACE_TO_FACE_PAYMENT',
+ 'scene' => 'bar_code',
+ ]
+ ));
+ $payload['sign'] = Support::generateSign($payload);
+
+ Events::dispatch(new Events\PayStarted('Alipay', 'Pos', $endpoint, $payload));
+
+ return Support::requestApi($payload);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/RefundGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/RefundGateway.php
new file mode 100644
index 0000000..c8d202f
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/RefundGateway.php
@@ -0,0 +1,23 @@
+
+ *
+ * @param $order
+ *
+ * @return array
+ */
+ public function find($order): array
+ {
+ return [
+ 'method' => 'alipay.trade.fastpay.refund.query',
+ 'biz_content' => json_encode(is_array($order) ? $order : ['out_trade_no' => $order]),
+ ];
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/ScanGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/ScanGateway.php
new file mode 100644
index 0000000..4aa07e6
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/ScanGateway.php
@@ -0,0 +1,41 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function pay($endpoint, array $payload): Collection
+ {
+ $payload['method'] = 'alipay.trade.precreate';
+ $payload['biz_content'] = json_encode(array_merge(
+ json_decode($payload['biz_content'], true),
+ ['product_code' => '']
+ ));
+ $payload['sign'] = Support::generateSign($payload);
+
+ Events::dispatch(new Events\PayStarted('Alipay', 'Scan', $endpoint, $payload));
+
+ return Support::requestApi($payload);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/Support.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/Support.php
new file mode 100644
index 0000000..abf7dc5
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/Support.php
@@ -0,0 +1,356 @@
+
+ *
+ * @property string app_id alipay app_id
+ * @property string ali_public_key
+ * @property string private_key
+ * @property array http http options
+ * @property string mode current mode
+ * @property array log log options
+ */
+class Support
+{
+ use HasHttpRequest;
+
+ /**
+ * Alipay gateway.
+ *
+ * @var string
+ */
+ protected $baseUri;
+
+ /**
+ * Config.
+ *
+ * @var Config
+ */
+ protected $config;
+
+ /**
+ * Instance.
+ *
+ * @var Support
+ */
+ private static $instance;
+
+ /**
+ * Bootstrap.
+ *
+ * @author yansongda
+ *
+ * @param Config $config
+ */
+ private function __construct(Config $config)
+ {
+ $this->baseUri = Alipay::URL[$config->get('mode', Alipay::MODE_NORMAL)];
+ $this->config = $config;
+
+ $this->setHttpOptions();
+ }
+
+ /**
+ * __get.
+ *
+ * @author yansongda
+ *
+ * @param $key
+ *
+ * @return mixed|null|Config
+ */
+ public function __get($key)
+ {
+ return $this->getConfig($key);
+ }
+
+ /**
+ * create.
+ *
+ * @author yansongda
+ *
+ * @param Config $config
+ *
+ * @return Support
+ */
+ public static function create(Config $config)
+ {
+ if (php_sapi_name() === 'cli' || !(self::$instance instanceof self)) {
+ self::$instance = new self($config);
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * clear.
+ *
+ * @author yansongda
+ *
+ * @return void
+ */
+ public function clear()
+ {
+ self::$instance = null;
+ }
+
+ /**
+ * Get Alipay API result.
+ *
+ * @author yansongda
+ *
+ * @param array $data
+ *
+ * @throws GatewayException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public static function requestApi(array $data): Collection
+ {
+ Events::dispatch(new Events\ApiRequesting('Alipay', '', self::$instance->getBaseUri(), $data));
+
+ $data = array_filter($data, function ($value) {
+ return ($value == '' || is_null($value)) ? false : true;
+ });
+
+ $result = json_decode(self::$instance->post('', $data), true);
+
+ Events::dispatch(new Events\ApiRequested('Alipay', '', self::$instance->getBaseUri(), $result));
+
+ return self::processingApiResult($data, $result);
+ }
+
+ /**
+ * Generate sign.
+ *
+ * @author yansongda
+ *
+ * @param array $params
+ *
+ * @throws InvalidConfigException
+ *
+ * @return string
+ */
+ public static function generateSign(array $params): string
+ {
+ $privateKey = self::$instance->private_key;
+
+ if (is_null($privateKey)) {
+ throw new InvalidConfigException('Missing Alipay Config -- [private_key]');
+ }
+
+ if (Str::endsWith($privateKey, '.pem')) {
+ $privateKey = openssl_pkey_get_private(
+ Str::startsWith($privateKey, 'file://') ? $privateKey : 'file://'.$privateKey
+ );
+ } else {
+ $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n".
+ wordwrap($privateKey, 64, "\n", true).
+ "\n-----END RSA PRIVATE KEY-----";
+ }
+
+ openssl_sign(self::getSignContent($params), $sign, $privateKey, OPENSSL_ALGO_SHA256);
+
+ $sign = base64_encode($sign);
+
+ Log::debug('Alipay Generate Sign', [$params, $sign]);
+
+ if (is_resource($privateKey)) {
+ openssl_free_key($privateKey);
+ }
+
+ return $sign;
+ }
+
+ /**
+ * Verify sign.
+ *
+ * @author yansongda
+ *
+ * @param array $data
+ * @param bool $sync
+ * @param string|null $sign
+ *
+ * @throws InvalidConfigException
+ *
+ * @return bool
+ */
+ public static function verifySign(array $data, $sync = false, $sign = null): bool
+ {
+ $publicKey = self::$instance->ali_public_key;
+
+ if (is_null($publicKey)) {
+ throw new InvalidConfigException('Missing Alipay Config -- [ali_public_key]');
+ }
+
+ if (Str::endsWith($publicKey, '.pem')) {
+ $publicKey = openssl_pkey_get_public(
+ Str::startsWith($publicKey, 'file://') ? $publicKey : 'file://'.$publicKey
+ );
+ } else {
+ $publicKey = "-----BEGIN PUBLIC KEY-----\n".
+ wordwrap($publicKey, 64, "\n", true).
+ "\n-----END PUBLIC KEY-----";
+ }
+
+ $sign = $sign ?? $data['sign'];
+
+ $toVerify = $sync ? json_encode($data, JSON_UNESCAPED_UNICODE) : self::getSignContent($data, true);
+
+ $isVerify = openssl_verify($toVerify, base64_decode($sign), $publicKey, OPENSSL_ALGO_SHA256) === 1;
+
+ if (is_resource($publicKey)) {
+ openssl_free_key($publicKey);
+ }
+
+ return $isVerify;
+ }
+
+ /**
+ * Get signContent that is to be signed.
+ *
+ * @author yansongda
+ *
+ * @param array $data
+ * @param bool $verify
+ *
+ * @return string
+ */
+ public static function getSignContent(array $data, $verify = false): string
+ {
+ ksort($data);
+
+ $stringToBeSigned = '';
+ foreach ($data as $k => $v) {
+ if ($verify && $k != 'sign' && $k != 'sign_type') {
+ $stringToBeSigned .= $k.'='.$v.'&';
+ }
+ if (!$verify && $v !== '' && !is_null($v) && $k != 'sign' && '@' != substr($v, 0, 1)) {
+ $stringToBeSigned .= $k.'='.$v.'&';
+ }
+ }
+
+ Log::debug('Alipay Generate Sign Content Before Trim', [$data, $stringToBeSigned]);
+
+ return trim($stringToBeSigned, '&');
+ }
+
+ /**
+ * Convert encoding.
+ *
+ * @author yansongda
+ *
+ * @param string|array $data
+ * @param string $to
+ * @param string $from
+ *
+ * @return array
+ */
+ public static function encoding($data, $to = 'utf-8', $from = 'gb2312'): array
+ {
+ return Arr::encoding((array) $data, $to, $from);
+ }
+
+ /**
+ * Get service config.
+ *
+ * @author yansongda
+ *
+ * @param null|string $key
+ * @param null|mixed $default
+ *
+ * @return mixed|null
+ */
+ public function getConfig($key = null, $default = null)
+ {
+ if (is_null($key)) {
+ return $this->config->all();
+ }
+
+ if ($this->config->has($key)) {
+ return $this->config[$key];
+ }
+
+ return $default;
+ }
+
+ /**
+ * Get Base Uri.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ public function getBaseUri()
+ {
+ return $this->baseUri;
+ }
+
+ /**
+ * processingApiResult.
+ *
+ * @author yansongda
+ *
+ * @param $data
+ * @param $result
+ *
+ * @throws GatewayException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ protected static function processingApiResult($data, $result): Collection
+ {
+ $method = str_replace('.', '_', $data['method']).'_response';
+
+ if (!isset($result['sign']) || $result[$method]['code'] != '10000') {
+ throw new GatewayException(
+ 'Get Alipay API Error:'.$result[$method]['msg'].
+ (isset($result[$method]['sub_code']) ? (' - '.$result[$method]['sub_code']) : ''),
+ $result
+ );
+ }
+
+ if (self::verifySign($result[$method], true, $result['sign'])) {
+ return new Collection($result[$method]);
+ }
+
+ Events::dispatch(new Events\SignFailed('Alipay', '', $result));
+
+ throw new InvalidSignException('Alipay Sign Verify FAILED', $result);
+ }
+
+ /**
+ * Set Http options.
+ *
+ * @author yansongda
+ *
+ * @return self
+ */
+ protected function setHttpOptions(): self
+ {
+ if ($this->config->has('http') && is_array($this->config->get('http'))) {
+ $this->config->forget('http.base_uri');
+ $this->httpOptions = $this->config->get('http');
+ }
+
+ return $this;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/TransferGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/TransferGateway.php
new file mode 100644
index 0000000..022b882
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/TransferGateway.php
@@ -0,0 +1,67 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function pay($endpoint, array $payload): Collection
+ {
+ if($payload['version'] > 0){
+ $payload['method'] = 'alipay.fund.trans.uni.transfer';
+ $payload['biz_content'] = json_encode(array_merge(
+ json_decode($payload['biz_content'], true),
+ ['product_code' => 'TRANS_ACCOUNT_NO_PWD']
+ ));
+ }else{
+ $payload['method'] = 'alipay.fund.trans.toaccount.transfer';
+ $payload['biz_content'] = json_encode(array_merge(
+ json_decode($payload['biz_content'], true),
+ ['product_code' => '']
+ ));
+ }
+ unset($payload['version']);
+ $payload['sign'] = Support::generateSign($payload);
+
+ Events::dispatch(new Events\PayStarted('Alipay', 'Transfer', $endpoint, $payload));
+
+ return Support::requestApi($payload);
+ }
+
+ /**
+ * Find.
+ *
+ * @author yansongda
+ *
+ * @param $order
+ *
+ * @return array
+ */
+ public function find($order): array
+ {
+ return [
+ 'method' => 'alipay.fund.trans.order.query',
+ 'biz_content' => json_encode(is_array($order) ? $order : ['out_biz_no' => $order]),
+ ];
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/WapGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/WapGateway.php
new file mode 100644
index 0000000..9d81ec3
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/WapGateway.php
@@ -0,0 +1,30 @@
+
+ *
+ * @return string
+ */
+ protected function getMethod(): string
+ {
+ return 'alipay.trade.wap.pay';
+ }
+
+ /**
+ * Get productCode config.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ protected function getProductCode(): string
+ {
+ return 'QUICK_WAP_WAY';
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/WebGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/WebGateway.php
new file mode 100644
index 0000000..b949035
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Alipay/WebGateway.php
@@ -0,0 +1,111 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws InvalidConfigException
+ *
+ * @return Response
+ */
+ public function pay($endpoint, array $payload): Response
+ {
+ $biz_array = json_decode($payload['biz_content'], true);
+ $biz_array['product_code'] = $this->getProductCode();
+
+ $method = $biz_array['http_method'] ?? 'POST';
+
+ unset($biz_array['http_method']);
+
+ $payload['method'] = $this->getMethod();
+ $payload['biz_content'] = json_encode($biz_array);
+ $payload['sign'] = Support::generateSign($payload);
+
+ Events::dispatch(new Events\PayStarted('Alipay', 'Web/Wap', $endpoint, $payload));
+
+ return $this->buildPayHtml($endpoint, $payload, $method);
+ }
+
+ /**
+ * Find.
+ *
+ * @author yansongda
+ *
+ * @param $order
+ *
+ * @return array
+ */
+ public function find($order): array
+ {
+ return [
+ 'method' => 'alipay.trade.query',
+ 'biz_content' => json_encode(is_array($order) ? $order : ['out_trade_no' => $order]),
+ ];
+ }
+
+ /**
+ * Build Html response.
+ *
+ * @author yansongda
+ *
+ * @param string $endpoint
+ * @param array $payload
+ * @param string $method
+ *
+ * @return Response
+ */
+ protected function buildPayHtml($endpoint, $payload, $method = 'POST'): Response
+ {
+ if (strtoupper($method) === 'GET') {
+ return RedirectResponse::create($endpoint.'&'.http_build_query($payload));
+ }
+
+ $sHtml = "";
+ $sHtml .= "";
+
+ return Response::create($sHtml);
+ }
+
+ /**
+ * Get method config.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ protected function getMethod(): string
+ {
+ return 'alipay.trade.page.pay';
+ }
+
+ /**
+ * Get productCode config.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ protected function getProductCode(): string
+ {
+ return 'FAST_INSTANT_TRADE_PAY';
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat.php
new file mode 100644
index 0000000..3631462
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat.php
@@ -0,0 +1,387 @@
+ 'https://api.mch.weixin.qq.com/',
+ self::MODE_DEV => 'https://api.mch.weixin.qq.com/sandboxnew/',
+ self::MODE_HK => 'https://apihk.mch.weixin.qq.com/',
+ self::MODE_SERVICE => 'https://api.mch.weixin.qq.com/',
+ self::MODE_US => 'https://apius.mch.weixin.qq.com/',
+ ];
+
+ /**
+ * Wechat payload.
+ *
+ * @var array
+ */
+ protected $payload;
+
+ /**
+ * Wechat gateway.
+ *
+ * @var string
+ */
+ protected $gateway;
+
+ /**
+ * Bootstrap.
+ *
+ * @author yansongda
+ *
+ * @param Config $config
+ *
+ * @throws Exception
+ */
+ public function __construct(Config $config)
+ {
+ $this->gateway = Support::create($config)->getBaseUri();
+ $this->payload = [
+ 'appid' => $config->get('app_id', ''),
+ 'mch_id' => $config->get('mch_id', ''),
+ 'nonce_str' => Str::random(),
+ 'notify_url' => $config->get('notify_url', ''),
+ 'sign' => '',
+ 'trade_type' => '',
+ 'spbill_create_ip' => Request::createFromGlobals()->getClientIp(),
+ ];
+
+ if ($config->get('mode', self::MODE_NORMAL) === static::MODE_SERVICE) {
+ $this->payload = array_merge($this->payload, [
+ 'sub_mch_id' => $config->get('sub_mch_id'),
+ 'sub_appid' => $config->get('sub_app_id', ''),
+ ]);
+ }
+ }
+
+ /**
+ * Magic pay.
+ *
+ * @author yansongda
+ *
+ * @param string $method
+ * @param string $params
+ *
+ * @throws InvalidGatewayException
+ *
+ * @return Response|Collection
+ */
+ public function __call($method, $params)
+ {
+ return self::pay($method, ...$params);
+ }
+
+ /**
+ * Pay an order.
+ *
+ * @author yansongda
+ *
+ * @param string $gateway
+ * @param array $params
+ *
+ * @throws InvalidGatewayException
+ *
+ * @return Response|Collection
+ */
+ public function pay($gateway, $params = [])
+ {
+ Events::dispatch(new Events\PayStarting('Wechat', $gateway, $params));
+
+ $this->payload = array_merge($this->payload, $params);
+
+ $gateway = get_class($this).'\\'.Str::studly($gateway).'Gateway';
+
+ if (class_exists($gateway)) {
+ return $this->makePay($gateway);
+ }
+
+ throw new InvalidGatewayException("Pay Gateway [{$gateway}] Not Exists");
+ }
+
+ /**
+ * Verify data.
+ *
+ * @author yansongda
+ *
+ * @param string|null $content
+ * @param bool $refund
+ *
+ * @throws InvalidSignException
+ * @throws InvalidArgumentException
+ *
+ * @return Collection
+ */
+ public function verify($content = null, bool $refund = false): Collection
+ {
+ $content = $content ?? Request::createFromGlobals()->getContent();
+
+ Events::dispatch(new Events\RequestReceived('Wechat', '', [$content]));
+
+ $data = Support::fromXml($content);
+ if ($refund) {
+ $decrypt_data = Support::decryptRefundContents($data['req_info']);
+ $data = array_merge(Support::fromXml($decrypt_data), $data);
+ }
+
+ Log::debug('Resolved The Received Wechat Request Data', $data);
+
+ if ($refund || Support::generateSign($data) === $data['sign']) {
+ return new Collection($data);
+ }
+
+ Events::dispatch(new Events\SignFailed('Wechat', '', $data));
+
+ throw new InvalidSignException('Wechat Sign Verify FAILED', $data);
+ }
+
+ /**
+ * Query an order.
+ *
+ * @author yansongda
+ *
+ * @param string|array $order
+ * @param string $type
+ *
+ * @throws GatewayException
+ * @throws InvalidSignException
+ * @throws InvalidArgumentException
+ *
+ * @return Collection
+ */
+ public function find($order, string $type = 'wap'): Collection
+ {
+ if ($type != 'wap') {
+ unset($this->payload['spbill_create_ip']);
+ }
+
+ $gateway = get_class($this).'\\'.Str::studly($type).'Gateway';
+
+ if (!class_exists($gateway) || !is_callable([new $gateway(), 'find'])) {
+ throw new GatewayException("{$gateway} Done Not Exist Or Done Not Has FIND Method");
+ }
+
+ $config = call_user_func([new $gateway(), 'find'], $order);
+
+ $this->payload = Support::filterPayload($this->payload, $config['order']);
+
+ Events::dispatch(new Events\MethodCalled('Wechat', 'Find', $this->gateway, $this->payload));
+
+ return Support::requestApi(
+ $config['endpoint'],
+ $this->payload,
+ $config['cert']
+ );
+ }
+
+ /**
+ * Refund an order.
+ *
+ * @author yansongda
+ *
+ * @param array $order
+ *
+ * @throws GatewayException
+ * @throws InvalidSignException
+ * @throws InvalidArgumentException
+ *
+ * @return Collection
+ */
+ public function refund(array $order): Collection
+ {
+ $this->payload = Support::filterPayload($this->payload, $order, true);
+
+ Events::dispatch(new Events\MethodCalled('Wechat', 'Refund', $this->gateway, $this->payload));
+
+ return Support::requestApi(
+ 'secapi/pay/refund',
+ $this->payload,
+ true
+ );
+ }
+
+ /**
+ * Cancel an order.
+ *
+ * @author yansongda
+ *
+ * @param array $order
+ *
+ * @throws GatewayException
+ * @throws InvalidSignException
+ * @throws InvalidArgumentException
+ *
+ * @return Collection
+ */
+ public function cancel($order): Collection
+ {
+ unset($this->payload['spbill_create_ip']);
+
+ $this->payload = Support::filterPayload($this->payload, $order, true);
+
+ Events::dispatch(new Events\MethodCalled('Wechat', 'Cancel', $this->gateway, $this->payload));
+
+ return Support::requestApi(
+ 'secapi/pay/reverse',
+ $this->payload,
+ true
+ );
+ }
+
+ /**
+ * Close an order.
+ *
+ * @author yansongda
+ *
+ * @param string|array $order
+ *
+ * @throws GatewayException
+ * @throws InvalidSignException
+ * @throws InvalidArgumentException
+ *
+ * @return Collection
+ */
+ public function close($order): Collection
+ {
+ unset($this->payload['spbill_create_ip']);
+
+ $this->payload = Support::filterPayload($this->payload, $order);
+
+ Events::dispatch(new Events\MethodCalled('Wechat', 'Close', $this->gateway, $this->payload));
+
+ return Support::requestApi('pay/closeorder', $this->payload);
+ }
+
+ /**
+ * Echo success to server.
+ *
+ * @author yansongda
+ *
+ * @throws InvalidArgumentException
+ *
+ * @return Response
+ */
+ public function success(): Response
+ {
+ Events::dispatch(new Events\MethodCalled('Wechat', 'Success', $this->gateway));
+
+ return Response::create(
+ Support::toXml(['return_code' => 'SUCCESS', 'return_msg' => 'OK']),
+ 200,
+ ['Content-Type' => 'application/xml']
+ );
+ }
+
+ /**
+ * Download the bill.
+ *
+ * @author yansongda
+ *
+ * @param array $params
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ *
+ * @return string
+ */
+ public function download(array $params): string
+ {
+ unset($this->payload['spbill_create_ip']);
+
+ $this->payload = Support::filterPayload($this->payload, $params, true);
+
+ Events::dispatch(new Events\MethodCalled('Wechat', 'Download', $this->gateway, $this->payload));
+
+ $result = Support::getInstance()->post(
+ 'pay/downloadbill',
+ Support::getInstance()->toXml($this->payload)
+ );
+
+ if (is_array($result)) {
+ throw new GatewayException('Get Wechat API Error: '.$result['return_msg'], $result);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Make pay gateway.
+ *
+ * @author yansongda
+ *
+ * @param string $gateway
+ *
+ * @throws InvalidGatewayException
+ *
+ * @return Response|Collection
+ */
+ protected function makePay($gateway)
+ {
+ $app = new $gateway();
+
+ if ($app instanceof GatewayInterface) {
+ return $app->pay($this->gateway, array_filter($this->payload, function ($value) {
+ return $value !== '' && !is_null($value);
+ }));
+ }
+
+ throw new InvalidGatewayException("Pay Gateway [{$gateway}] Must Be An Instance Of GatewayInterface");
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/AppGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/AppGateway.php
new file mode 100644
index 0000000..afdb166
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/AppGateway.php
@@ -0,0 +1,67 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ * @throws Exception
+ *
+ * @return Response
+ */
+ public function pay($endpoint, array $payload): Response
+ {
+ $payload['appid'] = Support::getInstance()->appid;
+ $payload['trade_type'] = $this->getTradeType();
+
+ if ($this->mode === WeChat::MODE_SERVICE) {
+ $payload['sub_appid'] = Support::getInstance()->sub_appid;
+ }
+
+ $pay_request = [
+ 'appid' => $this->mode === WeChat::MODE_SERVICE ? $payload['sub_appid'] : $payload['appid'],
+ 'partnerid' => $this->mode === WeChat::MODE_SERVICE ? $payload['sub_mch_id'] : $payload['mch_id'],
+ 'prepayid' => $this->preOrder($payload)->get('prepay_id'),
+ 'timestamp' => strval(time()),
+ 'noncestr' => Str::random(),
+ 'package' => 'Sign=WXPay',
+ ];
+ $pay_request['sign'] = Support::generateSign($pay_request);
+
+ Events::dispatch(new Events\PayStarted('Wechat', 'App', $endpoint, $pay_request));
+
+ return JsonResponse::create($pay_request);
+ }
+
+ /**
+ * Get trade type config.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ protected function getTradeType(): string
+ {
+ return 'APP';
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/Gateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/Gateway.php
new file mode 100644
index 0000000..decf603
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/Gateway.php
@@ -0,0 +1,93 @@
+
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct()
+ {
+ $this->mode = Support::getInstance()->mode;
+ }
+
+ /**
+ * Pay an order.
+ *
+ * @author yansongda
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @return Collection
+ */
+ abstract public function pay($endpoint, array $payload);
+
+ /**
+ * Find.
+ *
+ * @author yansongda
+ *
+ * @param string|array $order
+ *
+ * @return array
+ */
+ public function find($order): array
+ {
+ return [
+ 'endpoint' => 'pay/orderquery',
+ 'order' => is_array($order) ? $order : ['out_trade_no' => $order],
+ 'cert' => false,
+ ];
+ }
+
+ /**
+ * Get trade type config.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ abstract protected function getTradeType();
+
+ /**
+ * Schedule an order.
+ *
+ * @author yansongda
+ *
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ protected function preOrder($payload): Collection
+ {
+ $payload['sign'] = Support::generateSign($payload);
+
+ Events::dispatch(new Events\MethodCalled('Wechat', 'PreOrder', '', $payload));
+
+ return Support::requestApi('pay/unifiedorder', $payload);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/GroupRedpackGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/GroupRedpackGateway.php
new file mode 100644
index 0000000..c22a1ad
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/GroupRedpackGateway.php
@@ -0,0 +1,62 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function pay($endpoint, array $payload): Collection
+ {
+ $payload['wxappid'] = $payload['appid'];
+ $payload['amt_type'] = 'ALL_RAND';
+
+ if ($this->mode === WeChat::MODE_SERVICE) {
+ $payload['msgappid'] = $payload['appid'];
+ }
+
+ unset($payload['appid'], $payload['trade_type'],
+ $payload['notify_url'], $payload['spbill_create_ip']);
+
+ $payload['sign'] = Support::generateSign($payload);
+
+ Events::dispatch(new Events\PayStarted('Wechat', 'Group Redpack', $endpoint, $payload));
+
+ return Support::requestApi(
+ 'mmpaymkttransfers/sendgroupredpack',
+ $payload,
+ true
+ );
+ }
+
+ /**
+ * Get trade type config.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ protected function getTradeType(): string
+ {
+ return '';
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/MiniappGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/MiniappGateway.php
new file mode 100644
index 0000000..e6f37ef
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/MiniappGateway.php
@@ -0,0 +1,38 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function pay($endpoint, array $payload): Collection
+ {
+ $payload['appid'] = Support::getInstance()->miniapp_id;
+
+ if ($this->mode === WeChat::MODE_SERVICE) {
+ $payload['sub_appid'] = Support::getInstance()->sub_miniapp_id;
+ $this->payRequestUseSubAppId = true;
+ }
+
+ return parent::pay($endpoint, $payload);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/MpGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/MpGateway.php
new file mode 100644
index 0000000..868cebe
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/MpGateway.php
@@ -0,0 +1,64 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ * @throws Exception
+ *
+ * @return Collection
+ */
+ public function pay($endpoint, array $payload): Collection
+ {
+ $payload['trade_type'] = $this->getTradeType();
+
+ $pay_request = [
+ 'appId' => !$this->payRequestUseSubAppId ? $payload['appid'] : $payload['sub_appid'],
+ 'timeStamp' => strval(time()),
+ 'nonceStr' => Str::random(),
+ 'package' => 'prepay_id='.$this->preOrder($payload)->get('prepay_id'),
+ 'signType' => 'MD5',
+ ];
+ $pay_request['paySign'] = Support::generateSign($pay_request);
+
+ Events::dispatch(new Events\PayStarted('Wechat', 'JSAPI', $endpoint, $pay_request));
+
+ return new Collection($pay_request);
+ }
+
+ /**
+ * Get trade type config.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ protected function getTradeType(): string
+ {
+ return 'JSAPI';
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/PosGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/PosGateway.php
new file mode 100644
index 0000000..00a29b7
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/PosGateway.php
@@ -0,0 +1,49 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function pay($endpoint, array $payload): Collection
+ {
+ unset($payload['trade_type'], $payload['notify_url']);
+
+ $payload['sign'] = Support::generateSign($payload);
+
+ Events::dispatch(new Events\PayStarted('Wechat', 'Pos', $endpoint, $payload));
+
+ return Support::requestApi('pay/micropay', $payload);
+ }
+
+ /**
+ * Get trade type config.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ protected function getTradeType(): string
+ {
+ return 'MICROPAY';
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/RedpackGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/RedpackGateway.php
new file mode 100644
index 0000000..4db8295
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/RedpackGateway.php
@@ -0,0 +1,73 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function pay($endpoint, array $payload): Collection
+ {
+
+
+
+ $payload['wxappid'] = $payload['appid'];
+
+ if (php_sapi_name() !== 'cli') {
+ $payload['client_ip'] = Request::createFromGlobals()->server->get('SERVER_ADDR');
+ }
+
+ if ($this->mode === WeChat::MODE_SERVICE) {
+ $payload['msgappid'] = $payload['appid'];
+ }
+ //判断是小程序红包 OR 公众号红包 默认公众号
+ $api = 'sendredpack';
+ if ($payload['type'] == 'miniapp') $api = 'sendminiprogramhb';
+ //删除多余的信息
+ unset($payload['appid'], $payload['trade_type'],
+ $payload['notify_url'], $payload['spbill_create_ip'], $payload['type']);
+
+ $payload['sign'] = Support::generateSign($payload);
+
+ Events::dispatch(new Events\PayStarted('Wechat', 'Redpack', $endpoint, $payload));
+
+
+ return Support::requestApi(
+ "mmpaymkttransfers/{$api}",
+ $payload,
+ true
+ );
+ }
+
+ /**
+ * Get trade type config.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ protected function getTradeType(): string
+ {
+ return '';
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/RefundGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/RefundGateway.php
new file mode 100644
index 0000000..1a2bdf6
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/RefundGateway.php
@@ -0,0 +1,57 @@
+
+ *
+ * @param $order
+ *
+ * @return array
+ */
+ public function find($order): array
+ {
+ return [
+ 'endpoint' => 'pay/refundquery',
+ 'order' => is_array($order) ? $order : ['out_trade_no' => $order],
+ 'cert' => false,
+ ];
+ }
+
+ /**
+ * Pay an order.
+ *
+ * @author yansongda
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws InvalidArgumentException
+ *
+ * @return void
+ */
+ public function pay($endpoint, array $payload)
+ {
+ throw new InvalidArgumentException('Not Support Refund In Pay');
+ }
+
+ /**
+ * Get trade type config.
+ *
+ * @author yansongda
+ *
+ * @throws InvalidArgumentException
+ *
+ * @return void
+ */
+ protected function getTradeType()
+ {
+ throw new InvalidArgumentException('Not Support Refund In Pay');
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/ScanGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/ScanGateway.php
new file mode 100644
index 0000000..0c436db
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/ScanGateway.php
@@ -0,0 +1,49 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function pay($endpoint, array $payload): Collection
+ {
+ $payload['spbill_create_ip'] = Request::createFromGlobals()->server->get('SERVER_ADDR');
+ $payload['trade_type'] = $this->getTradeType();
+
+ Events::dispatch(new Events\PayStarted('Wechat', 'Scan', $endpoint, $payload));
+
+ return $this->preOrder($payload);
+ }
+
+ /**
+ * Get trade type config.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ protected function getTradeType(): string
+ {
+ return 'NATIVE';
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/Support.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/Support.php
new file mode 100644
index 0000000..e8e6dd6
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/Support.php
@@ -0,0 +1,481 @@
+
+ *
+ * @property string appid
+ * @property string app_id
+ * @property string miniapp_id
+ * @property string sub_appid
+ * @property string sub_app_id
+ * @property string sub_miniapp_id
+ * @property string mch_id
+ * @property string sub_mch_id
+ * @property string key
+ * @property string return_url
+ * @property string cert_client
+ * @property string cert_key
+ * @property array log
+ * @property array http
+ * @property string mode
+ */
+class Support
+{
+ use HasHttpRequest;
+
+ /**
+ * Wechat gateway.
+ *
+ * @var string
+ */
+ protected $baseUri;
+
+ /**
+ * Config.
+ *
+ * @var Config
+ */
+ protected $config;
+
+ /**
+ * Instance.
+ *
+ * @var Support
+ */
+ private static $instance;
+
+ /**
+ * Bootstrap.
+ *
+ * @author yansongda
+ *
+ * @param Config $config
+ */
+ private function __construct(Config $config)
+ {
+ $this->baseUri = WeChat::URL[$config->get('mode', WeChat::MODE_NORMAL)];
+ $this->config = $config;
+
+ $this->setHttpOptions();
+ }
+
+ /**
+ * __get.
+ *
+ * @author yansongda
+ *
+ * @param $key
+ *
+ * @return mixed|null|Config
+ */
+ public function __get($key)
+ {
+ return $this->getConfig($key);
+ }
+
+ /**
+ * create.
+ *
+ * @author yansongda
+ *
+ * @param Config $config
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ *
+ * @return Support
+ */
+ public static function create(Config $config)
+ {
+ if (php_sapi_name() === 'cli' || !(self::$instance instanceof self)) {
+ self::$instance = new self($config);
+
+ self::setDevKey();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * getInstance.
+ *
+ * @author yansongda
+ *
+ * @throws InvalidArgumentException
+ *
+ * @return Support
+ */
+ public static function getInstance()
+ {
+ if (is_null(self::$instance)) {
+ throw new InvalidArgumentException('You Should [Create] First Before Using');
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * clear.
+ *
+ * @author yansongda
+ *
+ * @return void
+ */
+ public static function clear()
+ {
+ self::$instance = null;
+ }
+
+ /**
+ * Request wechat api.
+ *
+ * @author yansongda
+ *
+ * @param string $endpoint
+ * @param array $data
+ * @param bool $cert
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public static function requestApi($endpoint, $data, $cert = false): Collection
+ {
+ Events::dispatch(new Events\ApiRequesting('Wechat', '', self::$instance->getBaseUri().$endpoint, $data));
+
+ $result = self::$instance->post(
+ $endpoint,
+ self::toXml($data),
+ $cert ? [
+ 'cert' => self::$instance->cert_client,
+ 'ssl_key' => self::$instance->cert_key,
+ ] : []
+ );
+ $result = is_array($result) ? $result : self::fromXml($result);
+
+ Events::dispatch(new Events\ApiRequested('Wechat', '', self::$instance->getBaseUri().$endpoint, $result));
+
+
+ return self::processingApiResult($endpoint, $result);
+ }
+
+ /**
+ * Filter payload.
+ *
+ * @author yansongda
+ *
+ * @param array $payload
+ * @param array|string $params
+ * @param bool $preserve_notify_url
+ *
+ * @throws InvalidArgumentException
+ *
+ * @return array
+ */
+ public static function filterPayload($payload, $params, $preserve_notify_url = false): array
+ {
+ $type = self::getTypeName($params['type'] ?? '');
+
+ $payload = array_merge(
+ $payload,
+ is_array($params) ? $params : ['out_trade_no' => $params]
+ );
+ $payload['appid'] = self::$instance->getConfig($type, '');
+
+ if (self::$instance->getConfig('mode', WeChat::MODE_NORMAL) === WeChat::MODE_SERVICE) {
+ $payload['sub_appid'] = self::$instance->getConfig('sub_'.$type, '');
+ }
+
+ unset($payload['trade_type'], $payload['type']);
+ if (!$preserve_notify_url) {
+ unset($payload['notify_url']);
+ }
+
+ $payload['sign'] = self::generateSign($payload);
+
+ return $payload;
+ }
+
+ /**
+ * Generate wechat sign.
+ *
+ * @author yansongda
+ *
+ * @param array $data
+ *
+ * @throws InvalidArgumentException
+ *
+ * @return string
+ */
+ public static function generateSign($data): string
+ {
+ $key = self::$instance->key;
+
+ if (is_null($key)) {
+ throw new InvalidArgumentException('Missing Wechat Config -- [key]');
+ }
+
+ ksort($data);
+
+ $string = md5(self::getSignContent($data).'&key='.$key);
+
+ Log::debug('Wechat Generate Sign Before UPPER', [$data, $string]);
+
+ return strtoupper($string);
+ }
+
+ /**
+ * Generate sign content.
+ *
+ * @author yansongda
+ *
+ * @param array $data
+ *
+ * @return string
+ */
+ public static function getSignContent($data): string
+ {
+ $buff = '';
+
+ foreach ($data as $k => $v) {
+ $buff .= ($k != 'sign' && $v != '' && !is_array($v)) ? $k.'='.$v.'&' : '';
+ }
+
+ Log::debug('Wechat Generate Sign Content Before Trim', [$data, $buff]);
+
+ return trim($buff, '&');
+ }
+
+ /**
+ * Decrypt refund contents.
+ *
+ * @author yansongda
+ *
+ * @param string $contents
+ *
+ * @return string
+ */
+ public static function decryptRefundContents($contents): string
+ {
+ return openssl_decrypt(
+ base64_decode($contents),
+ 'AES-256-ECB',
+ md5(self::$instance->key),
+ OPENSSL_RAW_DATA
+ );
+ }
+
+ /**
+ * Convert array to xml.
+ *
+ * @author yansongda
+ *
+ * @param array $data
+ *
+ * @throws InvalidArgumentException
+ *
+ * @return string
+ */
+ public static function toXml($data): string
+ {
+ if (!is_array($data) || count($data) <= 0) {
+ throw new InvalidArgumentException('Convert To Xml Error! Invalid Array!');
+ }
+
+ $xml = '';
+ foreach ($data as $key => $val) {
+ $xml .= is_numeric($val) ? '<'.$key.'>'.$val.''.$key.'>' :
+ '<'.$key.'>'.$key.'>';
+ }
+ $xml .= '';
+
+ return $xml;
+ }
+
+ /**
+ * Convert xml to array.
+ *
+ * @author yansongda
+ *
+ * @param string $xml
+ *
+ * @throws InvalidArgumentException
+ *
+ * @return array
+ */
+ public static function fromXml($xml): array
+ {
+ if (!$xml) {
+ throw new InvalidArgumentException('Convert To Array Error! Invalid Xml!');
+ }
+
+ libxml_disable_entity_loader(true);
+
+ return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA), JSON_UNESCAPED_UNICODE), true);
+ }
+
+ /**
+ * Get service config.
+ *
+ * @author yansongda
+ *
+ * @param null|string $key
+ * @param null|mixed $default
+ *
+ * @return mixed|null
+ */
+ public function getConfig($key = null, $default = null)
+ {
+ if (is_null($key)) {
+ return $this->config->all();
+ }
+
+ if ($this->config->has($key)) {
+ return $this->config[$key];
+ }
+
+ return $default;
+ }
+
+ /**
+ * Get app id according to param type.
+ *
+ * @author yansongda
+ *
+ * @param string $type
+ *
+ * @return string
+ */
+ public static function getTypeName($type = ''): string
+ {
+ switch ($type) {
+ case '':
+ $type = 'app_id';
+ break;
+ case 'app':
+ $type = 'appid';
+ break;
+ default:
+ $type = $type.'_id';
+ }
+
+ return $type;
+ }
+
+ /**
+ * Get Base Uri.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ public function getBaseUri()
+ {
+ return $this->baseUri;
+ }
+
+ /**
+ * processingApiResult.
+ *
+ * @author yansongda
+ *
+ * @param $endpoint
+ * @param array $result
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ protected static function processingApiResult($endpoint, array $result)
+ {
+ if (!isset($result['return_code']) || $result['return_code'] != 'SUCCESS') {
+ throw new GatewayException(
+ 'Get Wechat API Error:'.($result['return_msg'] ?? $result['retmsg'] ?? ''),
+ $result
+ );
+ }
+
+ if (isset($result['result_code']) && $result['result_code'] != 'SUCCESS') {
+ throw new BusinessException(
+ 'Wechat Business Error: '.$result['err_code'].' - '.$result['err_code_des'],
+ $result
+ );
+ }
+
+ if ($endpoint === 'pay/getsignkey' ||
+ strpos($endpoint, 'mmpaymkttransfers') !== false ||
+ self::generateSign($result) === $result['sign']) {
+ return new Collection($result);
+ }
+
+ Events::dispatch(new Events\SignFailed('Wechat', '', $result));
+
+ throw new InvalidSignException('Wechat Sign Verify FAILED', $result);
+ }
+
+ /**
+ * setDevKey.
+ *
+ * @author yansongda
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ * @throws Exception
+ *
+ * @return Support
+ */
+ private static function setDevKey()
+ {
+ if (self::$instance->mode == WeChat::MODE_DEV) {
+ $data = [
+ 'mch_id' => self::$instance->mch_id,
+ 'nonce_str' => Str::random(),
+ ];
+ $data['sign'] = self::generateSign($data);
+
+ $result = self::requestApi('pay/getsignkey', $data);
+
+ self::$instance->config->set('key', $result['sandbox_signkey']);
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Set Http options.
+ *
+ * @author yansongda
+ *
+ * @return self
+ */
+ private function setHttpOptions(): self
+ {
+ if ($this->config->has('http') && is_array($this->config->get('http'))) {
+ $this->config->forget('http.base_uri');
+ $this->httpOptions = $this->config->get('http');
+ }
+
+ return $this;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/TransferGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/TransferGateway.php
new file mode 100644
index 0000000..4945a11
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/TransferGateway.php
@@ -0,0 +1,87 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ *
+ * @return Collection
+ */
+ public function pay($endpoint, array $payload): Collection
+ {
+ if ($this->mode === WeChat::MODE_SERVICE) {
+ unset($payload['sub_mch_id'], $payload['sub_appid']);
+ }
+
+ $type = Support::getTypeName($payload['type'] ?? '');
+
+ $payload['mch_appid'] = Support::getInstance()->getConfig($type, '');
+ $payload['mchid'] = $payload['mch_id'];
+
+ if (php_sapi_name() !== 'cli' && !isset($payload['spbill_create_ip'])) {
+ $payload['spbill_create_ip'] = Request::createFromGlobals()->server->get('SERVER_ADDR');
+ }
+
+ unset($payload['appid'], $payload['mch_id'], $payload['trade_type'],
+ $payload['notify_url'], $payload['type']);
+
+ $payload['sign'] = Support::generateSign($payload);
+
+ Events::dispatch(new Events\PayStarted('Wechat', 'Transfer', $endpoint, $payload));
+
+ return Support::requestApi(
+ 'mmpaymkttransfers/promotion/transfers',
+ $payload,
+ true
+ );
+ }
+
+ /**
+ * Find.
+ *
+ * @author yansongda
+ *
+ * @param $order
+ *
+ * @return array
+ */
+ public function find($order): array
+ {
+ return [
+ 'endpoint' => 'mmpaymkttransfers/gettransferinfo',
+ 'order' => is_array($order) ? $order : ['partner_trade_no' => $order],
+ 'cert' => true,
+ ];
+ }
+
+ /**
+ * Get trade type config.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ protected function getTradeType(): string
+ {
+ return '';
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/WapGateway.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/WapGateway.php
new file mode 100644
index 0000000..ba8fc66
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Gateways/Wechat/WapGateway.php
@@ -0,0 +1,52 @@
+
+ *
+ * @param string $endpoint
+ * @param array $payload
+ *
+ * @throws GatewayException
+ * @throws InvalidArgumentException
+ * @throws InvalidSignException
+ *
+ * @return RedirectResponse
+ */
+ public function pay($endpoint, array $payload): RedirectResponse
+ {
+ $payload['trade_type'] = $this->getTradeType();
+
+ Events::dispatch(new Events\PayStarted('Wechat', 'Wap', $endpoint, $payload));
+
+ $mweb_url = $this->preOrder($payload)->get('mweb_url');
+
+ $url = is_null(Support::getInstance()->return_url) ? $mweb_url : $mweb_url.
+ '&redirect_url='.urlencode(Support::getInstance()->return_url);
+
+ return RedirectResponse::create($url);
+ }
+
+ /**
+ * Get trade type config.
+ *
+ * @author yansongda
+ *
+ * @return string
+ */
+ protected function getTradeType(): string
+ {
+ return 'MWEB';
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Listeners/KernelLogSubscriber.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Listeners/KernelLogSubscriber.php
new file mode 100644
index 0000000..a89e5b3
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Listeners/KernelLogSubscriber.php
@@ -0,0 +1,142 @@
+ 'methodName')
+ * * array('eventName' => array('methodName', $priority))
+ * * array('eventName' => array(array('methodName1', $priority), array('methodName2')))
+ *
+ * @return array The event names to listen to
+ */
+ public static function getSubscribedEvents()
+ {
+ return [
+ Events\PayStarting::class => ['writePayStartingLog', 256],
+ Events\PayStarted::class => ['writePayStartedLog', 256],
+ Events\ApiRequesting::class => ['writeApiRequestingLog', 256],
+ Events\ApiRequested::class => ['writeApiRequestedLog', 256],
+ Events\SignFailed::class => ['writeSignFailedLog', 256],
+ Events\RequestReceived::class => ['writeRequestReceivedLog', 256],
+ Events\MethodCalled::class => ['writeMethodCalledLog', 256],
+ ];
+ }
+
+ /**
+ * writePayStartingLog.
+ *
+ * @author yansongda
+ *
+ * @param Events\PayStarting $event
+ *
+ * @return void
+ */
+ public function writePayStartingLog(Events\PayStarting $event)
+ {
+ Log::debug("Starting To {$event->driver}", [$event->gateway, $event->params]);
+ }
+
+ /**
+ * writePayStartedLog.
+ *
+ * @author yansongda
+ *
+ * @param Events\PayStarted $event
+ *
+ * @return void
+ */
+ public function writePayStartedLog(Events\PayStarted $event)
+ {
+ Log::info(
+ "{$event->driver} {$event->gateway} Has Started",
+ [$event->endpoint, $event->payload]
+ );
+ }
+
+ /**
+ * writeApiRequestingLog.
+ *
+ * @author yansongda
+ *
+ * @param Events\ApiRequesting $event
+ *
+ * @return void
+ */
+ public function writeApiRequestingLog(Events\ApiRequesting $event)
+ {
+ Log::debug("Requesting To {$event->driver} Api", [$event->endpoint, $event->payload]);
+ }
+
+ /**
+ * writeApiRequestedLog.
+ *
+ * @author yansongda
+ *
+ * @param Events\ApiRequested $event
+ *
+ * @return void
+ */
+ public function writeApiRequestedLog(Events\ApiRequested $event)
+ {
+ Log::debug("Result Of {$event->driver} Api", $event->result);
+ }
+
+ /**
+ * writeSignFailedLog.
+ *
+ * @author yansongda
+ *
+ * @param Events\SignFailed $event
+ *
+ * @return void
+ */
+ public function writeSignFailedLog(Events\SignFailed $event)
+ {
+ Log::warning("{$event->driver} Sign Verify FAILED", $event->data);
+ }
+
+ /**
+ * writeRequestReceivedLog.
+ *
+ * @author yansongda
+ *
+ * @param Events\RequestReceived $event
+ *
+ * @return void
+ */
+ public function writeRequestReceivedLog(Events\RequestReceived $event)
+ {
+ Log::info("Received {$event->driver} Request", $event->data);
+ }
+
+ /**
+ * writeMethodCalledLog.
+ *
+ * @author yansongda
+ *
+ * @param Events\MethodCalled $event
+ *
+ * @return void
+ */
+ public function writeMethodCalledLog(Events\MethodCalled $event)
+ {
+ Log::info("{$event->driver} {$event->gateway} Method Has Called", [$event->endpoint, $event->payload]);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Log.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Log.php
new file mode 100644
index 0000000..c1f8c3e
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Log.php
@@ -0,0 +1,49 @@
+
+ *
+ * @param string $method
+ * @param array $args
+ *
+ * @return mixed
+ */
+ public static function __callStatic($method, $args)
+ {
+ return forward_static_call_array([BaseLog::class, $method], $args);
+ }
+
+ /**
+ * Forward call.
+ *
+ * @author yansongda
+ *
+ * @param string $method
+ * @param array $args
+ *
+ * @return mixed
+ */
+ public function __call($method, $args)
+ {
+ return call_user_func_array([BaseLog::class, $method], $args);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/src/Pay.php b/addons/weliam_smartcity/vendor/yansongda/pay/src/Pay.php
new file mode 100644
index 0000000..aa4accb
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/src/Pay.php
@@ -0,0 +1,142 @@
+
+ *
+ * @param array $config
+ *
+ * @throws Exception
+ */
+ public function __construct(array $config)
+ {
+ $this->config = new Config($config);
+
+ $this->registerLogService();
+ $this->registerEventService();
+ }
+
+ /**
+ * Magic static call.
+ *
+ * @author yansongda
+ *
+ * @param string $method
+ * @param array $params
+ *
+ * @throws InvalidGatewayException
+ * @throws Exception
+ *
+ * @return GatewayApplicationInterface
+ */
+ public static function __callStatic($method, $params): GatewayApplicationInterface
+ {
+ $app = new self(...$params);
+
+ return $app->create($method);
+ }
+
+ /**
+ * Create a instance.
+ *
+ * @author yansongda
+ *
+ * @param string $method
+ *
+ * @throws InvalidGatewayException
+ *
+ * @return GatewayApplicationInterface
+ */
+ protected function create($method): GatewayApplicationInterface
+ {
+ $gateway = __NAMESPACE__.'\\Gateways\\'.Str::studly($method);
+
+ if (class_exists($gateway)) {
+ return self::make($gateway);
+ }
+
+ throw new InvalidGatewayException("Gateway [{$method}] Not Exists");
+ }
+
+ /**
+ * Make a gateway.
+ *
+ * @author yansongda
+ *
+ * @param string $gateway
+ *
+ * @throws InvalidGatewayException
+ *
+ * @return GatewayApplicationInterface
+ */
+ protected function make($gateway): GatewayApplicationInterface
+ {
+ $app = new $gateway($this->config);
+
+ if ($app instanceof GatewayApplicationInterface) {
+ return $app;
+ }
+
+ throw new InvalidGatewayException("Gateway [{$gateway}] Must Be An Instance Of GatewayApplicationInterface");
+ }
+
+ /**
+ * Register log service.
+ *
+ * @author yansongda
+ *
+ * @throws Exception
+ */
+ protected function registerLogService()
+ {
+ $logger = Log::createLogger(
+ $this->config->get('log.file'),
+ 'yansongda.pay',
+ $this->config->get('log.level', 'warning'),
+ $this->config->get('log.type', 'daily'),
+ $this->config->get('log.max_file', 30)
+ );
+
+ Log::setLogger($logger);
+ }
+
+ /**
+ * Register event service.
+ *
+ * @author yansongda
+ *
+ * @return void
+ */
+ protected function registerEventService()
+ {
+ Events::setDispatcher(Events::createDispatcher());
+
+ Events::addSubscriber(new KernelLogSubscriber());
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/tests/Gateways/AlipayTest.php b/addons/weliam_smartcity/vendor/yansongda/pay/tests/Gateways/AlipayTest.php
new file mode 100644
index 0000000..08901c9
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/tests/Gateways/AlipayTest.php
@@ -0,0 +1,18 @@
+success();
+
+ $this->assertInstanceOf(Response::class, $success);
+ $this->assertEquals('success', $success->getContent());
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/tests/PayTest.php b/addons/weliam_smartcity/vendor/yansongda/pay/tests/PayTest.php
new file mode 100644
index 0000000..534e71e
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/tests/PayTest.php
@@ -0,0 +1,36 @@
+ 'bar']);
+
+ $this->assertInstanceOf(Alipay::class, $alipay);
+ $this->assertInstanceOf(GatewayApplicationInterface::class, $alipay);
+ }
+
+ public function testWechatGateway()
+ {
+ $wechat = Pay::wechat(['foo' => 'bar']);
+
+ $this->assertInstanceOf(WeChat::class, $wechat);
+ $this->assertInstanceOf(GatewayApplicationInterface::class, $wechat);
+ }
+
+ public function testFooGateway()
+ {
+ $this->expectException(InvalidGatewayException::class);
+ $this->expectExceptionMessage('INVALID_GATEWAY: Gateway [foo] Not Exists');
+
+ Pay::foo([]);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/pay/tests/TestCase.php b/addons/weliam_smartcity/vendor/yansongda/pay/tests/TestCase.php
new file mode 100644
index 0000000..cf2d8bc
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/pay/tests/TestCase.php
@@ -0,0 +1,16 @@
+
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/addons/weliam_smartcity/vendor/yansongda/supports/README.md b/addons/weliam_smartcity/vendor/yansongda/supports/README.md
new file mode 100644
index 0000000..debfbde
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/supports/README.md
@@ -0,0 +1,62 @@
+Supports
+
+handle with array/config/log/guzzle etc.
+
+## About log
+
+### Register
+
+#### Method 1
+
+A application logger can extends `Yansongda\Supports\Log` and modify `createLogger` method, the method must return instance of `Monolog\Logger`.
+
+```PHP
+use Yansongda\Supports\Log;
+use Monolog\Logger;
+
+class APPLICATIONLOG extends Log
+{
+ /**
+ * Make a default log instance.
+ *
+ * @author yansongda
+ *
+ * @return Logger
+ */
+ public static function createLogger()
+ {
+ $handler = new StreamHandler('./log.log');
+ $handler->setFormatter(new LineFormatter("%datetime% > %level_name% > %message% %context% %extra%\n\n"));
+
+ $logger = new Logger('yansongda.private_number');
+ $logger->pushHandler($handler);
+
+ return $logger;
+ }
+}
+```
+
+#### Method 2
+
+Or, just init the log service with:
+
+```PHP
+use Yansongda\Supports\Log;
+
+protected function registerLog()
+{
+ $logger = Log::createLogger($file, $identify, $level);
+
+ Log::setLogger($logger);
+}
+```
+
+### Usage
+
+After registerLog, you can use Log service:
+
+```PHP
+use Yansongda\Supports\Log;
+
+Log::debug('test', ['test log']);
+```
diff --git a/addons/weliam_smartcity/vendor/yansongda/supports/composer.json b/addons/weliam_smartcity/vendor/yansongda/supports/composer.json
new file mode 100644
index 0000000..657118f
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/supports/composer.json
@@ -0,0 +1,32 @@
+{
+ "name": "yansongda/supports",
+ "description": "common components",
+ "keywords": ["support", "array", "collection", "config", "http", "guzzle", "throttle"],
+ "support": {
+ "issues": "https://github.com/yansongda/supports/issues",
+ "source": "https://github.com/yansongda/supports"
+ },
+ "authors": [
+ {
+ "name": "yansongda",
+ "email": "me@yansongda.cn"
+ }
+ ],
+ "require": {
+ "php": ">=5.5",
+ "monolog/monolog": "^1.23",
+ "guzzlehttp/guzzle": "^6.2"
+ },
+ "require-dev": {
+ "predis/predis": "^1.1"
+ },
+ "autoload": {
+ "psr-4": {
+ "Yansongda\\Supports\\": "src/"
+ }
+ },
+ "suggest": {
+ "predis/predis": "Allows to use throttle feature"
+ },
+ "license": "MIT"
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/supports/src/Arr.php b/addons/weliam_smartcity/vendor/yansongda/supports/src/Arr.php
new file mode 100644
index 0000000..ce84332
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/supports/src/Arr.php
@@ -0,0 +1,387 @@
+ $value) {
+ list($innerKey, $innerValue) = call_user_func($callback, $key, $value);
+ $results[$innerKey] = $innerValue;
+ }
+
+ return $results;
+ }
+
+ /**
+ * Divide an array into two arrays. One with keys and the other with values.
+ *
+ * @param array $array
+ *
+ * @return array
+ */
+ public static function divide($array)
+ {
+ return [
+ array_keys($array),
+ array_values($array),
+ ];
+ }
+
+ /**
+ * Flatten a multi-dimensional associative array with dots.
+ *
+ * @param array $array
+ * @param string $prepend
+ *
+ * @return array
+ */
+ public static function dot($array, $prepend = '')
+ {
+ $results = [];
+
+ foreach ($array as $key => $value) {
+ if (is_array($value)) {
+ $results = array_merge($results, static::dot($value, $prepend.$key.'.'));
+ } else {
+ $results[$prepend.$key] = $value;
+ }
+ }
+
+ return $results;
+ }
+
+ /**
+ * Get all of the given array except for a specified array of items.
+ *
+ * @param array $array
+ * @param array|string $keys
+ *
+ * @return array
+ */
+ public static function except($array, $keys)
+ {
+ return array_diff_key($array, array_flip((array) $keys));
+ }
+
+ /**
+ * Fetch a flattened array of a nested array element.
+ *
+ * @param array $array
+ * @param string $key
+ *
+ * @return array
+ */
+ public static function fetch($array, $key)
+ {
+ $results = [];
+
+ foreach (explode('.', $key) as $segment) {
+ $results = [];
+ foreach ($array as $value) {
+ $value = (array) $value;
+ $results[] = $value[$segment];
+ }
+ $array = array_values($results);
+ }
+
+ return array_values($results);
+ }
+
+ /**
+ * Return the first element in an array passing a given truth test.
+ *
+ * @param array $array
+ * @param Closure $callback
+ * @param mixed $default
+ *
+ * @return mixed
+ */
+ public static function first($array, $callback, $default = null)
+ {
+ foreach ($array as $key => $value) {
+ if (call_user_func($callback, $key, $value)) {
+ return $value;
+ }
+ }
+
+ return $default;
+ }
+
+ /**
+ * Return the last element in an array passing a given truth test.
+ *
+ * @param array $array
+ * @param Closure $callback
+ * @param mixed $default
+ *
+ * @return mixed
+ */
+ public static function last($array, $callback, $default = null)
+ {
+ return static::first(array_reverse($array), $callback, $default);
+ }
+
+ /**
+ * Flatten a multi-dimensional array into a single level.
+ *
+ * @param array $array
+ *
+ * @return array
+ */
+ public static function flatten($array)
+ {
+ $return = [];
+ array_walk_recursive(
+ $array,
+ function ($x) use (&$return) {
+ $return[] = $x;
+ }
+ );
+
+ return $return;
+ }
+
+ /**
+ * Remove one or many array items from a given array using "dot" notation.
+ *
+ * @param array $array
+ * @param array|string $keys
+ */
+ public static function forget(&$array, $keys)
+ {
+ $original = &$array;
+
+ foreach ((array) $keys as $key) {
+ $parts = explode('.', $key);
+ while (count($parts) > 1) {
+ $part = array_shift($parts);
+ if (isset($array[$part]) && is_array($array[$part])) {
+ $array = &$array[$part];
+ }
+ }
+ unset($array[array_shift($parts)]);
+ // clean up after each pass
+ $array = &$original;
+ }
+ }
+
+ /**
+ * Get an item from an array using "dot" notation.
+ *
+ * @param array $array
+ * @param string $key
+ * @param mixed $default
+ *
+ * @return mixed
+ */
+ public static function get($array, $key, $default = null)
+ {
+ if (is_null($key)) {
+ return $array;
+ }
+
+ if (isset($array[$key])) {
+ return $array[$key];
+ }
+
+ foreach (explode('.', $key) as $segment) {
+ if (!is_array($array) || !array_key_exists($segment, $array)) {
+ return $default;
+ }
+ $array = $array[$segment];
+ }
+
+ return $array;
+ }
+
+ /**
+ * Get a subset of the items from the given array.
+ *
+ * @param array $array
+ * @param array|string $keys
+ *
+ * @return array
+ */
+ public static function only($array, $keys)
+ {
+ return array_intersect_key($array, array_flip((array) $keys));
+ }
+
+ /**
+ * Pluck an array of values from an array.
+ *
+ * @param array $array
+ * @param string $value
+ * @param string $key
+ *
+ * @return array
+ */
+ public static function pluck($array, $value, $key = null)
+ {
+ $results = [];
+
+ foreach ($array as $item) {
+ $itemValue = is_object($item) ? $item->{$value} : $item[$value];
+ // If the key is "null", we will just append the value to the array and keep
+ // looping. Otherwise we will key the array using the value of the key we
+ // received from the developer. Then we'll return the final array form.
+ if (is_null($key)) {
+ $results[] = $itemValue;
+ } else {
+ $itemKey = is_object($item) ? $item->{$key} : $item[$key];
+ $results[$itemKey] = $itemValue;
+ }
+ }
+
+ return $results;
+ }
+
+ /**
+ * Get a value from the array, and remove it.
+ *
+ * @param array $array
+ * @param string $key
+ * @param mixed $default
+ *
+ * @return mixed
+ */
+ public static function pull(&$array, $key, $default = null)
+ {
+ $value = static::get($array, $key, $default);
+ static::forget($array, $key);
+
+ return $value;
+ }
+
+ /**
+ * Set an array item to a given value using "dot" notation.
+ *
+ * If no key is given to the method, the entire array will be replaced.
+ *
+ * @param array $array
+ * @param string $key
+ * @param mixed $value
+ *
+ * @return array
+ */
+ public static function set(&$array, $key, $value)
+ {
+ if (is_null($key)) {
+ return $array = $value;
+ }
+
+ $keys = explode('.', $key);
+
+ while (count($keys) > 1) {
+ $key = array_shift($keys);
+ // If the key doesn't exist at this depth, we will just create an empty array
+ // to hold the next value, allowing us to create the arrays to hold final
+ // values at the correct depth. Then we'll keep digging into the array.
+ if (!isset($array[$key]) || !is_array($array[$key])) {
+ $array[$key] = [];
+ }
+ $array = &$array[$key];
+ }
+ $array[array_shift($keys)] = $value;
+
+ return $array;
+ }
+
+ /**
+ * Sort the array using the given Closure.
+ *
+ * @param array $array
+ * @param Closure $callback
+ *
+ * @return array
+ */
+ public static function sort($array, Closure $callback)
+ {
+ $results = [];
+
+ foreach ($array as $key => $value) {
+ $results[$key] = $callback($value);
+ }
+
+ return $results;
+ }
+
+ /**
+ * Filter the array using the given Closure.
+ *
+ * @param array $array
+ * @param Closure $callback
+ *
+ * @return array
+ */
+ public static function where($array, Closure $callback)
+ {
+ $filtered = [];
+
+ foreach ($array as $key => $value) {
+ if (call_user_func($callback, $key, $value)) {
+ $filtered[$key] = $value;
+ }
+ }
+
+ return $filtered;
+ }
+
+ /**
+ * Convert encoding.
+ *
+ * @author yansongda
+ *
+ * @param array $array
+ * @param string $to_encoding
+ * @param string $from_encoding
+ *
+ * @return array
+ */
+ public static function encoding($array, $to_encoding, $from_encoding = 'gb2312')
+ {
+ $encoded = [];
+
+ foreach ($array as $key => $value) {
+ $encoded[$key] = is_array($value) ? self::encoding($value, $to_encoding, $from_encoding) :
+ mb_convert_encoding($value, $to_encoding, $from_encoding);
+ }
+
+ return $encoded;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/supports/src/Collection.php b/addons/weliam_smartcity/vendor/yansongda/supports/src/Collection.php
new file mode 100644
index 0000000..15275f5
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/supports/src/Collection.php
@@ -0,0 +1,417 @@
+
+ *
+ * modified by yansongda
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace Yansongda\Supports;
+
+use ArrayAccess;
+use ArrayIterator;
+use Countable;
+use IteratorAggregate;
+use JsonSerializable;
+use Serializable;
+
+class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable, Serializable
+{
+ /**
+ * The collection data.
+ *
+ * @var array
+ */
+ protected $items = [];
+
+ /**
+ * set data.
+ *
+ * @param mixed $items
+ */
+ public function __construct(array $items = [])
+ {
+ foreach ($items as $key => $value) {
+ $this->set($key, $value);
+ }
+ }
+
+ /**
+ * To string.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toJson();
+ }
+
+ /**
+ * Get a data by key.
+ *
+ * @param string $key
+ *
+ * @return mixed
+ */
+ public function __get($key)
+ {
+ return $this->get($key);
+ }
+
+ /**
+ * Assigns a value to the specified data.
+ *
+ * @param string $key
+ * @param mixed $value
+ */
+ public function __set($key, $value)
+ {
+ $this->set($key, $value);
+ }
+
+ /**
+ * Whether or not an data exists by key.
+ *
+ * @param string $key
+ *
+ * @return bool
+ */
+ public function __isset($key)
+ {
+ return $this->has($key);
+ }
+
+ /**
+ * Unsets an data by key.
+ *
+ * @param string $key
+ */
+ public function __unset($key)
+ {
+ $this->forget($key);
+ }
+
+ /**
+ * var_export.
+ *
+ * @param array $array
+ *
+ * @return array
+ */
+ public static function __set_state(array $array = [])
+ {
+ return (new static())->all();
+ }
+
+ /**
+ * Return all items.
+ *
+ * @return array
+ */
+ public function all()
+ {
+ return $this->items;
+ }
+
+ /**
+ * Return specific items.
+ *
+ * @param array $keys
+ *
+ * @return array
+ */
+ public function only(array $keys)
+ {
+ $return = [];
+
+ foreach ($keys as $key) {
+ $value = $this->get($key);
+
+ if (!is_null($value)) {
+ $return[$key] = $value;
+ }
+ }
+
+ return $return;
+ }
+
+ /**
+ * Get all items except for those with the specified keys.
+ *
+ * @param mixed $keys
+ *
+ * @return static
+ */
+ public function except($keys)
+ {
+ $keys = is_array($keys) ? $keys : func_get_args();
+
+ return new static(Arr::except($this->items, $keys));
+ }
+
+ /**
+ * Merge data.
+ *
+ * @param Collection|array $items
+ *
+ * @return array
+ */
+ public function merge($items)
+ {
+ foreach ($items as $key => $value) {
+ $this->set($key, $value);
+ }
+
+ return $this->all();
+ }
+
+ /**
+ * To determine Whether the specified element exists.
+ *
+ * @param string $key
+ *
+ * @return bool
+ */
+ public function has($key)
+ {
+ return !is_null(Arr::get($this->items, $key));
+ }
+
+ /**
+ * Retrieve the first item.
+ *
+ * @return mixed
+ */
+ public function first()
+ {
+ return reset($this->items);
+ }
+
+ /**
+ * Retrieve the last item.
+ *
+ * @return bool
+ */
+ public function last()
+ {
+ $end = end($this->items);
+
+ reset($this->items);
+
+ return $end;
+ }
+
+ /**
+ * add the item value.
+ *
+ * @param string $key
+ * @param mixed $value
+ */
+ public function add($key, $value)
+ {
+ Arr::set($this->items, $key, $value);
+ }
+
+ /**
+ * Set the item value.
+ *
+ * @param string $key
+ * @param mixed $value
+ */
+ public function set($key, $value)
+ {
+ Arr::set($this->items, $key, $value);
+ }
+
+ /**
+ * Retrieve item from Collection.
+ *
+ * @param string $key
+ * @param mixed $default
+ *
+ * @return mixed
+ */
+ public function get($key = null, $default = null)
+ {
+ return Arr::get($this->items, $key, $default);
+ }
+
+ /**
+ * Remove item form Collection.
+ *
+ * @param string $key
+ */
+ public function forget($key)
+ {
+ Arr::forget($this->items, $key);
+ }
+
+ /**
+ * Build to array.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return $this->all();
+ }
+
+ /**
+ * Build to json.
+ *
+ * @param int $option
+ *
+ * @return string
+ */
+ public function toJson($option = JSON_UNESCAPED_UNICODE)
+ {
+ return json_encode($this->all(), $option);
+ }
+
+ /**
+ * (PHP 5 >= 5.4.0)
+ * Specify data which should be serialized to JSON.
+ *
+ * @see http://php.net/manual/en/jsonserializable.jsonserialize.php
+ *
+ * @return mixed data which can be serialized by json_encode,
+ * which is a value of any type other than a resource
+ */
+ public function jsonSerialize()
+ {
+ return $this->items;
+ }
+
+ /**
+ * (PHP 5 >= 5.1.0)
+ * String representation of object.
+ *
+ * @see http://php.net/manual/en/serializable.serialize.php
+ *
+ * @return string the string representation of the object or null
+ */
+ public function serialize()
+ {
+ return serialize($this->items);
+ }
+
+ /**
+ * (PHP 5 >= 5.0.0)
+ * Retrieve an external iterator.
+ *
+ * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
+ *
+ * @return ArrayIterator An instance of an object implementing Iterator or
+ * ArrayIterator
+ */
+ public function getIterator()
+ {
+ return new ArrayIterator($this->items);
+ }
+
+ /**
+ * (PHP 5 >= 5.1.0)
+ * Count elements of an object.
+ *
+ * @see http://php.net/manual/en/countable.count.php
+ *
+ * @return int The custom count as an integer.
+ *
+ *
+ * The return value is cast to an integer
+ */
+ public function count()
+ {
+ return count($this->items);
+ }
+
+ /**
+ * (PHP 5 >= 5.1.0)
+ * Constructs the object.
+ *
+ * @see http://php.net/manual/en/serializable.unserialize.php
+ *
+ * @param string $serialized
+ * The string representation of the object.
+ *
+ *
+ * @return mixed|void
+ */
+ public function unserialize($serialized)
+ {
+ return $this->items = unserialize($serialized);
+ }
+
+ /**
+ * (PHP 5 >= 5.0.0)
+ * Whether a offset exists.
+ *
+ * @see http://php.net/manual/en/arrayaccess.offsetexists.php
+ *
+ * @param mixed $offset
+ * An offset to check for.
+ *
+ *
+ * @return bool true on success or false on failure.
+ * The return value will be casted to boolean if non-boolean was returned
+ */
+ public function offsetExists($offset)
+ {
+ return $this->has($offset);
+ }
+
+ /**
+ * (PHP 5 >= 5.0.0)
+ * Offset to unset.
+ *
+ * @see http://php.net/manual/en/arrayaccess.offsetunset.php
+ *
+ * @param mixed $offset
+ * The offset to unset.
+ *
+ */
+ public function offsetUnset($offset)
+ {
+ if ($this->offsetExists($offset)) {
+ $this->forget($offset);
+ }
+ }
+
+ /**
+ * (PHP 5 >= 5.0.0)
+ * Offset to retrieve.
+ *
+ * @see http://php.net/manual/en/arrayaccess.offsetget.php
+ *
+ * @param mixed $offset
+ * The offset to retrieve.
+ *
+ *
+ * @return mixed Can return all value types
+ */
+ public function offsetGet($offset)
+ {
+ return $this->offsetExists($offset) ? $this->get($offset) : null;
+ }
+
+ /**
+ * (PHP 5 >= 5.0.0)
+ * Offset to set.
+ *
+ * @see http://php.net/manual/en/arrayaccess.offsetset.php
+ *
+ * @param mixed $offset
+ * The offset to assign the value to.
+ *
+ * @param mixed $value
+ * The value to set.
+ *
+ */
+ public function offsetSet($offset, $value)
+ {
+ $this->set($offset, $value);
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/supports/src/Config.php b/addons/weliam_smartcity/vendor/yansongda/supports/src/Config.php
new file mode 100644
index 0000000..a660bad
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/supports/src/Config.php
@@ -0,0 +1,7 @@
+
+ *
+ * @param string $method
+ * @param array $args
+ *
+ * @throws Exception
+ *
+ * @return mixed
+ */
+ public static function __callStatic($method, $args)
+ {
+ return forward_static_call_array([self::getLogger(), $method], $args);
+ }
+
+ /**
+ * Forward call.
+ *
+ * @author yansongda
+ *
+ * @param string $method
+ * @param array $args
+ *
+ * @throws Exception
+ *
+ * @return mixed
+ */
+ public function __call($method, $args)
+ {
+ return call_user_func_array([self::getLogger(), $method], $args);
+ }
+
+ /**
+ * Return the logger instance.
+ *
+ * @author yansongda
+ *
+ * @throws Exception
+ *
+ * @return LoggerInterface
+ */
+ public static function getLogger()
+ {
+ return self::$logger ?: self::$logger = self::createLogger();
+ }
+
+ /**
+ * Set logger.
+ *
+ * @author yansongda
+ *
+ * @param LoggerInterface $logger
+ */
+ public static function setLogger(LoggerInterface $logger)
+ {
+ self::$logger = $logger;
+ }
+
+ /**
+ * Tests if logger exists.
+ *
+ * @author yansongda
+ *
+ * @return bool
+ */
+ public static function hasLogger()
+ {
+ return self::$logger ? true : false;
+ }
+
+ /**
+ * Make a default log instance.
+ *
+ * @author yansongda
+ *
+ * @param string $file
+ * @param string $identify
+ * @param int|string $level
+ * @param string $type
+ * @param int $max_files
+ *
+ * @throws Exception
+ *
+ * @return BaseLogger
+ */
+ public static function createLogger($file = null, $identify = 'yansongda.supports', $level = BaseLogger::DEBUG, $type = 'daily', $max_files = 30)
+ {
+ $file = is_null($file) ? sys_get_temp_dir().'/logs/'.$identify.'.log' : $file;
+
+ $handler = $type === 'single' ? new StreamHandler($file, $level) : new RotatingFileHandler($file, $max_files, $level);
+
+ $handler->setFormatter(
+ new LineFormatter("%datetime% > %channel%.%level_name% > %message% %context% %extra%\n\n", null, false, true)
+ );
+
+ $logger = new BaseLogger($identify);
+ $logger->pushHandler($handler);
+
+ return $logger;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/supports/src/Str.php b/addons/weliam_smartcity/vendor/yansongda/supports/src/Str.php
new file mode 100644
index 0000000..efd259c
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/supports/src/Str.php
@@ -0,0 +1,706 @@
+ $val) {
+ $value = str_replace($val, $key, $value);
+ }
+
+ return preg_replace('/[^\x20-\x7E]/u', '', $value);
+ }
+
+ /**
+ * Get the portion of a string before a given value.
+ *
+ * @param string $subject
+ * @param string $search
+ *
+ * @return string
+ */
+ public static function before($subject, $search)
+ {
+ return $search === '' ? $subject : explode($search, $subject)[0];
+ }
+
+ /**
+ * Convert a value to camel case.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public static function camel($value)
+ {
+ if (isset(static::$camelCache[$value])) {
+ return static::$camelCache[$value];
+ }
+
+ return static::$camelCache[$value] = lcfirst(static::studly($value));
+ }
+
+ /**
+ * Determine if a given string contains a given substring.
+ *
+ * @param string $haystack
+ * @param string|array $needles
+ *
+ * @return bool
+ */
+ public static function contains($haystack, $needles)
+ {
+ foreach ((array) $needles as $needle) {
+ if ($needle !== '' && mb_strpos($haystack, $needle) !== false) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Determine if a given string ends with a given substring.
+ *
+ * @param string $haystack
+ * @param string|array $needles
+ *
+ * @return bool
+ */
+ public static function endsWith($haystack, $needles)
+ {
+ foreach ((array) $needles as $needle) {
+ if (substr($haystack, -strlen($needle)) === (string) $needle) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Cap a string with a single instance of a given value.
+ *
+ * @param string $value
+ * @param string $cap
+ *
+ * @return string
+ */
+ public static function finish($value, $cap)
+ {
+ $quoted = preg_quote($cap, '/');
+
+ return preg_replace('/(?:'.$quoted.')+$/u', '', $value).$cap;
+ }
+
+ /**
+ * Determine if a given string matches a given pattern.
+ *
+ * @param string|array $pattern
+ * @param string $value
+ *
+ * @return bool
+ */
+ public static function is($pattern, $value)
+ {
+ $patterns = is_array($pattern) ? $pattern : (array) $pattern;
+
+ if (empty($patterns)) {
+ return false;
+ }
+
+ foreach ($patterns as $pattern) {
+ // If the given value is an exact match we can of course return true right
+ // from the beginning. Otherwise, we will translate asterisks and do an
+ // actual pattern match against the two strings to see if they match.
+ if ($pattern == $value) {
+ return true;
+ }
+
+ $pattern = preg_quote($pattern, '#');
+
+ // Asterisks are translated into zero-or-more regular expression wildcards
+ // to make it convenient to check if the strings starts with the given
+ // pattern such as "library/*", making any string check convenient.
+ $pattern = str_replace('\*', '.*', $pattern);
+
+ if (preg_match('#^'.$pattern.'\z#u', $value) === 1) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Convert a string to kebab case.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public static function kebab($value)
+ {
+ return static::snake($value, '-');
+ }
+
+ /**
+ * Return the length of the given string.
+ *
+ * @param string $value
+ * @param string $encoding
+ *
+ * @return int
+ */
+ public static function length($value, $encoding = null)
+ {
+ if ($encoding !== null) {
+ return mb_strlen($value, $encoding);
+ }
+
+ return mb_strlen($value);
+ }
+
+ /**
+ * Limit the number of characters in a string.
+ *
+ * @param string $value
+ * @param int $limit
+ * @param string $end
+ *
+ * @return string
+ */
+ public static function limit($value, $limit = 100, $end = '...')
+ {
+ if (mb_strwidth($value, 'UTF-8') <= $limit) {
+ return $value;
+ }
+
+ return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')).$end;
+ }
+
+ /**
+ * Convert the given string to lower-case.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public static function lower($value)
+ {
+ return mb_strtolower($value, 'UTF-8');
+ }
+
+ /**
+ * Limit the number of words in a string.
+ *
+ * @param string $value
+ * @param int $words
+ * @param string $end
+ *
+ * @return string
+ */
+ public static function words($value, $words = 100, $end = '...')
+ {
+ preg_match('/^\s*+(?:\S++\s*+){1,'.$words.'}/u', $value, $matches);
+
+ if (!isset($matches[0]) || static::length($value) === static::length($matches[0])) {
+ return $value;
+ }
+
+ return rtrim($matches[0]).$end;
+ }
+
+ /**
+ * Parse a Class.
+ *
+ * @param string $callback
+ * @param string|null $default
+ *
+ * @return array
+ */
+ public static function parseCallback($callback, $default = null)
+ {
+ return static::contains($callback, '@') ? explode('@', $callback, 2) : [$callback, $default];
+ }
+
+ /**
+ * Generate a more truly "random" alpha-numeric string.
+ *
+ * @param int $length
+ *
+ * @throws Exception
+ *
+ * @return string
+ */
+ public static function random($length = 16)
+ {
+ $string = '';
+
+ while (($len = strlen($string)) < $length) {
+ $size = $length - $len;
+
+ $bytes = function_exists('random_bytes') ? random_bytes($size) : mt_rand();
+
+ $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);
+ }
+
+ return $string;
+ }
+
+ /**
+ * Replace a given value in the string sequentially with an array.
+ *
+ * @param string $search
+ * @param array $replace
+ * @param string $subject
+ *
+ * @return string
+ */
+ public static function replaceArray($search, array $replace, $subject)
+ {
+ foreach ($replace as $value) {
+ $subject = static::replaceFirst($search, $value, $subject);
+ }
+
+ return $subject;
+ }
+
+ /**
+ * Replace the first occurrence of a given value in the string.
+ *
+ * @param string $search
+ * @param string $replace
+ * @param string $subject
+ *
+ * @return string
+ */
+ public static function replaceFirst($search, $replace, $subject)
+ {
+ if ($search == '') {
+ return $subject;
+ }
+
+ $position = strpos($subject, $search);
+
+ if ($position !== false) {
+ return substr_replace($subject, $replace, $position, strlen($search));
+ }
+
+ return $subject;
+ }
+
+ /**
+ * Replace the last occurrence of a given value in the string.
+ *
+ * @param string $search
+ * @param string $replace
+ * @param string $subject
+ *
+ * @return string
+ */
+ public static function replaceLast($search, $replace, $subject)
+ {
+ $position = strrpos($subject, $search);
+
+ if ($position !== false) {
+ return substr_replace($subject, $replace, $position, strlen($search));
+ }
+
+ return $subject;
+ }
+
+ /**
+ * Begin a string with a single instance of a given value.
+ *
+ * @param string $value
+ * @param string $prefix
+ *
+ * @return string
+ */
+ public static function start($value, $prefix)
+ {
+ $quoted = preg_quote($prefix, '/');
+
+ return $prefix.preg_replace('/^(?:'.$quoted.')+/u', '', $value);
+ }
+
+ /**
+ * Convert the given string to upper-case.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public static function upper($value)
+ {
+ return mb_strtoupper($value, 'UTF-8');
+ }
+
+ /**
+ * Convert the given string to title case.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public static function title($value)
+ {
+ return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8');
+ }
+
+ /**
+ * Generate a URL friendly "slug" from a given string.
+ *
+ * @param string $title
+ * @param string $separator
+ * @param string $language
+ *
+ * @return string
+ */
+ public static function slug($title, $separator = '-', $language = 'en')
+ {
+ $title = static::ascii($title, $language);
+
+ // Convert all dashes/underscores into separator
+ $flip = $separator == '-' ? '_' : '-';
+
+ $title = preg_replace('!['.preg_quote($flip).']+!u', $separator, $title);
+
+ // Replace @ with the word 'at'
+ $title = str_replace('@', $separator.'at'.$separator, $title);
+
+ // Remove all characters that are not the separator, letters, numbers, or whitespace.
+ $title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', mb_strtolower($title));
+
+ // Replace all separator characters and whitespace by a single separator
+ $title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title);
+
+ return trim($title, $separator);
+ }
+
+ /**
+ * Convert a string to snake case.
+ *
+ * @param string $value
+ * @param string $delimiter
+ *
+ * @return string
+ */
+ public static function snake($value, $delimiter = '_')
+ {
+ $key = $value;
+
+ if (isset(static::$snakeCache[$key][$delimiter])) {
+ return static::$snakeCache[$key][$delimiter];
+ }
+
+ if (!ctype_lower($value)) {
+ $value = preg_replace('/\s+/u', '', ucwords($value));
+
+ $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1'.$delimiter, $value));
+ }
+
+ return static::$snakeCache[$key][$delimiter] = $value;
+ }
+
+ /**
+ * Determine if a given string starts with a given substring.
+ *
+ * @param string $haystack
+ * @param string|array $needles
+ *
+ * @return bool
+ */
+ public static function startsWith($haystack, $needles)
+ {
+ foreach ((array) $needles as $needle) {
+ if ($needle !== '' && substr($haystack, 0, strlen($needle)) === (string) $needle) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Convert a value to studly caps case.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public static function studly($value)
+ {
+ $key = $value;
+
+ if (isset(static::$studlyCache[$key])) {
+ return static::$studlyCache[$key];
+ }
+
+ $value = ucwords(str_replace(['-', '_'], ' ', $value));
+
+ return static::$studlyCache[$key] = str_replace(' ', '', $value);
+ }
+
+ /**
+ * Returns the portion of string specified by the start and length parameters.
+ *
+ * @param string $string
+ * @param int $start
+ * @param int|null $length
+ *
+ * @return string
+ */
+ public static function substr($string, $start, $length = null)
+ {
+ return mb_substr($string, $start, $length, 'UTF-8');
+ }
+
+ /**
+ * Make a string's first character uppercase.
+ *
+ * @param string $string
+ *
+ * @return string
+ */
+ public static function ucfirst($string)
+ {
+ return static::upper(static::substr($string, 0, 1)).static::substr($string, 1);
+ }
+
+ /**
+ * Convert string's encoding.
+ *
+ * @author yansongda
+ *
+ * @param string $string
+ * @param string $to
+ * @param string $from
+ *
+ * @return string
+ */
+ public static function encoding($string, $to = 'utf-8', $from = 'gb2312')
+ {
+ return mb_convert_encoding($string, $to, $from);
+ }
+
+ /**
+ * Returns the replacements for the ascii method.
+ *
+ * Note: Adapted from Stringy\Stringy.
+ *
+ * @see https://github.com/danielstjules/Stringy/blob/3.1.0/LICENSE.txt
+ *
+ * @return array
+ */
+ protected static function charsArray()
+ {
+ static $charsArray;
+
+ if (isset($charsArray)) {
+ return $charsArray;
+ }
+
+ return $charsArray = [
+ '0' => ['°', '₀', '۰', '0'],
+ '1' => ['¹', '₁', '۱', '1'],
+ '2' => ['²', '₂', '۲', '2'],
+ '3' => ['³', '₃', '۳', '3'],
+ '4' => ['⁴', '₄', '۴', '٤', '4'],
+ '5' => ['⁵', '₅', '۵', '٥', '5'],
+ '6' => ['⁶', '₆', '۶', '٦', '6'],
+ '7' => ['⁷', '₇', '۷', '7'],
+ '8' => ['⁸', '₈', '۸', '8'],
+ '9' => ['⁹', '₉', '۹', '9'],
+ 'a' => ['à', 'á', 'ả', 'ã', 'ạ', 'ă', 'ắ', 'ằ', 'ẳ', 'ẵ', 'ặ', 'â', 'ấ', 'ầ', 'ẩ', 'ẫ', 'ậ', 'ā', 'ą', 'å', 'α', 'ά', 'ἀ', 'ἁ', 'ἂ', 'ἃ', 'ἄ', 'ἅ', 'ἆ', 'ἇ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ὰ', 'ά', 'ᾰ', 'ᾱ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'а', 'أ', 'အ', 'ာ', 'ါ', 'ǻ', 'ǎ', 'ª', 'ა', 'अ', 'ا', 'a', 'ä'],
+ 'b' => ['б', 'β', 'ب', 'ဗ', 'ბ', 'b'],
+ 'c' => ['ç', 'ć', 'č', 'ĉ', 'ċ', 'c'],
+ 'd' => ['ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ', 'д', 'δ', 'د', 'ض', 'ဍ', 'ဒ', 'დ', 'd'],
+ 'e' => ['é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê', 'ế', 'ề', 'ể', 'ễ', 'ệ', 'ë', 'ē', 'ę', 'ě', 'ĕ', 'ė', 'ε', 'έ', 'ἐ', 'ἑ', 'ἒ', 'ἓ', 'ἔ', 'ἕ', 'ὲ', 'έ', 'е', 'ё', 'э', 'є', 'ə', 'ဧ', 'ေ', 'ဲ', 'ე', 'ए', 'إ', 'ئ', 'e'],
+ 'f' => ['ф', 'φ', 'ف', 'ƒ', 'ფ', 'f'],
+ 'g' => ['ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ဂ', 'გ', 'گ', 'g'],
+ 'h' => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ', 'h'],
+ 'i' => ['í', 'ì', 'ỉ', 'ĩ', 'ị', 'î', 'ï', 'ī', 'ĭ', 'į', 'ı', 'ι', 'ί', 'ϊ', 'ΐ', 'ἰ', 'ἱ', 'ἲ', 'ἳ', 'ἴ', 'ἵ', 'ἶ', 'ἷ', 'ὶ', 'ί', 'ῐ', 'ῑ', 'ῒ', 'ΐ', 'ῖ', 'ῗ', 'і', 'ї', 'и', 'ဣ', 'ိ', 'ီ', 'ည်', 'ǐ', 'ი', 'इ', 'ی', 'i'],
+ 'j' => ['ĵ', 'ј', 'Ј', 'ჯ', 'ج', 'j'],
+ 'k' => ['ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك', 'က', 'კ', 'ქ', 'ک', 'k'],
+ 'l' => ['ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل', 'လ', 'ლ', 'l'],
+ 'm' => ['м', 'μ', 'م', 'မ', 'მ', 'm'],
+ 'n' => ['ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن', 'န', 'ნ', 'n'],
+ 'o' => ['ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ố', 'ồ', 'ổ', 'ỗ', 'ộ', 'ơ', 'ớ', 'ờ', 'ở', 'ỡ', 'ợ', 'ø', 'ō', 'ő', 'ŏ', 'ο', 'ὀ', 'ὁ', 'ὂ', 'ὃ', 'ὄ', 'ὅ', 'ὸ', 'ό', 'о', 'و', 'θ', 'ို', 'ǒ', 'ǿ', 'º', 'ო', 'ओ', 'o', 'ö'],
+ 'p' => ['п', 'π', 'ပ', 'პ', 'پ', 'p'],
+ 'q' => ['ყ', 'q'],
+ 'r' => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ', 'r'],
+ 's' => ['ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص', 'စ', 'ſ', 'ს', 's'],
+ 't' => ['ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط', 'ဋ', 'တ', 'ŧ', 'თ', 'ტ', 't'],
+ 'u' => ['ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư', 'ứ', 'ừ', 'ử', 'ữ', 'ự', 'û', 'ū', 'ů', 'ű', 'ŭ', 'ų', 'µ', 'у', 'ဉ', 'ု', 'ူ', 'ǔ', 'ǖ', 'ǘ', 'ǚ', 'ǜ', 'უ', 'उ', 'u', 'ў', 'ü'],
+ 'v' => ['в', 'ვ', 'ϐ', 'v'],
+ 'w' => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ', 'w'],
+ 'x' => ['χ', 'ξ', 'x'],
+ 'y' => ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ', 'ϋ', 'ύ', 'ΰ', 'ي', 'ယ', 'y'],
+ 'z' => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ', 'z'],
+ 'aa' => ['ع', 'आ', 'آ'],
+ 'ae' => ['æ', 'ǽ'],
+ 'ai' => ['ऐ'],
+ 'ch' => ['ч', 'ჩ', 'ჭ', 'چ'],
+ 'dj' => ['ђ', 'đ'],
+ 'dz' => ['џ', 'ძ'],
+ 'ei' => ['ऍ'],
+ 'gh' => ['غ', 'ღ'],
+ 'ii' => ['ई'],
+ 'ij' => ['ij'],
+ 'kh' => ['х', 'خ', 'ხ'],
+ 'lj' => ['љ'],
+ 'nj' => ['њ'],
+ 'oe' => ['ö', 'œ', 'ؤ'],
+ 'oi' => ['ऑ'],
+ 'oii' => ['ऒ'],
+ 'ps' => ['ψ'],
+ 'sh' => ['ш', 'შ', 'ش'],
+ 'shch' => ['щ'],
+ 'ss' => ['ß'],
+ 'sx' => ['ŝ'],
+ 'th' => ['þ', 'ϑ', 'ث', 'ذ', 'ظ'],
+ 'ts' => ['ц', 'ც', 'წ'],
+ 'ue' => ['ü'],
+ 'uu' => ['ऊ'],
+ 'ya' => ['я'],
+ 'yu' => ['ю'],
+ 'zh' => ['ж', 'ჟ', 'ژ'],
+ '(c)' => ['©'],
+ 'A' => ['Á', 'À', 'Ả', 'Ã', 'Ạ', 'Ă', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ', 'Ặ', 'Â', 'Ấ', 'Ầ', 'Ẩ', 'Ẫ', 'Ậ', 'Å', 'Ā', 'Ą', 'Α', 'Ά', 'Ἀ', 'Ἁ', 'Ἂ', 'Ἃ', 'Ἄ', 'Ἅ', 'Ἆ', 'Ἇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'Ᾰ', 'Ᾱ', 'Ὰ', 'Ά', 'ᾼ', 'А', 'Ǻ', 'Ǎ', 'A', 'Ä'],
+ 'B' => ['Б', 'Β', 'ब', 'B'],
+ 'C' => ['Ç', 'Ć', 'Č', 'Ĉ', 'Ċ', 'C'],
+ 'D' => ['Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ', 'D'],
+ 'E' => ['É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê', 'Ế', 'Ề', 'Ể', 'Ễ', 'Ệ', 'Ë', 'Ē', 'Ę', 'Ě', 'Ĕ', 'Ė', 'Ε', 'Έ', 'Ἐ', 'Ἑ', 'Ἒ', 'Ἓ', 'Ἔ', 'Ἕ', 'Έ', 'Ὲ', 'Е', 'Ё', 'Э', 'Є', 'Ə', 'E'],
+ 'F' => ['Ф', 'Φ', 'F'],
+ 'G' => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ', 'G'],
+ 'H' => ['Η', 'Ή', 'Ħ', 'H'],
+ 'I' => ['Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị', 'Î', 'Ï', 'Ī', 'Ĭ', 'Į', 'İ', 'Ι', 'Ί', 'Ϊ', 'Ἰ', 'Ἱ', 'Ἳ', 'Ἴ', 'Ἵ', 'Ἶ', 'Ἷ', 'Ῐ', 'Ῑ', 'Ὶ', 'Ί', 'И', 'І', 'Ї', 'Ǐ', 'ϒ', 'I'],
+ 'J' => ['J'],
+ 'K' => ['К', 'Κ', 'K'],
+ 'L' => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल', 'L'],
+ 'M' => ['М', 'Μ', 'M'],
+ 'N' => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν', 'N'],
+ 'O' => ['Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ố', 'Ồ', 'Ổ', 'Ỗ', 'Ộ', 'Ơ', 'Ớ', 'Ờ', 'Ở', 'Ỡ', 'Ợ', 'Ø', 'Ō', 'Ő', 'Ŏ', 'Ο', 'Ό', 'Ὀ', 'Ὁ', 'Ὂ', 'Ὃ', 'Ὄ', 'Ὅ', 'Ὸ', 'Ό', 'О', 'Θ', 'Ө', 'Ǒ', 'Ǿ', 'O', 'Ö'],
+ 'P' => ['П', 'Π', 'P'],
+ 'Q' => ['Q'],
+ 'R' => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ', 'R'],
+ 'S' => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ', 'S'],
+ 'T' => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ', 'T'],
+ 'U' => ['Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư', 'Ứ', 'Ừ', 'Ử', 'Ữ', 'Ự', 'Û', 'Ū', 'Ů', 'Ű', 'Ŭ', 'Ų', 'У', 'Ǔ', 'Ǖ', 'Ǘ', 'Ǚ', 'Ǜ', 'U', 'Ў', 'Ü'],
+ 'V' => ['В', 'V'],
+ 'W' => ['Ω', 'Ώ', 'Ŵ', 'W'],
+ 'X' => ['Χ', 'Ξ', 'X'],
+ 'Y' => ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ', 'Ы', 'Й', 'Υ', 'Ϋ', 'Ŷ', 'Y'],
+ 'Z' => ['Ź', 'Ž', 'Ż', 'З', 'Ζ', 'Z'],
+ 'AE' => ['Æ', 'Ǽ'],
+ 'Ch' => ['Ч'],
+ 'Dj' => ['Ђ'],
+ 'Dz' => ['Џ'],
+ 'Gx' => ['Ĝ'],
+ 'Hx' => ['Ĥ'],
+ 'Ij' => ['IJ'],
+ 'Jx' => ['Ĵ'],
+ 'Kh' => ['Х'],
+ 'Lj' => ['Љ'],
+ 'Nj' => ['Њ'],
+ 'Oe' => ['Œ'],
+ 'Ps' => ['Ψ'],
+ 'Sh' => ['Ш'],
+ 'Shch' => ['Щ'],
+ 'Ss' => ['ẞ'],
+ 'Th' => ['Þ'],
+ 'Ts' => ['Ц'],
+ 'Ya' => ['Я'],
+ 'Yu' => ['Ю'],
+ 'Zh' => ['Ж'],
+ ' ' => ["\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84", "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87", "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80", "\xEF\xBE\xA0"],
+ ];
+ }
+
+ /**
+ * Returns the language specific replacements for the ascii method.
+ *
+ * Note: Adapted from Stringy\Stringy.
+ *
+ * @see https://github.com/danielstjules/Stringy/blob/3.1.0/LICENSE.txt
+ *
+ * @param string $language
+ *
+ * @return array|null
+ */
+ protected static function languageSpecificCharsArray($language)
+ {
+ static $languageSpecific;
+ if (!isset($languageSpecific)) {
+ $languageSpecific = [
+ 'bg' => [
+ ['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'],
+ ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'],
+ ],
+ 'de' => [
+ ['ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü'],
+ ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'],
+ ],
+ ];
+ }
+
+ return isset($languageSpecific[$language]) ? $languageSpecific[$language] : null;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/supports/src/Traits/HasHttpRequest.php b/addons/weliam_smartcity/vendor/yansongda/supports/src/Traits/HasHttpRequest.php
new file mode 100644
index 0000000..0e13c3e
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/supports/src/Traits/HasHttpRequest.php
@@ -0,0 +1,168 @@
+
+ *
+ * @param string $endpoint
+ * @param array $query
+ * @param array $headers
+ *
+ * @return array|string
+ */
+ public function get($endpoint, $query = [], $headers = [])
+ {
+ return $this->request('get', $endpoint, [
+ 'headers' => $headers,
+ 'query' => $query,
+ ]);
+ }
+
+ /**
+ * Send a POST request.
+ *
+ * @author yansongda
+ *
+ * @param string $endpoint
+ * @param string|array $data
+ * @param array $options
+ *
+ * @return array|string
+ */
+ public function post($endpoint, $data, $options = [])
+ {
+ if (!is_array($data)) {
+ $options['body'] = $data;
+ } else {
+ $options['form_params'] = $data;
+ }
+
+ return $this->request('post', $endpoint, $options);
+ }
+
+ /**
+ * Send request.
+ *
+ * @author yansongda
+ *
+ * @param string $method
+ * @param string $endpoint
+ * @param array $options
+ *
+ * @return array|string
+ */
+ public function request($method, $endpoint, $options = [])
+ {
+ return $this->unwrapResponse($this->getHttpClient()->{$method}($endpoint, $options));
+ }
+
+ /**
+ * Set http client.
+ *
+ * @author yansongda
+ *
+ * @param Client $client
+ *
+ * @return $this
+ */
+ public function setHttpClient(Client $client)
+ {
+ $this->httpClient = $client;
+
+ return $this;
+ }
+
+ /**
+ * Get default options.
+ *
+ * @author yansongda
+ *
+ * @return array
+ */
+ public function getOptions()
+ {
+ return array_merge([
+ 'base_uri' => property_exists($this, 'baseUri') ? $this->baseUri : '',
+ 'timeout' => property_exists($this, 'timeout') ? $this->timeout : 5.0,
+ 'connect_timeout' => property_exists($this, 'connectTimeout') ? $this->connectTimeout : 5.0,
+ ], $this->httpOptions);
+ }
+
+ /**
+ * Return http client.
+ *
+ * @return Client
+ */
+ public function getHttpClient()
+ {
+ if (is_null($this->httpClient)) {
+ $this->httpClient = $this->getDefaultHttpClient();
+ }
+
+ return $this->httpClient;
+ }
+
+ /**
+ * Get default http client.
+ *
+ * @author yansongda
+ *
+ * @return Client
+ */
+ public function getDefaultHttpClient()
+ {
+ return new Client($this->getOptions());
+ }
+
+ /**
+ * Convert response.
+ *
+ * @author yansongda
+ *
+ * @param ResponseInterface $response
+ *
+ * @return array|string
+ */
+ public function unwrapResponse(ResponseInterface $response)
+ {
+ $contentType = $response->getHeaderLine('Content-Type');
+ $contents = $response->getBody()->getContents();
+
+ if (false !== stripos($contentType, 'json') || stripos($contentType, 'javascript')) {
+ return json_decode($contents, true);
+ } elseif (false !== stripos($contentType, 'xml')) {
+ return json_decode(json_encode(simplexml_load_string($contents, 'SimpleXMLElement', LIBXML_NOCDATA), JSON_UNESCAPED_UNICODE), true);
+ }
+
+ return $contents;
+ }
+}
diff --git a/addons/weliam_smartcity/vendor/yansongda/supports/src/Traits/ShouldThrottle.php b/addons/weliam_smartcity/vendor/yansongda/supports/src/Traits/ShouldThrottle.php
new file mode 100644
index 0000000..50893b6
--- /dev/null
+++ b/addons/weliam_smartcity/vendor/yansongda/supports/src/Traits/ShouldThrottle.php
@@ -0,0 +1,149 @@
+ 60,
+ 'period' => 60,
+ 'count' => 0,
+ 'reset_time' => 0
+ ];
+
+ /**
+ * isThrottled.
+ *
+ * @author yansongda
+ *
+ * @param string $key
+ * @param int $limit
+ * @param int $period
+ * @param bool $auto_add
+ *
+ * @return bool
+ */
+ public function isThrottled($key, $limit = 60, $period = 60, $auto_add = false)
+ {
+ if ($limit === -1) {
+ return false;
+ }
+
+ $now = microtime(true) * 1000;
+
+ $this->redis->zremrangebyscore($key, 0, $now - $period * 1000);
+
+ $this->_throttle = [
+ 'limit' => $limit,
+ 'period' => $period,
+ 'count' => $this->getThrottleCounts($key, $period),
+ 'reset_time' => $this->getThrottleResetTime($key, $now),
+ ];
+
+ if ($this->_throttle['count'] < $limit) {
+ if ($auto_add) {
+ $this->throttleAdd($key, $period);
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * 限流 + 1.
+ *
+ * @author yansongda
+ *
+ * @param string $key
+ * @param int $period
+ *
+ * @return void
+ */
+ public function throttleAdd($key, $period = 60)
+ {
+ $now = microtime(true) * 1000;
+
+ $this->redis->zadd($key, [$now => $now]);
+ $this->redis->expire($key, $period * 2);
+ }
+
+ /**
+ * getResetTime.
+ *
+ * @author yansongda
+ *
+ * @param $key
+ * @param $now
+ *
+ * @return int
+ */
+ public function getThrottleResetTime($key, $now)
+ {
+ $data = $this->redis->zrangebyscore(
+ $key,
+ $now - $this->_throttle['period'] * 1000,
+ $now,
+ ['limit' => [0, 1]]
+ );
+
+ if (count($data) === 0) {
+ return $this->_throttle['reset_time'] = time() + $this->_throttle['period'];
+ }
+
+ return intval($data[0] / 1000) + $this->_throttle['period'];
+ }
+
+ /**
+ * 获取限流相关信息.
+ *
+ * @author yansongda
+ *
+ * @param null $key
+ * @param null $default
+ *
+ * @return array|null
+ */
+ public function getThrottleInfo($key = null, $default = null)
+ {
+ if (is_null($key)) {
+ return $this->_throttle;
+ }
+
+ if (isset($this->_throttle[$key])) {
+ return $this->_throttle[$key];
+ }
+
+ return $default;
+ }
+
+ /**
+ * 获取已使用次数.
+ *
+ * @author yansongda
+ *
+ * @param $key
+ * @param int $period
+ *
+ * @return string
+ */
+ public function getThrottleCounts($key, $period = 60)
+ {
+ $now = microtime(true) * 1000;
+
+ return $this->redis->zcount($key, $now - $period * 1000, $now);
+ }
+}