├── .gitignore
├── README.md
├── composer.json
├── doc
├── benchmarks.md
├── db.md
├── pdo_test.sql
└── settings.ini.php
├── favicon.ico
├── index.php
├── server.sh
├── src
├── Controller
│ ├── CtrHello.php
│ ├── CtrPdo.php
│ └── CtrRedis.php
├── Core
│ ├── YcfCore.php
│ ├── YcfDB.php
│ ├── YcfDBServer.php
│ ├── YcfHttpServer.php
│ ├── YcfLog.php
│ ├── YcfRedis.php
│ ├── YcfUtils.php
│ └── settings.ini.php
├── Model
│ ├── ModelBase.php
│ ├── ModelPdo.php
│ ├── ModelProxyDb.php
│ ├── ModelRedis.php
│ └── ModelTask.php
└── runtime
│ └── .gitignore
└── vendor
├── autoload.php
└── composer
├── ClassLoader.php
├── LICENSE
├── autoload_classmap.php
├── autoload_namespaces.php
├── autoload_psr4.php
├── autoload_real.php
└── installed.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | composer.lock
3 | src/Core/settings.ini.php
4 |
5 | vendor/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ##queueSwoole
2 |
3 |
4 | ##目标
5 | * 基于swoole实现排队抢购系统,适用于高并发场景
6 | * 对性能要求极高,qps至少同配置php-fpm一倍以上
7 |
8 | ##难点
9 | * 库存控制
10 | * 排队公平性
11 | * 稳定性
12 |
13 | ##设计文档
14 | * [架构图](https://github.com/kcloze/queueSwoole/blob/master/project.md)
15 |
16 |
17 | ##启动
18 | ```
19 | chmod u+x server.sh
20 | ./server.sh start|stop
21 |
22 | ```
23 |
24 | ##压测
25 |
26 |
27 |
28 |
29 | ##感谢
30 |
31 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kcloze/ycf",
3 | "description": "A simple PHP framework for api or cli application",
4 | "keywords": ["microframework","api","cli"],
5 | "homepage": "https://www.kcloze.com",
6 | "license": "MIT",
7 | "require": {
8 | "php": ">=5.3.0"
9 | },
10 | "require-dev": {
11 | "php": ">=5.3.0"
12 | },
13 | "minimum-stability": "stable",
14 | "autoload": {
15 | "psr-4": {
16 | "Ycf\\": "src"
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/doc/benchmarks.md:
--------------------------------------------------------------------------------
1 |
2 | ## Benchmarks
3 | ####1. computer and config info:
4 | ```
5 | Architecture: x86_64
6 | CPU op-mode(s): 32-bit, 64-bit
7 | Byte Order: Little Endian
8 | CPU(s): 2
9 | On-line CPU(s) list: 0,1
10 | Thread(s) per core: 1
11 | Core(s) per socket: 2
12 | Socket(s): 1
13 | NUMA node(s): 1
14 | Vendor ID: GenuineIntel
15 | CPU family: 6
16 | Model: 60
17 | Stepping: 3
18 | CPU MHz: 800.000
19 | BogoMIPS: 5587.05
20 | Virtualization: VT-x
21 | L1d cache: 32K
22 | L1i cache: 32K
23 | L2 cache: 256K
24 | L3 cache: 2048K
25 | NUMA node0 CPU(s): 0,1
26 |
27 | Mem: 4G
28 |
29 | fpm config:
30 | pm = static
31 | pm.max_children = 150
32 | pm.start_servers = 20
33 | pm.max_requests = 500
34 |
35 | swoole config:
36 | worker_num=8
37 | max_request=1000
38 |
39 | ```
40 |
41 |
42 | ##Benchmarks:echo hello world
43 | ####2. ab -c100 -n1000 "http://192.168.10.244/kcloze/index.php?ycf=hello&act=index"
44 | code in here:(https://github.com/kcloze/ycf/blob/master/src%2FService%2FYcfHello.php)
45 |
46 | ###php7 with php-fpm:
47 | ```
48 | Server Software: nginx/1.6.3
49 | Server Hostname: 192.168.10.244
50 | Server Port: 80
51 |
52 | Document Path: /kcloze/index.php?ycf=hello&act=index
53 | Document Length: 21 bytes
54 |
55 | Concurrency Level: 100
56 | Time taken for tests: 0.228 seconds
57 | Complete requests: 1000
58 | Failed requests: 0
59 | Write errors: 0
60 | Total transferred: 182182 bytes
61 | HTML transferred: 21021 bytes
62 | Requests per second: 4393.92 [#/sec] (mean)
63 | Time per request: 22.759 [ms] (mean)
64 | Time per request: 0.228 [ms] (mean, across all concurrent requests)
65 | Transfer rate: 781.73 [Kbytes/sec] received
66 |
67 | Connection Times (ms)
68 | min mean[+/-sd] median max
69 | Connect: 0 0 0.2 0 1
70 | Processing: 3 22 2.7 22 28
71 | Waiting: 3 22 2.7 22 28
72 | Total: 3 22 2.5 22 28
73 |
74 | Percentage of the requests served within a certain time (ms)
75 | 50% 22
76 | 66% 22
77 | 75% 22
78 | 80% 22
79 | 90% 22
80 | 95% 22
81 | 98% 25
82 | 99% 27
83 | 100% 28 (longest request)
84 | ```
85 |
86 | ###php7 with swoole-http-server:
87 | ```
88 | Server Software: swoole-http-server
89 | Server Hostname: 192.168.10.244
90 | Server Port: 9501
91 |
92 | Document Path: /kcloze/index.php?ycf=hello&act=index
93 | Document Length: 9 bytes
94 |
95 | Concurrency Level: 200
96 | Time taken for tests: 0.054 seconds
97 | Complete requests: 1000
98 | Failed requests: 0
99 | Write errors: 0
100 | Total transferred: 156000 bytes
101 | HTML transferred: 9000 bytes
102 | Requests per second: 18540.49 [#/sec] (mean)
103 | Time per request: 10.787 [ms] (mean)
104 | Time per request: 0.054 [ms] (mean, across all concurrent requests)
105 | Transfer rate: 2824.53 [Kbytes/sec] received
106 |
107 | Connection Times (ms)
108 | min mean[+/-sd] median max
109 | Connect: 0 0 0.6 0 2
110 | Processing: 0 9 7.6 7 28
111 | Waiting: 0 9 7.6 7 28
112 | Total: 0 10 7.6 8 29
113 |
114 | Percentage of the requests served within a certain time (ms)
115 | 50% 8
116 | 66% 12
117 | 75% 15
118 | 80% 17
119 | 90% 22
120 | 95% 25
121 | 98% 27
122 | 99% 28
123 | 100% 29 (longest request)
124 |
125 | ```
126 |
127 | ##Benchmarks:select one record
128 | swoole with mysql aync
129 |
130 |
131 | ####2. ab -c200 -n1000 "http://192.168.10.244/kcloze/index.php?ycf=pdo&act=test"
132 | code in here:(https://github.com/kcloze/ycf/blob/master/src%2FService%2FYcfPdo.php)
133 |
134 | ###php7 with php-fpm:
135 | ```
136 |
137 |
138 | Server Software: nginx/1.6.3
139 | Server Hostname: 192.168.10.244
140 | Server Port: 80
141 |
142 | Document Path: /kcloze/index.php?ycf=pdo&act=test
143 | Document Length: 163 bytes
144 |
145 | Concurrency Level: 200
146 | Time taken for tests: 0.348 seconds
147 | Complete requests: 1000
148 | Failed requests: 0
149 | Write errors: 0
150 | Total transferred: 324000 bytes
151 | HTML transferred: 163000 bytes
152 | Requests per second: 2874.74 [#/sec] (mean)
153 | Time per request: 69.572 [ms] (mean)
154 | Time per request: 0.348 [ms] (mean, across all concurrent requests)
155 | Transfer rate: 909.58 [Kbytes/sec] received
156 |
157 | Connection Times (ms)
158 | min mean[+/-sd] median max
159 | Connect: 0 0 0.6 0 2
160 | Processing: 9 62 12.0 65 93
161 | Waiting: 9 62 12.0 65 93
162 | Total: 11 62 11.6 65 93
163 |
164 | Percentage of the requests served within a certain time (ms)
165 | 50% 65
166 | 66% 66
167 | 75% 67
168 | 80% 67
169 | 90% 70
170 | 95% 75
171 | 98% 83
172 | 99% 88
173 | 100% 93 (longest request)
174 |
175 |
176 | ```
177 |
178 |
179 |
180 | ###php7 with swoole-http-server:
181 |
182 | ```
183 |
184 | Server Software: swoole-http-server
185 | Server Hostname: 192.168.10.244
186 | Server Port: 9501
187 |
188 | Document Path: /kcloze/index.php?ycf=pdo&act=aync
189 | Document Length: 51 bytes
190 |
191 | Concurrency Level: 200
192 | Time taken for tests: 0.290 seconds
193 | Complete requests: 1000
194 | Failed requests: 0
195 | Write errors: 0
196 | Total transferred: 199000 bytes
197 | HTML transferred: 51000 bytes
198 | Requests per second: 3449.31 [#/sec] (mean)
199 | Time per request: 57.983 [ms] (mean)
200 | Time per request: 0.290 [ms] (mean, across all concurrent requests)
201 | Transfer rate: 670.33 [Kbytes/sec] received
202 |
203 | Connection Times (ms)
204 | min mean[+/-sd] median max
205 | Connect: 0 0 0.6 0 2
206 | Processing: 5 52 12.7 55 72
207 | Waiting: 5 52 12.7 55 72
208 | Total: 7 52 12.3 55 73
209 |
210 | Percentage of the requests served within a certain time (ms)
211 | 50% 55
212 | 66% 58
213 | 75% 60
214 | 80% 61
215 | 90% 64
216 | 95% 66
217 | 98% 68
218 | 99% 69
219 | 100% 73 (longest request)
220 |
221 | ```
--------------------------------------------------------------------------------
/doc/db.md:
--------------------------------------------------------------------------------
1 | ## Examples
2 | Below some examples of the basic functions of the database class. I've included a SQL dump so you can easily test the database
3 | class functions.
4 | #### The persons table
5 | | id | firstname | lastname | sex | age
6 | |:-----------:|:------------:|:------------:|:------------:|:------------:|
7 | | 1 | John | Doe | M | 19
8 | | 2 | Bob | Black | M | 41
9 | | 3 | Zoe | Chan | F | 20
10 | | 4 | Kona | Khan | M | 14
11 | | 5 | Kader| Khan | M | 56
12 |
13 | #### Fetching everything from the table
14 | ```php
15 | query("SELECT * FROM persons");
18 | ```
19 | #### Fetching with Bindings (ANTI-SQL-INJECTION):
20 | Binding parameters is the best way to prevent SQL injection. The class prepares your SQL query and binds the parameters
21 | afterwards.
22 |
23 | There are three different ways to bind parameters.
24 | ```php
25 | bind("id","1");
28 | $db->bind("firstname","John");
29 | $person = $db->query("SELECT * FROM Persons WHERE firstname = :firstname AND id = :id");
30 |
31 | // 2. Bind more parameters
32 | $db->bindMore(array("firstname"=>"John","id"=>"1"));
33 | $person = $db->query("SELECT * FROM Persons WHERE firstname = :firstname AND id = :id"));
34 |
35 | // 3. Or just give the parameters to the method
36 | $person = $db->query("SELECT * FROM Persons WHERE firstname = :firstname",array("firstname"=>"John","id"=>"1"));
37 | ```
38 |
39 | More about SQL injection prevention : http://indieteq.com/index/readmore/how-to-prevent-sql-injection-in-php
40 |
41 | #### Fetching Row:
42 | This method always returns only 1 row.
43 | ```php
44 | row("SELECT * FROM Persons WHERE id = :id", array("id"=>"1"));
47 | ```
48 | ##### Result
49 | | id | firstname | lastname | sex | age
50 | |:-----------:|:------------:|:------------:|:------------:|:------------:|
51 | | 1 | John | Doe | M | 19
52 | #### Fetching Single Value:
53 | This method returns only one single value of a record.
54 | ```php
55 | bind("id","3");
58 | $firstname = $db->single("SELECT firstname FROM Persons WHERE id = :id");
59 | ```
60 | ##### Result
61 | |firstname
62 | |:------------:
63 | | Zoe
64 | #### Fetching Column:
65 | ```php
66 | column("SELECT Firstname FROM Persons");
69 | ```
70 | ##### Result
71 | |firstname |
72 | |:-----------:
73 | | John
74 | | Bob
75 | | Zoe
76 | | Kona
77 | | Kader
78 | ### Delete / Update / Insert
79 | When executing the delete, update, or insert statement by using the query method the affected rows will be returned.
80 | ```php
81 | query("DELETE FROM Persons WHERE Id = :id", array("id"=>"1"));
85 |
86 | // Update
87 | $update = $db->query("UPDATE Persons SET firstname = :f WHERE Id = :id", array("f"=>"Jan","id"=>"32"));
88 |
89 |
90 | // Insert
91 | $insert = $db->query("INSERT INTO Persons(Firstname,Age) VALUES(:f,:age)", array("f"=>"Vivek","age"=>"20"));
92 |
93 | // Do something with the data
94 | if($insert > 0 ) {
95 | return 'Succesfully created a new person !';
96 | }
97 |
98 | ```
99 | ## Method parameters
100 | Every method which executes a query has the optional parameter called bindings.
101 |
102 | The row and the query method have a third optional parameter which is the fetch style.
103 | The default fetch style is PDO::FETCH_ASSOC which returns an associative array.
104 |
105 | Here an example :
106 |
107 | ```php
108 | row("SELECT * FROM Persons WHERE id = :id", array("id"=>"1"), PDO::FETCH_NUM);
111 |
112 | print_r($person_num);
113 | // Array ( [0] => 1 [1] => Johny [2] => Doe [3] => M [4] => 19 )
114 |
115 | ```
116 | More info about the PDO fetchstyle : http://php.net/manual/en/pdostatement.fetch.php
--------------------------------------------------------------------------------
/doc/pdo_test.sql:
--------------------------------------------------------------------------------
1 | -- phpMyAdmin SQL Dump
2 | -- version 4.5.3.1
3 | -- http://www.phpmyadmin.net
4 | --
5 | -- Host: 127.0.0.1
6 | -- Generation Time: 2016-01-17 12:18:41
7 | -- 服务器版本: 5.5.37-0ubuntu0.14.04.1
8 | -- PHP Version: 7.0.2
9 |
10 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
11 | SET time_zone = "+00:00";
12 |
13 |
14 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
15 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
16 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
17 | /*!40101 SET NAMES utf8mb4 */;
18 |
19 | --
20 | -- Database: `test`
21 | --
22 |
23 | -- --------------------------------------------------------
24 |
25 | --
26 | -- 表的结构 `pdo_test`
27 | --
28 |
29 | DROP TABLE IF EXISTS `pdo_test`;
30 | CREATE TABLE IF NOT EXISTS `pdo_test` (
31 | `id` int(10) NOT NULL AUTO_INCREMENT,
32 | `pName` varchar(50) NOT NULL,
33 | `pValue` varchar(50) NOT NULL,
34 | PRIMARY KEY (`id`)
35 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='pdo测试';
36 |
37 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
38 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
39 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
40 |
--------------------------------------------------------------------------------
/doc/settings.ini.php:
--------------------------------------------------------------------------------
1 | ;
2 | [Mysql]
3 | host = 127.0.0.1
4 | user = test
5 | password ="test123"
6 | dbname = test
7 | port = 3306
8 | charset = utf8
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kcloze/queueSwoole/c4a4f58e10e705d8468785ff0adbad4eb7f38be9/favicon.ico
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | init();
13 | $ycf->run();
14 |
--------------------------------------------------------------------------------
/server.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | pidFile="/var/qserver_pid";
3 | pidDbFile="/var/db_server_pid";
4 | function start(){
5 | php ./src/Core/YcfHttpServer.php $pidFile;
6 |
7 | printf $?
8 | if [ $? == 0 ]; then
9 | printf "\qserver start OK\r\n"
10 | return 0
11 | else
12 | printf "\qserver start FAIL\r\n"
13 | return 1
14 | fi
15 | }
16 |
17 | function stop(){
18 |
19 | $(ps aux | grep "$pidFile" |grep -v "grep "| awk '{print $2}' | xargs kill -9)
20 |
21 |
22 | PROCESS_NUM2=$(ps aux | grep "$pidFile" |grep -v "grep "| awk '{print $2}' | wc -l )
23 | if [ $PROCESS_NUM2 == 0 ]; then
24 | printf "\qserver stop OK\r\n"
25 | return 0
26 | else
27 | printf "\qserver stop FAIL\r\n"
28 | return 1
29 | fi
30 |
31 | }
32 |
33 |
34 | function startDB(){
35 | php ./src/Core/YcfDBServer.php $pidDbFile
36 |
37 | if [ $? == 0 ]; then
38 | printf "\db_server start OK\r\n"
39 | return 0
40 | else
41 | printf "\db_server start FAIL\r\n"
42 | return 1
43 | fi
44 | }
45 |
46 | function stopDB(){
47 |
48 | $(ps aux | grep "$pidDbFile" |grep -v "grep "| awk '{print $2}' | xargs kill -9)
49 |
50 |
51 | PROCESS_NUM2=$(ps aux | grep "$pidDbFile" |grep -v "grep "| awk '{print $2}' | wc -l )
52 | if [ $PROCESS_NUM2 == 0 ]; then
53 | printf "\db_server stop OK\r\n"
54 | return 0
55 | else
56 | printf "\db_server stop FAIL\r\n"
57 | return 1
58 | fi
59 |
60 | }
61 |
62 |
63 | case $1 in
64 |
65 | start )
66 | start
67 | ;;
68 | startDB )
69 | startDB
70 | ;;
71 |
72 | stop)
73 | stop
74 | ;;
75 | stopDB)
76 | stopDB
77 | ;;
78 | restart)
79 | stop
80 | sleep 1
81 | start
82 | ;;
83 |
84 | *)
85 | start
86 | ;;
87 | esac
88 |
89 |
--------------------------------------------------------------------------------
/src/Controller/CtrHello.php:
--------------------------------------------------------------------------------
1 | end("Greet, Klcoze!");
13 |
14 | }
15 | public function actionHello()
16 | {
17 | echo "hello ycf" . time();
18 | echo $this->getPPP();
19 |
20 | }
21 |
22 | public function actionTask()
23 | {
24 | // send a task to task worker.
25 | $param = array(
26 | 'action' => 'test',
27 | 'time' => time(),
28 | );
29 | //var_dump(HttpServer::getInstance()->http);
30 | //$this->http->task(json_encode($param));
31 | for ($i = 0; $i < 1; $i++) {
32 | $taskId = YcfCore::$_http_server->task(json_encode($param));
33 | }
34 | echo $taskId . " hello ycf" . time();
35 |
36 | }
37 |
38 | public function actionLog()
39 | {
40 | //for ($i = 0; $i < 1000; $i++) {
41 | YcfCore::$_log->log('hello ycf' . time(), 'info');
42 | YcfCore::$_response->end("Greet, Klcoze!");
43 | //}
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/Controller/CtrPdo.php:
--------------------------------------------------------------------------------
1 | testInsert();
14 | var_dump($result);
15 |
16 | //$result = $modelTest->testQuery();
17 | //var_dump($result);
18 | }
19 |
20 | public function actionAync()
21 | {
22 | $result = ModelProxyDb::query('select * from pdo_test limit 1');
23 | var_dump($result);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/Controller/CtrRedis.php:
--------------------------------------------------------------------------------
1 | testRedis();
13 | var_dump($result);
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Core/YcfCore.php:
--------------------------------------------------------------------------------
1 | routeCli();
29 | } else {
30 | $router = $this->route();
31 | }
32 | //route to controller
33 | $actionName = 'action' . ucfirst($router['action']);
34 | $ycfName = "Ycf\Controller\Ctr" . ucfirst($router['controller']);
35 | if (method_exists($ycfName, $actionName)) {
36 | try {
37 | $ycf = new $ycfName();
38 | $ycf->$actionName();
39 | } catch (Exception $e) {
40 | var_dump($e);
41 | }
42 |
43 | } else {
44 | echo ("action not find");
45 | }
46 | $this->shutdown();
47 |
48 | }
49 |
50 | public function shutdown()
51 | {
52 | //echo 'shutdown....';
53 | if (!defined('SWOOLE')) {
54 | self::$_log->flush();
55 | } else {
56 | self::$_log->sendTask();
57 | }
58 | }
59 |
60 | public function route()
61 | {
62 | $array = array('controller' => 'Hello', 'action' => 'index');
63 | if (!empty($_GET["ycf"])) {
64 | $array['controller'] = $_GET["ycf"];
65 | }
66 | if (!empty($_GET["act"])) {
67 | $array['action'] = $_GET["act"];
68 | return $array;
69 | }
70 | $uri = parse_url($_SERVER['REQUEST_URI']);
71 | if (empty($uri['path']) or '/' == $uri['path'] or '/index.php' == $uri['path']) {
72 | return $array;
73 | }
74 | $request = explode('/', trim($uri['path'], '/'), 3);
75 | if (count($request) < 2) {
76 | return $array;
77 | }
78 | $array['controller'] = $request[0];
79 | $array['action'] = $request[1];
80 |
81 | return $array;
82 | }
83 | /**
84 | *cli use this: /opt/php7/bin/php index.php ycf=Pdo act=test
85 | *
86 | */
87 | public function routeCli()
88 | {
89 | $array = array('controller' => 'Hello', 'action' => 'index');
90 | global $argv;
91 | foreach ($argv as $arg) {
92 | $e = explode("=", $arg);
93 | if (count($e) == 2) {
94 | $_GET[$e[0]] = $e[1];
95 | } else {
96 | $_GET[$e[0]] = 0;
97 | }
98 | }
99 | if (!empty($_GET["ycf"])) {
100 | $array['controller'] = $_GET["ycf"];
101 | }
102 | if (!empty($_GET["act"])) {
103 | $array['action'] = $_GET["act"];
104 | }
105 | //$_SERVER['REQUEST_URI'] = $argv[0] . "?" . $argv[1] . "&" . $argv[2];
106 | return $array;
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/Core/YcfDB.php:
--------------------------------------------------------------------------------
1 | config = $config;
44 | $this->Connect();
45 | $this->parameters = array();
46 | }
47 |
48 | /**
49 | * This method makes connection to the database.
50 | *
51 | * 1. Reads the database settings from a ini file.
52 | * 2. Puts the ini content into the settings array.
53 | * 3. Tries to connect to the database.
54 | * 4. If connection failed, exception is displayed and a log file gets created.
55 | */
56 | private function Connect()
57 | {
58 | $dsn = 'mysql:dbname=' . $this->config["dbname"] . ';host=' . $this->config["host"] . '';
59 | try
60 | {
61 | # Read settings from INI file, set UTF8
62 | $this->pdo = new \PDO($dsn, $this->config["user"], $this->config["password"], array(\PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
63 |
64 | # We can now log any exceptions on Fatal error.
65 | $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
66 |
67 | # Disable emulation of prepared statements, use REAL prepared statements instead.
68 | $this->pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
69 |
70 | # Connection succeeded, set the boolean to true.
71 | $this->bConnected = true;
72 | } catch (\PDOException $e) {
73 | # Write into log
74 | echo $this->ExceptionLog($e->getMessage());
75 | return;
76 | //die();
77 | }
78 | }
79 | /*
80 | * You can use this little method if you want to close the PDO connection
81 | *
82 | */
83 | public function CloseConnection()
84 | {
85 | # Set the PDO object to null to close the connection
86 | # http://www.php.net/manual/en/pdo.connections.php
87 | $this->pdo = null;
88 | }
89 |
90 | /**
91 | * Every method which needs to execute a SQL query uses this method.
92 | *
93 | * 1. If not connected, connect to the database.
94 | * 2. Prepare Query.
95 | * 3. Parameterize Query.
96 | * 4. Execute Query.
97 | * 5. On exception : Write Exception into the log + SQL query.
98 | * 6. Reset the Parameters.
99 | */
100 | private function Init($query, $parameters = "")
101 | {
102 | # Connect to database
103 | if (!$this->bConnected) {$this->Connect();}
104 | try {
105 | # Prepare query
106 | $this->sQuery = $this->pdo->prepare($query);
107 |
108 | # Add parameters to the parameter array
109 | $this->bindMore($parameters);
110 |
111 | # Bind parameters
112 | if (!empty($this->parameters)) {
113 | foreach ($this->parameters as $param) {
114 | $parameters = explode("\x7F", $param);
115 | $this->sQuery->bindParam($parameters[0], $parameters[1]);
116 | }
117 | }
118 |
119 | # Execute SQL
120 | $this->succes = $this->sQuery->execute();
121 | } catch (\PDOException $e) {
122 | # Write into log and display Exception
123 | echo $this->ExceptionLog($e->getMessage(), $query);
124 | return;
125 | //die();
126 | }
127 |
128 | # Reset the parameters
129 | $this->parameters = array();
130 | }
131 |
132 | /**
133 | * @void
134 | *
135 | * Add the parameter to the parameter array
136 | * @param string $para
137 | * @param string $value
138 | */
139 | public function bind($para, $value)
140 | {
141 | $this->parameters[sizeof($this->parameters)] = ":" . $para . "\x7F" . $value;
142 | }
143 | /**
144 | * @void
145 | *
146 | * Add more parameters to the parameter array
147 | * @param array $parray
148 | */
149 | public function bindMore($parray)
150 | {
151 | if (empty($this->parameters) && is_array($parray)) {
152 | $columns = array_keys($parray);
153 | foreach ($columns as $i => &$column) {
154 | $this->bind($column, $parray[$column]);
155 | }
156 | }
157 | }
158 | /**
159 | * If the SQL query contains a SELECT or SHOW statement it returns an array containing all of the result set row
160 | * If the SQL statement is a DELETE, INSERT, or UPDATE statement it returns the number of affected rows
161 | *
162 | * @param string $query
163 | * @param array $params
164 | * @param int $fetchmode
165 | * @return mixed
166 | */
167 | public function query($query, $params = null, $fetchmode = \PDO::FETCH_ASSOC)
168 | {
169 | $query = trim($query);
170 |
171 | $this->Init($query, $params);
172 |
173 | $rawStatement = explode(" ", $query);
174 |
175 | # Which SQL statement is used
176 | $statement = strtolower($rawStatement[0]);
177 |
178 | if ('select' === $statement || 'show' === $statement) {
179 | return $this->sQuery->fetchAll($fetchmode);
180 | } elseif ('insert' === $statement || 'update' === $statement || 'delete' === $statement) {
181 | return $this->sQuery->rowCount();
182 | } else {
183 | return null;
184 | }
185 | }
186 |
187 | /**
188 | * Returns the last inserted id.
189 | * @return string
190 | */
191 | public function lastInsertId()
192 | {
193 | return $this->pdo->lastInsertId();
194 | }
195 |
196 | /**
197 | * Returns an array which represents a column from the result set
198 | *
199 | * @param string $query
200 | * @param array $params
201 | * @return array
202 | */
203 | public function column($query, $params = null)
204 | {
205 | $this->Init($query, $params);
206 | $Columns = $this->sQuery->fetchAll(\PDO::FETCH_NUM);
207 |
208 | $column = null;
209 |
210 | foreach ($Columns as $cells) {
211 | $column[] = $cells[0];
212 | }
213 |
214 | return $column;
215 |
216 | }
217 | /**
218 | * Returns an array which represents a row from the result set
219 | *
220 | * @param string $query
221 | * @param array $params
222 | * @param int $fetchmode
223 | * @return array
224 | */
225 | public function row($query, $params = null, $fetchmode = \PDO::FETCH_ASSOC)
226 | {
227 | $this->Init($query, $params);
228 | return $this->sQuery->fetch($fetchmode);
229 | }
230 | /**
231 | * Returns the value of one single field/column
232 | *
233 | * @param string $query
234 | * @param array $params
235 | * @return string
236 | */
237 | public function single($query, $params = null)
238 | {
239 | $this->Init($query, $params);
240 | return $this->sQuery->fetchColumn();
241 | }
242 | /**
243 | * [insert insert自动绑定字段参数]
244 | * @param [type] $tableName [description]
245 | * @param [type] $data [description]
246 | * @return [type] [description]
247 | */
248 | public function insert($tableName, $data)
249 | {
250 | $columnL = "";
251 | $columnR = ":";
252 |
253 | if (is_array($data)) {
254 | $keys = array_keys($data);
255 | $columnL .= implode(",", $keys);
256 | $columnR .= implode(",:", $keys);
257 | } else {
258 | return false;
259 | }
260 | $insert = $this->query("INSERT INTO " . $tableName . " ( " . $columnL . ") VALUES ( " . $columnR . " ) ", $data);
261 | if ($insert > 0) {
262 | return $this->lastInsertId();
263 | } else {
264 | return false;
265 | }
266 | }
267 | /**
268 | * [update update自动绑定字段参数]
269 | * @param [type] $tableName [description]
270 | * @param [type] $udate [description]
271 | * @param [type] $where [description]
272 | * @return [type] [description]
273 | */
274 | public function update($tableName, $udate, $where)
275 | {
276 | $columnL = " ";
277 | $columnR = " ";
278 | if (is_array($udate)) {
279 | $i = 0;
280 | foreach ($udate as $key => $value) {
281 | $i++;
282 | $columnL .= $key . " = :" . $key;
283 | if ($i < count($udate)) {
284 | $columnL .= ", ";
285 | }
286 | }
287 | } else {
288 | return false;
289 | }
290 | if (is_array($where)) {
291 | $i = 0;
292 | foreach ($where as $key => $value) {
293 | $i++;
294 | $columnR .= $key . " = :" . $key;
295 | if ($i < count($where)) {
296 | $columnR .= " and ";
297 | }
298 | }
299 | } else {
300 | return false;
301 | }
302 | //echo "UPDATE ".$tableName." SET ".$columnL." WHERE ".$columnR;exit;
303 | $data = array_merge($udate, $where);
304 | $update = $this->query("UPDATE " . $tableName . " SET " . $columnL . " WHERE " . $columnR, $data);
305 | return $update;
306 |
307 | }
308 |
309 | /**
310 | * Writes the log and returns the exception
311 | *
312 | * @param string $message
313 | * @param string $sql
314 | * @return string
315 | */
316 | private function ExceptionLog($message, $sql = "")
317 | {
318 | $exception = 'Unhandled Exception.
';
319 | $exception .= $message;
320 | $exception .= "
You can find the error back in the log.";
321 |
322 | if (!empty($sql)) {
323 | # Add the Raw SQL to the Log
324 | $message .= "\r\nRaw SQL : " . $sql;
325 | }
326 | # Write into log
327 | YcfCore::$_log->log($message, 'error', 'db');
328 |
329 | return $exception;
330 | }
331 | }
332 |
--------------------------------------------------------------------------------
/src/Core/YcfDBServer.php:
--------------------------------------------------------------------------------
1 | set(array(
26 | 'worker_num' => 5,
27 | 'max_request' => 1000,
28 | ));
29 |
30 | $serv->on('WorkerStart', array($this, 'onStart'));
31 | //$serv->on('Connect', array($this, 'onConnect'));
32 | $serv->on('Receive', array($this, 'onReceive'));
33 | //$serv->on('Close', array($this, 'onClose'));
34 | $serv->start();
35 | }
36 |
37 | public function onStart($serv)
38 | {
39 | $this->serv = $serv;
40 | $settings = parse_ini_file("settings.ini.php", true)['Mysql'];
41 |
42 | for ($i = 0; $i < $this->pool_size; $i++) {
43 | $db = new mysqli;
44 | $db->connect($settings['host'], $settings['user'], $settings['password'], $settings['dbname']);
45 | $db_sock = swoole_get_mysqli_sock($db);
46 | swoole_event_add($db_sock, array($this, 'onSQLReady'));
47 | $this->idle_pool[] = array(
48 | 'mysqli' => $db,
49 | 'db_sock' => $db_sock,
50 | 'fd' => 0,
51 | );
52 | }
53 | echo "Server: start.Swoole version is [" . SWOOLE_VERSION . "]\n";
54 | }
55 |
56 | public function onSQLReady($db_sock)
57 | {
58 | $db_res = $this->busy_pool[$db_sock];
59 | $mysqli = $db_res['mysqli'];
60 | $fd = $db_res['fd'];
61 |
62 | echo __METHOD__ . ": client_sock=$fd|db_sock=$db_sock\n";
63 |
64 | if ($result = $mysqli->reap_async_query()) {
65 | $ret = var_export($result->fetch_all(MYSQLI_ASSOC), true) . "\n";
66 | $this->serv->send($fd, $ret);
67 | if (is_object($result)) {
68 | mysqli_free_result($result);
69 | }
70 | } else {
71 | $this->serv->send($fd, sprintf("MySQLi Error: %s\n", mysqli_error($mysqli)));
72 | }
73 | //release mysqli object
74 | $this->idle_pool[] = $db_res;
75 | unset($this->busy_pool[$db_sock]);
76 |
77 | //这里可以取出一个等待请求
78 | if (count($this->wait_queue) > 0) {
79 | $idle_n = count($this->idle_pool);
80 | for ($i = 0; $i < $idle_n; $i++) {
81 | $req = array_shift($this->wait_queue);
82 | $this->doQuery($req['fd'], $req['sql']);
83 | }
84 | }
85 | }
86 |
87 | public function onReceive($serv, $fd, $from_id, $data)
88 | {
89 | echo "Received: $data\n";
90 | //没有空闲的数据库连接
91 |
92 | if (count($this->idle_pool) == 0) {
93 | //等待队列未满
94 | if (count($this->wait_queue) < $this->wait_queue_max) {
95 | $this->wait_queue[] = array(
96 | 'fd' => $fd,
97 | 'sql' => $data,
98 | );
99 | } else {
100 | $this->serv->send($fd, "request too many, Please try again later.");
101 | }
102 | } else {
103 | $this->doQuery($fd, $data);
104 | }
105 | }
106 |
107 | public function doQuery($fd, $sql)
108 | {
109 | //从空闲池中移除
110 | $db = array_pop($this->idle_pool);
111 | /**
112 | * @var mysqli
113 | */
114 | $mysqli = $db['mysqli'];
115 |
116 | for ($i = 0; $i < 2; $i++) {
117 | $result = $mysqli->query($sql, MYSQLI_ASYNC);
118 | if ($result === false) {
119 | echo $mysqli->errno . "\n";
120 | if ($mysqli->errno == 2013 or $mysqli->errno == 2006) {
121 | $mysqli->close();
122 | $r = $mysqli->connect();
123 | if ($r === true) {
124 | continue;
125 | }
126 |
127 | }
128 | }
129 | break;
130 | }
131 |
132 | $db['fd'] = $fd;
133 | //加入工作池中
134 | $this->busy_pool[$db['db_sock']] = $db;
135 | }
136 | }
137 |
138 | $server = new YcfDBServer();
139 | $server->run();
140 |
--------------------------------------------------------------------------------
/src/Core/YcfHttpServer.php:
--------------------------------------------------------------------------------
1 | http = new \swoole_http_server("0.0.0.0", 9501);
23 |
24 | $this->http->set(
25 | array(
26 | 'worker_num' => 2,
27 | 'daemonize' => false,
28 | 'max_request' => 1,
29 | 'task_worker_num' => 2,
30 | //'dispatch_mode' => 1,
31 | )
32 | );
33 |
34 | $this->http->on('WorkerStart', array($this, 'onWorkerStart'));
35 |
36 | $this->http->on('request', function ($request, $response) {
37 | //捕获异常
38 | register_shutdown_function(array($this, 'handleFatal'));
39 | //请求过滤
40 | if ('/favicon.ico' == $request->server['path_info'] || '/favicon.ico' == $request->server['request_uri']) {
41 | return $response->end();
42 | }
43 | if (isset($request->server)) {
44 | self::$server = $request->server;
45 | foreach ($request->server as $key => $value) {
46 | $_SERVER[strtoupper($key)] = $value;
47 | }
48 | }
49 | if (isset($request->header)) {
50 | self::$header = $request->header;
51 | }
52 | if (isset($request->get)) {
53 | self::$get = $request->get;
54 | foreach ($request->get as $key => $value) {
55 | $_GET[$key] = $value;
56 | }
57 | }
58 | if (isset($request->post)) {
59 | self::$post = $request->post;
60 | foreach ($request->post as $key => $value) {
61 | $_POST[$key] = $value;
62 | }
63 | }
64 | if (isset($request->request_uri)) {
65 | $_SERVER['REQUEST_URI'] = $request->request_uri;
66 | }
67 | $GLOBALS['http_server'] = $this->http;
68 | ob_start();
69 | //实例化ycf对象
70 | try {
71 | $ycf = new YcfCore;
72 | YcfCore::$_response = $response;
73 | $ycf->init($this->http);
74 | $ycf->run();
75 | } catch (Exception $e) {
76 | var_dump($e);
77 | }
78 | $result = ob_get_contents();
79 | ob_end_clean();
80 | YcfCore::$_response->end($result);
81 | unset($result);
82 | });
83 |
84 | $this->http->on('Task', array($this, 'onTask'));
85 | $this->http->on('Finish', array($this, 'onFinish'));
86 |
87 | $this->http->start();
88 | }
89 |
90 | public function onWorkerStart()
91 | {
92 | date_default_timezone_set('Asia/Shanghai');
93 | define('DEBUG', true);
94 | define('SWOOLE', true);
95 | define('DS', DIRECTORY_SEPARATOR);
96 | define('ROOT_PATH', realpath(dirname(__FILE__)) . DS . "../.." . DS);
97 | define('YCF_BEGIN_TIME', microtime(true));
98 | //echo 'worker start....';
99 | require 'vendor/autoload.php';
100 |
101 | }
102 | public function onTask($serv, $task_id, $from_id, $data)
103 | {
104 | $ycf = new YcfCore;
105 | $ycf->init();
106 | return ModelTask::run($serv, $task_id, $from_id, $data);
107 | }
108 | public function onFinish($serv, $task_id, $data)
109 | {
110 | echo "Task {$task_id} finish\n";
111 | echo "Result: {$data}\n";
112 | unset($data);
113 | }
114 | /**
115 | * Fatal Error的捕获
116 | *
117 | */
118 | public function handleFatal()
119 | {
120 | $error = error_get_last();
121 | if (!isset($error['type'])) {
122 | return;
123 | }
124 |
125 | switch ($error['type']) {
126 | case E_ERROR:
127 | case E_PARSE:
128 | case E_DEPRECATED:
129 | case E_CORE_ERROR:
130 | case E_COMPILE_ERROR:
131 | break;
132 | default:
133 | return;
134 | }
135 | $message = $error['message'];
136 | $file = $error['file'];
137 | $line = $error['line'];
138 | $log = "\n异常提示:$message ($file:$line)\nStack trace:\n";
139 | $trace = debug_backtrace(1);
140 |
141 | foreach ($trace as $i => $t) {
142 | if (!isset($t['file'])) {
143 | $t['file'] = 'unknown';
144 | }
145 | if (!isset($t['line'])) {
146 | $t['line'] = 0;
147 | }
148 | if (!isset($t['function'])) {
149 | $t['function'] = 'unknown';
150 | }
151 | $log .= "#$i {$t['file']}({$t['line']}): ";
152 | if (isset($t['object']) && is_object($t['object'])) {
153 | $log .= get_class($t['object']) . '->';
154 | }
155 | $log .= "{$t['function']}()\n";
156 | }
157 | if (isset($_SERVER['REQUEST_URI'])) {
158 | $log .= '[QUERY] ' . $_SERVER['REQUEST_URI'];
159 | }
160 | YcfCore::$_log->log($log, 'fatal');
161 | YcfCore::$_log->sendTask();
162 | if (YcfCore::$_response) {
163 | YcfCore::$_response->status(500);
164 | YcfCore::$_response->end('程序异常');
165 | }
166 |
167 | unset($this->response);
168 | }
169 |
170 | public static function getInstance()
171 | {
172 | if (!self::$instance) {
173 | self::$instance = new YcfHttpServer();
174 | }
175 | return self::$instance;
176 | }
177 | }
178 |
179 | YcfHttpServer::getInstance();
180 |
--------------------------------------------------------------------------------
/src/Core/YcfLog.php:
--------------------------------------------------------------------------------
1 | _logs[$category][] = array($message, $level, $category, microtime(true));
25 | $this->_logCount++;
26 | if ($this->_logCount >= YcfLog::MAX_LOGS || true == $flush) {
27 | $this->flush($category);
28 | }
29 | }
30 |
31 | public function processLogs()
32 | {
33 | $logsAll["application"] = "[" . $_SERVER['REQUEST_URI'] . "] " . "[runing time]: " . (microtime(true) - YCF_BEGIN_TIME) . "\n";
34 | foreach ((array) $this->_logs as $key => $logs) {
35 | $logsAll[$key] = '';
36 | foreach ((array) $logs as $log) {
37 | $logsAll[$key] .= $this->formatLogMessage($log[0], $log[1], $log[2], $log[3]);
38 | }
39 | }
40 | return $logsAll;
41 | }
42 | /**
43 | *
44 | * 写日志到文件
45 | */
46 | public function flush()
47 | {
48 |
49 | if ($this->_logCount <= 0) {
50 | return false;
51 | }
52 | $logsAll = $this->processLogs();
53 | $this->write($logsAll);
54 | $this->_logs = array();
55 | $this->_logCount = 0;
56 | }
57 | //异步任务写日志
58 | public function sendTask()
59 | {
60 | $logsAll = $this->processLogs();
61 | if (empty($logsAll)) {
62 | return false;
63 | }
64 | $param = array(
65 | 'action' => 'flushLog',
66 | 'name' => '日志处理',
67 | 'content' => $logsAll,
68 | );
69 | $taskId = YcfCore::$_http_server->task(json_encode($param));
70 |
71 | }
72 | /**
73 | * [write 根据日志类型写到不同的日志文件]
74 | * @return [type] [description]
75 | */
76 | public function write($logsAll)
77 | {
78 | if (empty($logsAll)) {
79 | return;
80 | }
81 |
82 | $this->_logPath = ROOT_PATH . 'src/runtime/';
83 | if (!is_dir($this->_logPath)) {
84 | self::mkdir($this->_logPath, array(), true);
85 | }
86 | foreach ($logsAll as $key => $value) {
87 | if (empty($key)) {
88 | continue;
89 | }
90 | $fileName = $this->_logPath . $key . '.log';
91 | $fp2 = @fopen($fileName, "a+") or YcfUtils::exitMsg("Log fatal Error !");
92 | @fwrite($fp2, $value);
93 | @fclose($fp2);
94 | }
95 |
96 | }
97 |
98 | /**
99 | * Shared environment safe version of mkdir. Supports recursive creation.
100 | * For avoidance of umask side-effects chmod is used.
101 | *
102 | * @param string $dst path to be created
103 | * @param array $options newDirMode element used, must contain access bitmask
104 | * @param boolean $recursive whether to create directory structure recursive if parent dirs do not exist
105 | * @return boolean result of mkdir
106 | * @see mkdir
107 | */
108 | private static function mkdir($dst, array $options, $recursive)
109 | {
110 | $prevDir = dirname($dst);
111 | if ($recursive && !is_dir($dst) && !is_dir($prevDir)) {
112 | self::mkdir(dirname($dst), $options, true);
113 | }
114 |
115 | $mode = isset($options['newDirMode']) ? $options['newDirMode'] : 0777;
116 | $res = mkdir($dst, $mode);
117 | @chmod($dst, $mode);
118 | return $res;
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/src/Core/YcfRedis.php:
--------------------------------------------------------------------------------
1 | host = $config['host'];
45 | isset($config['port']) && $this->port = $config['port'];
46 | isset($config['connectTimeout']) && $this->connectTimeout = $config['connectTimeout'];
47 | isset($config['connectTries']) && $this->connectTries = $config['connectTries'];
48 | }
49 |
50 | /**
51 | * Getter of phpredis object
52 | * @return \Redis phpredis object instance
53 | * @throws RedisNotConfiguredException if any of required redis connect parameters are loose
54 | */
55 | private function getRedis()
56 | {
57 | if (is_null($this->Redis)) {
58 | if ($this->isConfigured()) {
59 | $this->Redis = new \Redis();
60 | $this->reconnect();
61 | } else {
62 | throw new RedisNotConfiguredException();
63 | }
64 | }
65 | return $this->Redis;
66 | }
67 |
68 | /**
69 | * Check required connection parameters configuration method
70 | * @return bool check result
71 | */
72 | private function isConfigured()
73 | {
74 | return !empty($this->host) && $this->port >= 0 && $this->port <= 65535;
75 | }
76 |
77 | /**
78 | * Reconnect to the redis instance
79 | * @return bool connection result. Always true.
80 | * @throws RedisConnectException if connection could not established by RedisException cause
81 | * @throws RedisTriesOverConnectException if connection could not established because tries was over
82 | */
83 | private function reconnect()
84 | {
85 | $count = 0;
86 | do {
87 | $count += 1;
88 | try {
89 | if ($this->persistent) {
90 | $result = $this->Redis->pconnect($this->host, $this->port, $this->connectTimeout);
91 | } else {
92 | $result = $this->Redis->connect($this->host, $this->port, $this->connectTimeout);
93 | }
94 | } catch (\RedisException $ex) {
95 | throw new RedisConnectException();
96 | }
97 | if (true === $result) {
98 | return true;
99 | }
100 | } while ($count < $this->connectTries);
101 |
102 | $this->Redis = null;
103 | throw new RedisTriesOverConnectException();
104 | }
105 |
106 | /**
107 | * Setter of connection timeout parameter
108 | * @param float $connectTimeout connection timeout value
109 | * @throws \InvalidArgumentException
110 | * @return Redis self
111 | */
112 | public function setConnectTimeout($connectTimeout)
113 | {
114 | $this->connectTimeout = (float) $connectTimeout;
115 | if ($this->connectTimeout < 0) {
116 | throw new \InvalidArgumentException();
117 | }
118 | return $this;
119 | }
120 |
121 | /**
122 | * Getter of connection timeout exception
123 | * @return float connect timeout value
124 | */
125 | public function getConnectTimeout()
126 | {
127 | return $this->connectTimeout;
128 | }
129 |
130 | /**
131 | * Setter of number of connection tries
132 | * @param int $connectTries connection tries count
133 | * @throws \InvalidArgumentException
134 | * @return Redis self
135 | */
136 | public function setConnectTries($connectTries)
137 | {
138 | $this->connectTries = (int) $connectTries;
139 | if ($this->connectTries < 1) {
140 | throw new \InvalidArgumentException();
141 | }
142 | return $this;
143 | }
144 |
145 | /**
146 | * Getter of number of connection tries
147 | * @return int connection tries count
148 | */
149 | public function getConnectTries()
150 | {
151 | return $this->connectTries;
152 | }
153 |
154 | /**
155 | * Setter for redis instance hostname or ip address
156 | * @param string $host hostname or ip address
157 | * @throws \InvalidArgumentException
158 | * @return Redis self
159 | */
160 | public function setHost($host)
161 | {
162 | $this->host = (string) $host;
163 | if (empty($this->host)) {
164 | throw new \InvalidArgumentException();
165 | }
166 | return $this;
167 | }
168 |
169 | /**
170 | * Getter of redis instance hostname
171 | * @return string redis instance hostname or ip address
172 | */
173 | public function getHost()
174 | {
175 | return $this->host;
176 | }
177 |
178 | /**
179 | * Setter of redis instance connection port
180 | * @param int $port redis instance connection port
181 | * @throws \InvalidArgumentException
182 | * @return Redis self
183 | */
184 | public function setPort($port)
185 | {
186 | $this->port = $port;
187 | if ($this->port < 0 || $this->port > 65535) {
188 | throw new \InvalidArgumentException();
189 | }
190 | return $this;
191 | }
192 |
193 | /**
194 | * Getter of redis instance connection port
195 | * @return int redis instance connection port
196 | */
197 | public function getPort()
198 | {
199 | return $this->port;
200 | }
201 |
202 | /**
203 | * Use persistent connection or not
204 | * @param bool $persistent if is set to true, pconnect will use, overwise not
205 | * @return Redis self
206 | */
207 | public function setPersistent($persistent)
208 | {
209 | $this->persistent = (bool) $persistent;
210 | return $this;
211 | }
212 |
213 | /**
214 | * Use persistent connection or not
215 | * @return bool if is set to true, pconnect will use, overwise not
216 | */
217 | public function getPersistent()
218 | {
219 | return $this->persistent;
220 | }
221 |
222 | /*
223 | * phpredis interface implementation
224 | */
225 |
226 | /**
227 | * Increment key value
228 | * @param string $key key
229 | * @param int $value value for increment
230 | * @return int current value
231 | * @throws RedisConnectException exception on connection to redis instance
232 | */
233 | public function incr($key, $value = 1)
234 | {
235 | $value = (int) $value;
236 | try {
237 | $result = ($value > 1)
238 | ? $this->getRedis()->incrBy($key, $value)
239 | : $this->getRedis()->incr($key);
240 | if (false !== $result) {
241 | return $result;
242 | }
243 | throw new RedisImpossibleValueException();
244 | } catch (\RedisException $ex) {
245 | throw new RedisConnectException();
246 | }
247 | }
248 |
249 | /**
250 | * Decrement key value
251 | * @param string $key key
252 | * @param int $value value for increment
253 | * @return int current value
254 | * @throws RedisConnectException exception on connection to redis instance
255 | */
256 | public function decr($key, $value = 1)
257 | {
258 | $value = (int) $value;
259 | try {
260 | $result = ($value > 1)
261 | ? $this->getRedis()->decrBy($key, $value)
262 | : $this->getRedis()->decr($key);
263 | if (false !== $result) {
264 | return $result;
265 | }
266 | throw new RedisImpossibleValueException();
267 | } catch (\RedisException $ex) {
268 | throw new RedisConnectException();
269 | }
270 | }
271 |
272 | /**
273 | * Append string value
274 | * @param string $key key
275 | * @param string $value appended value
276 | * @return int length of a key after append
277 | * @throws RedisConnectException
278 | */
279 | public function append($key, $value)
280 | {
281 | try {
282 | $result = $this->getRedis()->append($key, $value);
283 | if (false !== $result) {
284 | return $result;
285 | }
286 | throw new RedisImpossibleValueException();
287 | } catch (\RedisException $ex) {
288 | throw new RedisConnectException();
289 | }
290 | }
291 |
292 | /**
293 | * Get key value
294 | * @param string $key key
295 | * @return mixed key value
296 | * @throws RedisConnectException exception on connection to redis instance
297 | * @throws RedisKeyNotFoundException when key not found
298 | */
299 | public function get($key)
300 | {
301 | try {
302 | $result = $this->getRedis()->get($key);
303 | if (false === $result) {
304 | throw new RedisKeyNotFoundException();
305 | }
306 | return $result;
307 | } catch (\RedisException $ex) {
308 | throw new RedisConnectException();
309 | }
310 | }
311 |
312 | /**
313 | * Get multiple keys values
314 | * @param array $keys keys
315 | * @return array values
316 | * @throws RedisConnectException exception on connection to redis instance
317 | */
318 | public function mget(array $keys)
319 | {
320 | try {
321 | $result = $this->getRedis()->mGet($keys);
322 | if (false !== $result) {
323 | return array_combine($keys, $result);
324 | }
325 | throw new RedisImpossibleValueException();
326 | } catch (\RedisException $ex) {
327 | throw new RedisConnectException();
328 | }
329 | }
330 |
331 | /**
332 | * Set key value
333 | * @param string $key key
334 | * @param mixed $value value
335 | * @param int $timeout ttl timeout in milliseconds
336 | * @return bool operation result
337 | * @throws RedisConnectException exception on connection to redis instance
338 | */
339 | public function set($key, $value, $timeout = 0)
340 | {
341 | try {
342 | $result = (0 == $timeout)
343 | ? $this->getRedis()->set($key, $value)
344 | : $this->getRedis()->psetex($key, $timeout, $value);
345 | if (false !== $result) {
346 | return $result;
347 | }
348 | throw new RedisImpossibleValueException();
349 | } catch (\RedisException $ex) {
350 | throw new RedisConnectException();
351 | }
352 | }
353 |
354 | /**
355 | * Set multiple key values
356 | * @param array $values key and values
357 | * @return bool operation result
358 | * @throws RedisConnectException exception on connection to redis instance
359 | */
360 | public function mset(array $values)
361 | {
362 | try {
363 | return $this->getRedis()->mset($values);
364 | } catch (\RedisException $ex) {
365 | throw new RedisConnectException();
366 | }
367 | }
368 |
369 | /**
370 | * Set key value if not exists
371 | * @param string $key key
372 | * @param mixed $value value
373 | * @return bool returns true, if operation complete succesfull, else false
374 | * @throws RedisConnectException exception on connection to redis instance
375 | */
376 | public function setnx($key, $value)
377 | {
378 | try {
379 | return $this->getRedis()->setnx($key, $value);
380 | } catch (\RedisException $ex) {
381 | throw new RedisConnectException();
382 | }
383 | }
384 |
385 | /**
386 | * Set multiple key values
387 | * @param array $values key and values
388 | * @return bool operation result
389 | * @throws RedisConnectException exception on connection to redis instance
390 | */
391 | public function msetnx(array $values)
392 | {
393 | try {
394 | return $this->getRedis()->msetnx($values);
395 | } catch (\RedisException $ex) {
396 | throw new RedisConnectException();
397 | }
398 | }
399 |
400 | /**
401 | * GetSet implementation
402 | * @param string $key key
403 | * @param mixed $value value
404 | * @return bool|mixed previous value of a key. If key did not set, method returns false
405 | * @throws RedisConnectException exception on connection to redis instance
406 | */
407 | public function getset($key, $value)
408 | {
409 | try {
410 | return $this->getRedis()->getSet($key, $value);
411 | } catch (\RedisException $ex) {
412 | throw new RedisConnectException();
413 | }
414 | }
415 |
416 | /**
417 | * Delete key or keys
418 | * @param string|array $keys key or keys array
419 | * @return int count of deleted keys
420 | * @throws RedisConnectException exception on connection to redis instance
421 | */
422 | public function delete($keys)
423 | {
424 | try {
425 | $result = $this->getRedis()->delete($keys);
426 | if (false !== $result) {
427 | return $result;
428 | }
429 | throw new RedisImpossibleValueException();
430 | } catch (\RedisException $ex) {
431 | throw new RedisConnectException();
432 | }
433 | }
434 |
435 | /**
436 | * Check if key exists
437 | * @param string $key key
438 | * @return bool check result
439 | * @throws RedisConnectException exception on connection to redis instance
440 | */
441 | public function exists($key)
442 | {
443 | try {
444 | return $this->getRedis()->exists($key);
445 | } catch (\RedisException $ex) {
446 | throw new RedisConnectException();
447 | }
448 | }
449 |
450 | /**
451 | * Rename key
452 | * @param string $source current key name
453 | * @param string $destination needed key name
454 | * @return bool operation result. If false, source key not found
455 | * @throws RedisConnectException exception on connection to redis instance
456 | */
457 | public function rename($source, $destination)
458 | {
459 | try {
460 | return $this->getRedis()->rename($source, $destination);
461 | } catch (\RedisException $ex) {
462 | throw new RedisConnectException();
463 | }
464 | }
465 |
466 | /**
467 | * Rename key if needed key name was not
468 | * @param string $source current key name
469 | * @param string $destination needed key name
470 | * @return bool operation result. If false, source key not found or needed key name found
471 | * @throws RedisConnectException exception on connection to redis instance
472 | */
473 | public function renamenx($source, $destination)
474 | {
475 | try {
476 | return $this->getRedis()->renamenx($source, $destination);
477 | } catch (\RedisException $ex) {
478 | throw new RedisConnectException();
479 | }
480 | }
481 |
482 | /**
483 | * Get string length of a key
484 | * @param string $key key
485 | * @return int key value length
486 | * @throws RedisConnectException exception on connection to redis instance
487 | */
488 | public function strlen($key)
489 | {
490 | try {
491 | $result = $this->getRedis()->strlen($key);
492 | if (false !== $result) {
493 | return $result;
494 | }
495 | throw new RedisImpossibleValueException();
496 | } catch (\RedisException $ex) {
497 | throw new RedisConnectException();
498 | }
499 | }
500 |
501 | /**
502 | * Set ttl for a key
503 | * @param string $key key
504 | * @param int $timeout ttl in milliseconds
505 | * @return bool operation result. If false ttl cound not be set, or key not found
506 | * @throws RedisConnectException exception on connection to redis instance
507 | */
508 | public function expire($key, $timeout)
509 | {
510 | try {
511 | return $this->getRedis()->pexpire($key, $timeout);
512 | } catch (\RedisException $ex) {
513 | throw new RedisConnectException();
514 | }
515 | }
516 |
517 | /**
518 | * Set time of life for the key
519 | * @param string $key key
520 | * @param int $timestamp unix timestamp of time of death
521 | * @return bool operation result. If false timestamp cound not be set, or key not found
522 | * @throws RedisConnectException exception on connection to redis instance
523 | */
524 | public function expireat($key, $timestamp)
525 | {
526 | try {
527 | return $this->getRedis()->expireat($key, $timestamp);
528 | } catch (\RedisException $ex) {
529 | throw new RedisConnectException();
530 | }
531 | }
532 |
533 | /**
534 | * Get ttl of the key
535 | * @param string $key key
536 | * @return int|bool ttl in milliseconds or false, if ttl is not set or key not found
537 | * @throws RedisConnectException exception on connection to redis instance
538 | */
539 | public function ttl($key)
540 | {
541 | try {
542 | $result = $this->getRedis()->pttl($key);
543 | return (-1 != $result) ? $result : false;
544 | } catch (\RedisException $ex) {
545 | throw new RedisConnectException();
546 | }
547 | }
548 |
549 | /**
550 | * Remove ttl from the key
551 | * @param string $key key
552 | * @return bool if true ttl was removed successful, if false ttl did not set, or key not found
553 | * @throws RedisConnectException exception on connection to redis instance
554 | */
555 | public function persist($key)
556 | {
557 | try {
558 | return $this->getRedis()->persist($key);
559 | } catch (\RedisException $ex) {
560 | throw new RedisConnectException();
561 | }
562 | }
563 |
564 | /**
565 | * Get key bit
566 | * @param string $key key
567 | * @param int $offset bit offset
568 | * @return int bit value at the offset
569 | * @throws RedisConnectException exception on connection to redis instance
570 | */
571 | public function getbit($key, $offset)
572 | {
573 | $offset = (int) $offset;
574 | try {
575 | $result = $this->getRedis()->getBit($key, $offset);
576 | if (false !== $result) {
577 | return $result;
578 | }
579 | throw new RedisImpossibleValueException();
580 | } catch (\RedisException $ex) {
581 | throw new RedisConnectException();
582 | }
583 | }
584 |
585 | /**
586 | * Set key bit
587 | * @param string $key key
588 | * @param int $offset bit offset
589 | * @param int $value bit value. May be 0 or 1
590 | * @return int bit value before operation complete
591 | * @throws RedisConnectException exception on connection to redis instance
592 | */
593 | public function setbit($key, $offset, $value)
594 | {
595 | $offset = (int) $offset;
596 | $value = (int) (bool) $value;
597 | try {
598 | $result = $this->getRedis()->setBit($key, $offset, $value);
599 | if (false !== $result) {
600 | return $result;
601 | }
602 | throw new RedisImpossibleValueException();
603 | } catch (\RedisException $ex) {
604 | throw new RedisConnectException();
605 | }
606 | }
607 |
608 | /**
609 | * Evaluate Lua code
610 | * @param string $code string of Lua code
611 | * @param array $arguments array of Lua script arguments
612 | * @return mixed code execution result
613 | * @throws RedisConnectException exception on connection to redis instance
614 | * @throws RedisScriptExecutionException when script execution faled
615 | */
616 | public function evaluate($code, array $arguments = array())
617 | {
618 | try {
619 | if (empty($arguments)) {
620 | $result = $this->getRedis()->eval($code);
621 | } else {
622 | $result = $this->getRedis()->eval($code, $arguments, count($arguments));
623 | }
624 |
625 | $lastError = $this->getRedis()->getLastError();
626 | $this->getRedis()->clearLastError();
627 | if (is_null($lastError)) {
628 | return $result;
629 | }
630 | throw new RedisScriptExecutionException($lastError);
631 | } catch (\RedisException $ex) {
632 | throw new RedisConnectException();
633 | }
634 | }
635 |
636 | /**
637 | * Evaluate Lua code by hash
638 | * @param string $sha SHA1 string of Lua code
639 | * @param array $arguments array of Lua script arguments
640 | * @return mixed code execution result
641 | * @throws RedisConnectException exception on connection to redis instance
642 | * @throws RedisScriptExecutionException when script execution faled
643 | */
644 | public function evalSha($sha, array $arguments = array())
645 | {
646 | try {
647 | if (empty($arguments)) {
648 | $result = $this->getRedis()->evalSha($sha);
649 | } else {
650 | $result = $this->getRedis()->evalSha($sha, $arguments, count($arguments));
651 | }
652 |
653 | $lastError = $this->getRedis()->getLastError();
654 | $this->getRedis()->clearLastError();
655 | if (is_null($lastError)) {
656 | return $result;
657 | }
658 | throw new RedisScriptExecutionException($lastError);
659 | } catch (\RedisException $ex) {
660 | throw new RedisConnectException();
661 | }
662 | }
663 |
664 | /**
665 | * Add member to the set
666 | * @param string $key key
667 | * @param mixed $member set member
668 | * @return int count of added members
669 | * @throws RedisConnectException exception on connection to redis instance
670 | */
671 | public function sadd($key, $member)
672 | {
673 | try {
674 | $result = $this->getRedis()->sAdd($key, $member);
675 | if (false !== $result) {
676 | return $result;
677 | }
678 | throw new RedisImpossibleValueException();
679 | } catch (\RedisException $ex) {
680 | throw new RedisConnectException();
681 | }
682 | }
683 |
684 | /**
685 | * Pop (remove and return) a random member from the set
686 | * @param string $key key
687 | * @return mixed set member
688 | * @throws RedisConnectException exception on connection to redis instance
689 | */
690 | public function spop($key)
691 | {
692 | try {
693 | return $this->getRedis()->sPop($key);
694 | } catch (\RedisException $ex) {
695 | throw new RedisConnectException();
696 | }
697 | }
698 |
699 | /**
700 | * Return random member from the set
701 | * @param string $key key
702 | * @return mixed set member
703 | * @throws RedisConnectException exception on connection to redis instance
704 | */
705 | public function srandmember($key)
706 | {
707 | try {
708 | return $this->getRedis()->sRandMember($key);
709 | } catch (\RedisException $ex) {
710 | throw new RedisConnectException();
711 | }
712 | }
713 |
714 | /**
715 | * Returns size of the set
716 | * @param string $key set
717 | * @return int members count of the set
718 | * @throws RedisConnectException exception on connection to redis instance
719 | */
720 | public function scard($key)
721 | {
722 | try {
723 | return $this->getRedis()->sCard($key);
724 | } catch (\RedisException $ex) {
725 | throw new RedisConnectException();
726 | }
727 | }
728 |
729 | /**
730 | * Check that member is a member of the set
731 | * @param string $key key
732 | * @param mixed $member member
733 | * @return bool check result
734 | * @throws RedisConnectException exception on connection to redis instance
735 | */
736 | public function sismembers($key, $member)
737 | {
738 | try {
739 | return $this->getRedis()->sIsMember($key);
740 | } catch (\RedisException $ex) {
741 | throw new RedisConnectException();
742 | }
743 | }
744 |
745 | /**
746 | * Returns all members of the set
747 | * @param string $key key
748 | * @return array all members of the set
749 | * @throws RedisConnectException exception on connection to redis instance
750 | */
751 | public function smembers($key)
752 | {
753 | try {
754 | return $this->getRedis()->sMembers($key);
755 | } catch (\RedisException $ex) {
756 | throw new RedisConnectException();
757 | }
758 | }
759 |
760 | /**
761 | * Remove member from the set
762 | * @param string $key key
763 | * @param mixed $member set member
764 | * @return int count of removed elements
765 | * @throws RedisConnectException exception on connection to redis instance
766 | */
767 | public function srem($key, $member)
768 | {
769 | try {
770 | return $this->getRedis()->sRem($key);
771 | } catch (\RedisException $ex) {
772 | throw new RedisConnectException();
773 | }
774 | }
775 |
776 | /**
777 | * Create difference set
778 | * @param string $destination key for result set
779 | * @param array $sources source keys
780 | * @return int size of result set
781 | * @throws RedisConnectException exception on connection to redis instance
782 | */
783 | public function sdiffstore($destination, array $sources)
784 | {
785 | try {
786 | return call_user_func_array(array(
787 | $this->getRedis(),
788 | 'sDiffStore',
789 | ), array_merge(array($destination), $sources));
790 | } catch (\RedisException $ex) {
791 | throw new RedisConnectException();
792 | }
793 | }
794 | }
795 |
796 | class PhpRedisException extends \Exception
797 | {}
798 | class RedisConnectException extends PhpRedisException
799 | {}
800 | final class RedisTriesOverConnectException extends RedisConnectException
801 | {}
802 | final class RedisNotConfiguredException extends PhpRedisException
803 | {}
804 | final class RedisKeyNotFoundException extends PhpRedisException
805 | {}
806 | final class RedisScriptExecutionException extends PhpRedisException
807 | {}
808 | final class RedisImpossibleValueException extends PhpRedisException
809 | {}
810 |
--------------------------------------------------------------------------------
/src/Core/YcfUtils.php:
--------------------------------------------------------------------------------
1 |
2 | [Mysql]
3 | ;host = 119.29.152.216
4 | ;user = db_kcloze
5 | ;password ="@#uwhK677RHuh$%"
6 |
7 | host = 192.168.9.24
8 | user = yongfu_b
9 | password ="%#@SwEsdf43738"
10 |
11 | dbname = test
12 | port = 3306
13 | charset = utf8
--------------------------------------------------------------------------------
/src/Model/ModelBase.php:
--------------------------------------------------------------------------------
1 | _db = $this->load('_db');
15 | }
16 |
17 | protected function load($obj)
18 | {
19 | switch ($obj) {
20 | case '_db':
21 | return $this->getDbInstance();
22 | break;
23 | case '_redis':
24 | return $this->getRedisInstance();
25 | break;
26 | default:
27 | break;
28 | }
29 | }
30 |
31 | protected function getDbInstance()
32 | {
33 | // Create Mysql Client instance with you configuration settings
34 | if (null == $this->_db) {
35 | $this->_db = new YcfDB(YcfCore::$_settings['Mysql']);
36 | }
37 | return $this->_db;
38 | }
39 | protected function getRedisInstance()
40 | {
41 | if (!extension_loaded('redis')) {
42 | throw new \RuntimeException('php redis extension not found');
43 | return null;
44 | }
45 | // Create Redis Client instance with you configuration settings
46 | $this->_redis = new YcfRedis(YcfCore::$_settings['Redis']);
47 | return $this->_redis;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Model/ModelPdo.php:
--------------------------------------------------------------------------------
1 | _db->query("INSERT INTO pdo_test( pName,pValue) VALUES ( :pName,:pValue)", $data);
14 | if ($insert > 0) {
15 | echo $this->_db->lastInsertId() . "\r\n";
16 | } else {
17 | echo false . "\r\n";
18 | }
19 |
20 | }
21 |
22 | public function testQuery()
23 | {
24 | return $this->_db->query("select * from pdo_test limit 1");
25 |
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/Model/ModelProxyDb.php:
--------------------------------------------------------------------------------
1 | connect('127.0.0.1', 9509, 0.5, 0);
16 | $client->send($sql);
17 | return $client->recv();
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/Model/ModelRedis.php:
--------------------------------------------------------------------------------
1 | _redis = YcfCore::load('_redis');
12 | }
13 |
14 | public function testRedis()
15 | {
16 | $this->_redis->sadd('test1', 1);
17 | $this->_redis->sadd('test1', 2);
18 | $this->_redis->sadd('test1', 3);
19 | $this->_redis->sadd('test2', 2);
20 | $this->_redis->sdiffstore('test3', array('test1', 'test2'));
21 | var_dump($this->_redis->smembers('test3'));
22 | // Use Redis commands
23 | $this->_redis->set('test', '7');
24 | var_dump($this->_redis->get('test'));
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/Model/ModelTask.php:
--------------------------------------------------------------------------------
1 | testInsert();
27 | sleep(1);
28 | echo "This Task {$task_id} from Worker {$from_id}\n";
29 | //echo "Data: {$data}\n";
30 | /*for ($i = 0; $i < 10; $i++) {
31 | sleep(1);
32 | echo "Taks {$task_id} Handle {$i} times...\n";
33 | */
34 | //$fd = json_decode($data, true)['fd'];
35 | //$serv->send($fd, "Data in Task {$task_id}");
36 | echo "Task {$task_id}'s result {$result}";
37 | }
38 |
39 | public static function flushLogTask($serv, $task_id, $from_id, $data)
40 | {
41 | if (isset($data['content'])) {
42 | YcfCore::$_log && YcfCore::$_log->write($data['content']);
43 | }
44 | echo "Task {$task_id} have done";
45 |
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/runtime/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 |
--------------------------------------------------------------------------------
/vendor/autoload.php:
--------------------------------------------------------------------------------
1 |
7 | * Jordi Boggiano
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Composer\Autoload;
14 |
15 | /**
16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
17 | *
18 | * $loader = new \Composer\Autoload\ClassLoader();
19 | *
20 | * // register classes with namespaces
21 | * $loader->add('Symfony\Component', __DIR__.'/component');
22 | * $loader->add('Symfony', __DIR__.'/framework');
23 | *
24 | * // activate the autoloader
25 | * $loader->register();
26 | *
27 | * // to enable searching the include path (eg. for PEAR packages)
28 | * $loader->setUseIncludePath(true);
29 | *
30 | * In this example, if you try to use a class in the Symfony\Component
31 | * namespace or one of its children (Symfony\Component\Console for instance),
32 | * the autoloader will first look for the class under the component/
33 | * directory, and it will then fallback to the framework/ directory if not
34 | * found before giving up.
35 | *
36 | * This class is loosely based on the Symfony UniversalClassLoader.
37 | *
38 | * @author Fabien Potencier
39 | * @author Jordi Boggiano
40 | * @see http://www.php-fig.org/psr/psr-0/
41 | * @see http://www.php-fig.org/psr/psr-4/
42 | */
43 | class ClassLoader
44 | {
45 | // PSR-4
46 | private $prefixLengthsPsr4 = array();
47 | private $prefixDirsPsr4 = array();
48 | private $fallbackDirsPsr4 = array();
49 |
50 | // PSR-0
51 | private $prefixesPsr0 = array();
52 | private $fallbackDirsPsr0 = array();
53 |
54 | private $useIncludePath = false;
55 | private $classMap = array();
56 |
57 | private $classMapAuthoritative = false;
58 |
59 | public function getPrefixes()
60 | {
61 | if (!empty($this->prefixesPsr0)) {
62 | return call_user_func_array('array_merge', $this->prefixesPsr0);
63 | }
64 |
65 | return array();
66 | }
67 |
68 | public function getPrefixesPsr4()
69 | {
70 | return $this->prefixDirsPsr4;
71 | }
72 |
73 | public function getFallbackDirs()
74 | {
75 | return $this->fallbackDirsPsr0;
76 | }
77 |
78 | public function getFallbackDirsPsr4()
79 | {
80 | return $this->fallbackDirsPsr4;
81 | }
82 |
83 | public function getClassMap()
84 | {
85 | return $this->classMap;
86 | }
87 |
88 | /**
89 | * @param array $classMap Class to filename map
90 | */
91 | public function addClassMap(array $classMap)
92 | {
93 | if ($this->classMap) {
94 | $this->classMap = array_merge($this->classMap, $classMap);
95 | } else {
96 | $this->classMap = $classMap;
97 | }
98 | }
99 |
100 | /**
101 | * Registers a set of PSR-0 directories for a given prefix, either
102 | * appending or prepending to the ones previously set for this prefix.
103 | *
104 | * @param string $prefix The prefix
105 | * @param array|string $paths The PSR-0 root directories
106 | * @param bool $prepend Whether to prepend the directories
107 | */
108 | public function add($prefix, $paths, $prepend = false)
109 | {
110 | if (!$prefix) {
111 | if ($prepend) {
112 | $this->fallbackDirsPsr0 = array_merge(
113 | (array) $paths,
114 | $this->fallbackDirsPsr0
115 | );
116 | } else {
117 | $this->fallbackDirsPsr0 = array_merge(
118 | $this->fallbackDirsPsr0,
119 | (array) $paths
120 | );
121 | }
122 |
123 | return;
124 | }
125 |
126 | $first = $prefix[0];
127 | if (!isset($this->prefixesPsr0[$first][$prefix])) {
128 | $this->prefixesPsr0[$first][$prefix] = (array) $paths;
129 |
130 | return;
131 | }
132 | if ($prepend) {
133 | $this->prefixesPsr0[$first][$prefix] = array_merge(
134 | (array) $paths,
135 | $this->prefixesPsr0[$first][$prefix]
136 | );
137 | } else {
138 | $this->prefixesPsr0[$first][$prefix] = array_merge(
139 | $this->prefixesPsr0[$first][$prefix],
140 | (array) $paths
141 | );
142 | }
143 | }
144 |
145 | /**
146 | * Registers a set of PSR-4 directories for a given namespace, either
147 | * appending or prepending to the ones previously set for this namespace.
148 | *
149 | * @param string $prefix The prefix/namespace, with trailing '\\'
150 | * @param array|string $paths The PSR-4 base directories
151 | * @param bool $prepend Whether to prepend the directories
152 | *
153 | * @throws \InvalidArgumentException
154 | */
155 | public function addPsr4($prefix, $paths, $prepend = false)
156 | {
157 | if (!$prefix) {
158 | // Register directories for the root namespace.
159 | if ($prepend) {
160 | $this->fallbackDirsPsr4 = array_merge(
161 | (array) $paths,
162 | $this->fallbackDirsPsr4
163 | );
164 | } else {
165 | $this->fallbackDirsPsr4 = array_merge(
166 | $this->fallbackDirsPsr4,
167 | (array) $paths
168 | );
169 | }
170 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
171 | // Register directories for a new namespace.
172 | $length = strlen($prefix);
173 | if ('\\' !== $prefix[$length - 1]) {
174 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
175 | }
176 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
177 | $this->prefixDirsPsr4[$prefix] = (array) $paths;
178 | } elseif ($prepend) {
179 | // Prepend directories for an already registered namespace.
180 | $this->prefixDirsPsr4[$prefix] = array_merge(
181 | (array) $paths,
182 | $this->prefixDirsPsr4[$prefix]
183 | );
184 | } else {
185 | // Append directories for an already registered namespace.
186 | $this->prefixDirsPsr4[$prefix] = array_merge(
187 | $this->prefixDirsPsr4[$prefix],
188 | (array) $paths
189 | );
190 | }
191 | }
192 |
193 | /**
194 | * Registers a set of PSR-0 directories for a given prefix,
195 | * replacing any others previously set for this prefix.
196 | *
197 | * @param string $prefix The prefix
198 | * @param array|string $paths The PSR-0 base directories
199 | */
200 | public function set($prefix, $paths)
201 | {
202 | if (!$prefix) {
203 | $this->fallbackDirsPsr0 = (array) $paths;
204 | } else {
205 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
206 | }
207 | }
208 |
209 | /**
210 | * Registers a set of PSR-4 directories for a given namespace,
211 | * replacing any others previously set for this namespace.
212 | *
213 | * @param string $prefix The prefix/namespace, with trailing '\\'
214 | * @param array|string $paths The PSR-4 base directories
215 | *
216 | * @throws \InvalidArgumentException
217 | */
218 | public function setPsr4($prefix, $paths)
219 | {
220 | if (!$prefix) {
221 | $this->fallbackDirsPsr4 = (array) $paths;
222 | } else {
223 | $length = strlen($prefix);
224 | if ('\\' !== $prefix[$length - 1]) {
225 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
226 | }
227 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
228 | $this->prefixDirsPsr4[$prefix] = (array) $paths;
229 | }
230 | }
231 |
232 | /**
233 | * Turns on searching the include path for class files.
234 | *
235 | * @param bool $useIncludePath
236 | */
237 | public function setUseIncludePath($useIncludePath)
238 | {
239 | $this->useIncludePath = $useIncludePath;
240 | }
241 |
242 | /**
243 | * Can be used to check if the autoloader uses the include path to check
244 | * for classes.
245 | *
246 | * @return bool
247 | */
248 | public function getUseIncludePath()
249 | {
250 | return $this->useIncludePath;
251 | }
252 |
253 | /**
254 | * Turns off searching the prefix and fallback directories for classes
255 | * that have not been registered with the class map.
256 | *
257 | * @param bool $classMapAuthoritative
258 | */
259 | public function setClassMapAuthoritative($classMapAuthoritative)
260 | {
261 | $this->classMapAuthoritative = $classMapAuthoritative;
262 | }
263 |
264 | /**
265 | * Should class lookup fail if not found in the current class map?
266 | *
267 | * @return bool
268 | */
269 | public function isClassMapAuthoritative()
270 | {
271 | return $this->classMapAuthoritative;
272 | }
273 |
274 | /**
275 | * Registers this instance as an autoloader.
276 | *
277 | * @param bool $prepend Whether to prepend the autoloader or not
278 | */
279 | public function register($prepend = false)
280 | {
281 | spl_autoload_register(array($this, 'loadClass'), true, $prepend);
282 | }
283 |
284 | /**
285 | * Unregisters this instance as an autoloader.
286 | */
287 | public function unregister()
288 | {
289 | spl_autoload_unregister(array($this, 'loadClass'));
290 | }
291 |
292 | /**
293 | * Loads the given class or interface.
294 | *
295 | * @param string $class The name of the class
296 | * @return bool|null True if loaded, null otherwise
297 | */
298 | public function loadClass($class)
299 | {
300 | if ($file = $this->findFile($class)) {
301 | includeFile($file);
302 |
303 | return true;
304 | }
305 | }
306 |
307 | /**
308 | * Finds the path to the file where the class is defined.
309 | *
310 | * @param string $class The name of the class
311 | *
312 | * @return string|false The path if found, false otherwise
313 | */
314 | public function findFile($class)
315 | {
316 | // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
317 | if ('\\' == $class[0]) {
318 | $class = substr($class, 1);
319 | }
320 |
321 | // class map lookup
322 | if (isset($this->classMap[$class])) {
323 | return $this->classMap[$class];
324 | }
325 | if ($this->classMapAuthoritative) {
326 | return false;
327 | }
328 |
329 | $file = $this->findFileWithExtension($class, '.php');
330 |
331 | // Search for Hack files if we are running on HHVM
332 | if ($file === null && defined('HHVM_VERSION')) {
333 | $file = $this->findFileWithExtension($class, '.hh');
334 | }
335 |
336 | if ($file === null) {
337 | // Remember that this class does not exist.
338 | return $this->classMap[$class] = false;
339 | }
340 |
341 | return $file;
342 | }
343 |
344 | private function findFileWithExtension($class, $ext)
345 | {
346 | // PSR-4 lookup
347 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
348 |
349 | $first = $class[0];
350 | if (isset($this->prefixLengthsPsr4[$first])) {
351 | foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
352 | if (0 === strpos($class, $prefix)) {
353 | foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
354 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
355 | return $file;
356 | }
357 | }
358 | }
359 | }
360 | }
361 |
362 | // PSR-4 fallback dirs
363 | foreach ($this->fallbackDirsPsr4 as $dir) {
364 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
365 | return $file;
366 | }
367 | }
368 |
369 | // PSR-0 lookup
370 | if (false !== $pos = strrpos($class, '\\')) {
371 | // namespaced class name
372 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
373 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
374 | } else {
375 | // PEAR-like class name
376 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
377 | }
378 |
379 | if (isset($this->prefixesPsr0[$first])) {
380 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
381 | if (0 === strpos($class, $prefix)) {
382 | foreach ($dirs as $dir) {
383 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
384 | return $file;
385 | }
386 | }
387 | }
388 | }
389 | }
390 |
391 | // PSR-0 fallback dirs
392 | foreach ($this->fallbackDirsPsr0 as $dir) {
393 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
394 | return $file;
395 | }
396 | }
397 |
398 | // PSR-0 include paths.
399 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
400 | return $file;
401 | }
402 | }
403 | }
404 |
405 | /**
406 | * Scope isolated include.
407 | *
408 | * Prevents access to $this/self from included files.
409 | */
410 | function includeFile($file)
411 | {
412 | include $file;
413 | }
414 |
--------------------------------------------------------------------------------
/vendor/composer/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Copyright (c) 2016 Nils Adermann, Jordi Boggiano
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is furnished
9 | to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/vendor/composer/autoload_classmap.php:
--------------------------------------------------------------------------------
1 | array($baseDir . '/src'),
10 | );
11 |
--------------------------------------------------------------------------------
/vendor/composer/autoload_real.php:
--------------------------------------------------------------------------------
1 | $path) {
28 | $loader->set($namespace, $path);
29 | }
30 |
31 | $map = require __DIR__ . '/autoload_psr4.php';
32 | foreach ($map as $namespace => $path) {
33 | $loader->setPsr4($namespace, $path);
34 | }
35 |
36 | $classMap = require __DIR__ . '/autoload_classmap.php';
37 | if ($classMap) {
38 | $loader->addClassMap($classMap);
39 | }
40 |
41 | $loader->register(true);
42 |
43 | return $loader;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/vendor/composer/installed.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------