├── .babelrc ├── .editorconfig ├── .env.sample ├── .gitattributes ├── .gitignore ├── .htaccess ├── LICENSE ├── README.md ├── app ├── Http │ ├── Controller │ │ ├── Controller.php │ │ ├── ExceptionController.php │ │ └── IndexController.php │ ├── Exception │ │ ├── DefaultException.php │ │ ├── ErrorException.php │ │ └── MiddlewareException.php │ ├── Mapping.php │ ├── Middleware │ │ └── Authenticate.php │ └── Model │ │ └── Model.php ├── Provider │ ├── Listen │ │ ├── ApplicationListener.php │ │ ├── DbListener.php │ │ ├── DispatchListener.php │ │ └── RouterListener.php │ ├── Service │ │ ├── AbstractClass.php │ │ └── Adaptor.php │ └── Support │ │ ├── AbstractClass.php │ │ ├── Adaptor.php │ │ └── HelpClass.php ├── System │ ├── ErrorHandler.php │ ├── Language.php │ ├── Middleware.php │ └── Route.php ├── helper.php ├── kernel.php └── service.php ├── assets ├── css │ └── .gitkeep ├── fonts │ └── .gitkeep ├── images │ └── .gitkeep ├── js │ └── .gitkeep └── lang │ └── en_US │ └── message.php ├── bin └── .gitignore ├── composer.json ├── config ├── app.php ├── cache.php ├── database.php ├── routes │ └── web.php └── session.php ├── docs ├── examples │ ├── DemoController.php │ ├── DemoModel.php │ ├── LogsComponent.php │ ├── QueueComponent.php │ └── routes.php ├── grpc.md ├── gulp │ ├── README.md │ ├── gulpfile.default.js │ ├── gulpfile.webapp.js │ ├── index.html │ ├── modernizr.json │ └── package.json └── nginx │ ├── nginx.conf │ ├── nginx.http.conf │ └── nginx.https.conf ├── public ├── .htaccess ├── favicon.ico └── index.php ├── templates ├── default │ ├── default.phtml │ └── statusNotFound.phtml └── html │ └── defaultHandler.html └── var ├── cache └── .gitignore ├── log └── .gitignore └── session └── .gitignore /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # change these settings to your own preference 11 | indent_style = space 12 | indent_size = 4 13 | 14 | # we recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | 23 | [*.{yml,json,xml}] 24 | indent_size = 2 25 | 26 | [{package.json,.babelrc}] 27 | indent_style = space 28 | indent_size = 2 29 | -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | APP_NAME=zLab 2 | APP_ENV=prod 3 | APP_KEY= 4 | APP_TIMEZONE=UTC 5 | APP_URL=http://localhost 6 | 7 | DB_CONNECTION=mysql 8 | DB_HOST=127.0.0.1 9 | DB_PORT=3306 10 | DB_NAME= 11 | DB_USER= 12 | DB_PASS= 13 | 14 | MONGO_HOST=127.0.0.1 15 | MONGO_PORT=27017 16 | MONGO_NAME= 17 | MONGO_USER= 18 | MONGO_PASS= 19 | 20 | REDIS_HOST=127.0.0.1 21 | REDIS_PORT=6379 22 | REDIS_NAME= 23 | REDIS_PASS= 24 | 25 | CACHE_HOST=127.0.0.1 26 | CACHE_PORT=6379 27 | CACHE_NAME= 28 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | bower_components 4 | package-lock.json 5 | 6 | # compiled output 7 | /build 8 | /dist 9 | 10 | # System Files 11 | .DS_Store 12 | Thumbs.db 13 | 14 | # editor 15 | .idea/ 16 | 17 | # project 18 | .env 19 | .env.local 20 | composer.lock 21 | public/ 22 | var/ 23 | vendor/ 24 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine on 3 | RewriteRule ^$ public/ [L] 4 | RewriteRule (.*) public/$1 [L] 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2019 Joe Chu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## About Phalcon 2 | 基于Phalcon的高性能PHP框架,集成Composer 支持MongoDB Redis操作,监听器,中间件,以及多语言支持 3 | 4 | [![GitHub license](https://img.shields.io/github/license/xxtime/phalcon.svg)](https://github.com/xxtime/phalcon) 5 | [![Twitter](https://img.shields.io/twitter/url/https/github.com/xxtime/phalcon.svg?style=social)](https://twitter.com/intent/tweet?text=Wow:&url=https%3A%2F%2Fgithub.com%2Fxxtime%2Fphalcon) 6 | 7 | * A framework which use phalcon 8 | * High performance 9 | * Composer 10 | * Database support Redis, MongoDB, MySql 11 | * Event listener 12 | * Middleware 13 | * I18n translate 14 | * Debugging easier with whoops project 15 | 16 | 17 | ## Environment 18 | * php >= 8.1 19 | * phalcon >= 5.7 20 | * composer 21 | 22 | 23 | ## Advice 24 | * Mcrypt was DEPRECATED in PHP 7.1.0, and REMOVED in PHP 7.2.0. 25 | 26 | 27 | ## How to use 28 | 1. cd to /{$root}/ 29 | 2. copy .env.sample to .env or .env.local 30 | 31 | 32 | ## Components 33 | | component | intro | document | 34 | |-----------------------------------------------------------------------------------------------------|----------------------|------------------------------------------------------------| 35 | | [laminas/laminas-permissions-rbac](https://packagist.org/packages/laminas/laminas-permissions-rbac) | RBAC | [docs](https://docs.laminas.dev/laminas-permissions-rbac/) | 36 | | [laminas/laminas-crypt](https://packagist.org/packages/laminas/laminas-crypt) | 加密和密码HASH | [docs](https://docs.laminas.dev/laminas-crypt/) | 37 | | [firebase/php-jwt](https://packagist.org/packages/firebase/php-jwt) | JWT(JSON Web Tokens) | [docs](https://github.com/firebase/php-jwt) | 38 | | [endroid/qr-code](https://packagist.org/packages/endroid/qr-code) | 用于生成二维码 | [docs](https://github.com/endroid/qr-code) | 39 | | [phpgangsta/googleauthenticator](https://packagist.org/packages/phpgangsta/googleauthenticator) | 令牌验证相关 | [docs](https://github.com/PHPGangsta/GoogleAuthenticator) | 40 | | [overtrue/wechat](https://packagist.org/packages/overtrue/wechat) | 微信SDK | [docs](https://easywechat.org/) | 41 | | [omnipay/omnipay](https://packagist.org/packages/omnipay/omnipay) | 支付Omnipay | [docs](http://omnipay.thephpleague.com/) | 42 | | [xxtime/paytime](https://packagist.org/packages/xxtime/paytime) | 支付PayTime | [docs](https://github.com/xxtime/paytime) | 43 | | [geoip2/geoip2](https://packagist.org/packages/geoip2/geoip2) | 地理位置分析 | [docs](http://maxmind.github.io/GeoIP2-php/) | 44 | | [league/oauth2-server](https://packagist.org/packages/league/oauth2-server) | Auth2.0 Server | [docs](http://oauth2.thephpleague.com/) | 45 | | [bshaffer/oauth2-server-php](https://packagist.org/packages/bshaffer/oauth2-server-php) | Auth2.0 Server | [docs](https://bshaffer.github.io/oauth2-server-php-docs/) | 46 | | [league/oauth2-client](https://packagist.org/packages/league/oauth2-client) | Auth2.0 Client | [docs](http://oauth2-client.thephpleague.com/) | 47 | | [mobiledetect/mobiledetectlib](https://packagist.org/packages/mobiledetect/mobiledetectlib) | 设备识别 | [docs](http://mobiledetect.net/) | 48 | | [mongodb/mongodb](https://packagist.org/packages/mongodb/mongodb) | MongoDB抽象层 | [docs](https://docs.mongodb.com/php-library/) | 49 | | [hashids/hashids](https://packagist.org/packages/hashids/hashids) | Hashids | [docs](http://hashids.org/php/) | 50 | | [jenssegers/optimus](https://packagist.org/packages/jenssegers/optimus) | ID转换 | [docs](https://github.com/jenssegers/optimus) | 51 | | [league/climate](https://packagist.org/packages/league/climate) | 命令行颜色 | [docs](http://climate.thephpleague.com/) | 52 | 53 | ## Reference 54 | * [Aura](http://auraphp.com/) 55 | * [Hoa](https://hoa-project.net/En/) 56 | * [thephpleague](http://thephpleague.com/) 57 | * [laminas components](https://docs.laminas.dev/components/) 58 | * [symfony components](http://symfony.com/doc/current/components/index.html) 59 | * [github awesome lists](https://github.com/sindresorhus/awesome) 60 | * [github ziadoz awesome-php](https://github.com/ziadoz/awesome-php) 61 | * [github JingwenTian awesome-php](https://github.com/JingwenTian/awesome-php) 62 | * [github jobbole awesome-php-cn](https://github.com/jobbole/awesome-php-cn) 63 | * [github phalcon awesome-phalcon](https://github.com/phalcon/awesome-phalcon) 64 | 65 | 66 | ## About 67 | * Project : [https://github.com/xxtime/phalcon](https://github.com/xxtime/phalcon) 68 | * Document : [https://docs.phalconphp.com](https://docs.phalconphp.com) 69 | * Author : [https://zlab.dev](https://zlab.dev) 70 | -------------------------------------------------------------------------------- /app/Http/Controller/Controller.php: -------------------------------------------------------------------------------- 1 | response->setStatusCode(404, 'Not Found'); 23 | $this->view->pick("default/statusNotFound"); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/Http/Controller/IndexController.php: -------------------------------------------------------------------------------- 1 | view->setVars([ 24 | "pha_version" => $version->get(), 25 | "php_version" => phpversion(), 26 | ]); 27 | $this->view->pick("default/default"); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/Http/Exception/DefaultException.php: -------------------------------------------------------------------------------- 1 | router = $this->di->get('router'); 38 | $controllerName = $this->router->getControllerName(); 39 | if (in_array($controllerName, $this->except)) { 40 | return true; 41 | } 42 | 43 | // do something check authenticate 44 | return true; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app/Http/Model/Model.php: -------------------------------------------------------------------------------- 1 | getSQLStatement())) { 24 | $di->get('logger')->warn('DISABLE: ' . $pdo->getSQLStatement()); 25 | throw new ErrorException("Disable SQL Statement"); 26 | } 27 | if ($di['config']->path("app.env") == 'dev') { 28 | $di->get('logger')->warn($pdo->getSQLStatement()); 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /app/Provider/Listen/DispatchListener.php: -------------------------------------------------------------------------------- 1 | middleware as $value) { 33 | if (class_exists($value)) { 34 | $class = new $value($this->getDI()); 35 | if ($class->handle($this->request) !== true) { 36 | throw new MiddlewareException($value, 500); 37 | } 38 | } 39 | } 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /app/Provider/Service/AbstractClass.php: -------------------------------------------------------------------------------- 1 | di = $di; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /app/Provider/Service/Adaptor.php: -------------------------------------------------------------------------------- 1 | di = $di; 22 | } 23 | 24 | public function __get($name) 25 | { 26 | $name = ucfirst($name); 27 | if (isset($this->register[$name])) { 28 | return $this->register[$name]; 29 | } 30 | $class = "\\App\\Provider\\Service\\{$name}Class"; 31 | $this->register[$name] = new $class($this->di); 32 | return $this->register[$name]; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/Provider/Support/AbstractClass.php: -------------------------------------------------------------------------------- 1 | di = $di; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /app/Provider/Support/Adaptor.php: -------------------------------------------------------------------------------- 1 | di = $di; 25 | } 26 | 27 | public function __get($name) 28 | { 29 | $name = ucfirst($name); 30 | if (isset($this->register[$name])) { 31 | return $this->register[$name]; 32 | } 33 | $class = "\\App\\Provider\\Support\\{$name}Class"; 34 | $this->register[$name] = new $class($this->di); 35 | return $this->register[$name]; 36 | } 37 | 38 | public function getProcessId() 39 | { 40 | if ($this->processId != null) { 41 | return $this->processId; 42 | } 43 | return $this->processId = $this->help->randString(32); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/Provider/Support/HelpClass.php: -------------------------------------------------------------------------------- 1 | path = $path; 27 | } 28 | 29 | public function register() 30 | { 31 | $this->setErrorHandler([$this, self::ERROR_HANDLER]); 32 | $this->setExceptionHandler([$this, self::EXCEPTION_HANDLER]); 33 | $this->registerShutdownFunction([$this, self::SHUTDOWN_HANDLER]); 34 | } 35 | 36 | public function setErrorHandler(callable $handler, $types = 'use-php-defaults') 37 | { 38 | if ($types === 'use-php-defaults') { 39 | $types = E_ALL; 40 | } 41 | return set_error_handler($handler, $types); 42 | } 43 | 44 | public function setExceptionHandler(callable $handler) 45 | { 46 | return set_exception_handler($handler); 47 | } 48 | 49 | public function registerShutdownFunction(callable $function) 50 | { 51 | register_shutdown_function($function); 52 | } 53 | 54 | public function handleException($exception) 55 | { 56 | exit(file_get_contents(ROOT_DIR . "templates/" . $this->path)); 57 | } 58 | 59 | public function handleError($level, $message, $file = null, $line = null) 60 | { 61 | exit(file_get_contents(ROOT_DIR . "templates/" . $this->path)); 62 | } 63 | 64 | public function handleShutdown() 65 | { 66 | } 67 | 68 | } 69 | 70 | -------------------------------------------------------------------------------- /app/System/Language.php: -------------------------------------------------------------------------------- 1 | lang) { 35 | return $this->lang; 36 | } 37 | return $this->config->app->lang; 38 | } 39 | 40 | 41 | public function setLang($lang = 'en_US') 42 | { 43 | $this->lang = $lang; 44 | } 45 | 46 | 47 | public function t($translateKey, array $placeholders = null) 48 | { 49 | if (!$this->translator) { 50 | $this->translator = $this->getTranslator(); 51 | } 52 | return $this->translator->_($translateKey, $placeholders); 53 | } 54 | 55 | 56 | public function _($translateKey, array $placeholders = null) 57 | { 58 | return $this->t($translateKey, $placeholders); 59 | } 60 | 61 | 62 | private function getTranslator($file = 'message') 63 | { 64 | $path = ASSETS_DIR . 'lang/' . $this->getLang() . DIRECTORY_SEPARATOR . $file . '.php'; 65 | 66 | if (file_exists($path)) { 67 | $messages = include $path; 68 | } 69 | else { 70 | $messages = include ASSETS_DIR . 'lang/' . $this->config->app->lang . DIRECTORY_SEPARATOR . $file . '.php'; 71 | } 72 | 73 | return new NativeArray(new InterpolatorFactory(), [ 74 | 'content' => $messages, 75 | ]); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /app/System/Middleware.php: -------------------------------------------------------------------------------- 1 | di = $di; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/System/Route.php: -------------------------------------------------------------------------------- 1 | addResource('/product', 'V1\Product','{id:[a-z0-9]{1,24}}')->only('get'); 15 | * $r->addResource('/news', 'V1\News')->except('delete'); 16 | */ 17 | 18 | namespace App\System; 19 | 20 | use Phalcon\Mvc\Router\Group; 21 | use Exception; 22 | 23 | class Route 24 | { 25 | 26 | private $router; 27 | 28 | 29 | private $resource; 30 | 31 | 32 | private $idFormat = '{id:[a-z0-9]{1,24}}'; 33 | 34 | 35 | private $allowAction = ['index', 'get', 'post', 'put', 'delete']; 36 | 37 | 38 | private $_uri; 39 | 40 | 41 | public function __construct(&$router) 42 | { 43 | $this->router = $router; 44 | } 45 | 46 | 47 | public function __destruct() 48 | { 49 | $this->mountRoute(); 50 | } 51 | 52 | 53 | public function setIdFormat($format = '') 54 | { 55 | if (!$format) { 56 | return false; 57 | } 58 | $this->idFormat = $format; 59 | } 60 | 61 | 62 | public function getIdFormat() 63 | { 64 | return $this->idFormat; 65 | } 66 | 67 | 68 | public function addResource($uri = '', $handle = null, $idFormat = null) 69 | { 70 | if (!$uri || !$handle) { 71 | throw new Exception('invalid resource'); 72 | } 73 | $this->_uri = $uri; 74 | $this->resource[$uri] = [ 75 | 'regular' => $idFormat ? $idFormat : $this->getIdFormat(), 76 | 'handle' => ucfirst($handle), 77 | ]; 78 | return $this; 79 | } 80 | 81 | 82 | public function only(...$action) 83 | { 84 | $this->resource[$this->_uri]['action'] = $action; 85 | } 86 | 87 | 88 | public function except(...$action) 89 | { 90 | $this->resource[$this->_uri]['action'] = array_diff($this->allowAction, $action); 91 | } 92 | 93 | 94 | private function mountRoute() 95 | { 96 | foreach ($this->resource as $uri => $value) { 97 | $group = new Group(['controller' => $value['handle']]); 98 | $group->setPrefix($uri); 99 | if (empty($value['action'])) { 100 | $value['action'] = $this->allowAction; 101 | } 102 | foreach ($value['action'] as $action) { 103 | switch ($action) { 104 | case 'index': 105 | $group->addGet('', ['action' => 'index']); 106 | break; 107 | case 'post': 108 | $group->addPost('', ['action' => 'post']); 109 | break; 110 | case 'get': 111 | $group->addGet('/' . $value['regular'], ['action' => 'get']); 112 | break; 113 | case 'put': 114 | $group->addPut('', ['action' => 'put']); 115 | $group->addPut('/' . $value['regular'], ['action' => 'put']); 116 | break; 117 | case 'delete': 118 | $group->addDelete('', ['action' => 'delete']); 119 | $group->addDelete('/' . $value['regular'], ['action' => 'delete']); 120 | break; 121 | default: 122 | throw new Exception('invalid route action'); 123 | $group->add('/' . $value['regular'], ['action' => $action]); 124 | } 125 | } 126 | $this->router->mount($group); 127 | } 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /app/helper.php: -------------------------------------------------------------------------------- 1 | 1 && $value[0] === '"' && $value[$valueLength - 1] === '"') { 45 | return substr($value, 1, -1); 46 | } 47 | return $value; 48 | } 49 | } 50 | 51 | if (!function_exists('loadEnv')) { 52 | function loadEnv() 53 | { 54 | if (file_exists(ROOT_DIR . '.env.local')) { 55 | $path = ROOT_DIR . '.env.local'; 56 | } 57 | elseif (file_exists(ROOT_DIR . '.env')) { 58 | $path = ROOT_DIR . '.env'; 59 | } 60 | else { 61 | return false; 62 | } 63 | $autodetect = ini_get('auto_detect_line_endings'); 64 | ini_set('auto_detect_line_endings', '1'); 65 | $lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); 66 | ini_set('auto_detect_line_endings', $autodetect); 67 | foreach ($lines as $line) { 68 | list($name, $value) = explode('=', $line); 69 | putenv("{$name}={$value}"); 70 | } 71 | } 72 | } 73 | 74 | if (!function_exists('config')) { 75 | function config($string) 76 | { 77 | return $GLOBALS['app']->di['config']->path($string); 78 | } 79 | } 80 | 81 | if (!function_exists('getAllHeaders')) { 82 | /** 83 | * @doc https://github.com/ralouphie/getallheaders 84 | * Get all HTTP header key/values as an associative array for the current request. 85 | * @return string[string] The HTTP header key/value pairs. 86 | */ 87 | function getAllHeaders() 88 | { 89 | $headers = array(); 90 | $copy_server = array( 91 | 'CONTENT_TYPE' => 'Content-Type', 92 | 'CONTENT_LENGTH' => 'Content-Length', 93 | 'CONTENT_MD5' => 'Content-Md5', 94 | ); 95 | foreach ($_SERVER as $key => $value) { 96 | if (substr($key, 0, 5) === 'HTTP_') { 97 | $key = substr($key, 5); 98 | if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) { 99 | $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key)))); 100 | $headers[$key] = $value; 101 | } 102 | } 103 | elseif (isset($copy_server[$key])) { 104 | $headers[$copy_server[$key]] = $value; 105 | } 106 | } 107 | if (!isset($headers['Authorization'])) { 108 | if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { 109 | $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; 110 | } 111 | elseif (isset($_SERVER['PHP_AUTH_USER'])) { 112 | $basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : ''; 113 | $headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass); 114 | } 115 | elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) { 116 | $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST']; 117 | } 118 | } 119 | return $headers; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /app/kernel.php: -------------------------------------------------------------------------------- 1 | loader(); 31 | 32 | $this->setting(); 33 | 34 | $this->kernel(); 35 | } 36 | 37 | 38 | public function loader() 39 | { 40 | $loader = new Loader(); 41 | $loader->setNamespaces(array( 42 | 'App' => APP_DIR, 43 | ))->register(); 44 | 45 | require_once ROOT_DIR . 'vendor/autoload.php'; 46 | require_once APP_DIR . 'helper.php'; 47 | $this->di = require_once APP_DIR . 'service.php'; 48 | 49 | loadEnv(); 50 | } 51 | 52 | 53 | public function setting() 54 | { 55 | 56 | ini_set("date.timezone", $this->di['config']->app->timezone); 57 | 58 | /* 59 | | Setting ENV 60 | |------------------------------------------------------------------ 61 | */ 62 | switch ($this->di['config']->app->env != 'prod') { 63 | case true: 64 | $whoops = new \Whoops\Run; 65 | $whoops->appendHandler(new \Whoops\Handler\PrettyPageHandler); 66 | $whoops->register(); 67 | break; 68 | default: 69 | $handler = new ErrorHandler(); 70 | $handler->setTemplate("html/defaultHandler.html"); 71 | $handler->register(); 72 | }; 73 | 74 | /* 75 | | Setting Listeners 76 | |------------------------------------------------------------------ 77 | | 78 | | config/app.php listeners 79 | | 80 | */ 81 | foreach ($this->di['config']->path('app.listeners') as $name => $listener) { 82 | $this->di['eventsManager']->attach($name, new $listener); 83 | } 84 | 85 | } 86 | 87 | 88 | public function kernel() 89 | { 90 | $application = new Application($this->di); 91 | $application->setEventsManager($this->di['eventsManager']); 92 | if ($this->di['config']->path('app.disableView')) { 93 | $application->useImplicitView(false); 94 | } 95 | $application->handle($_SERVER["REQUEST_URI"])->send(); 96 | } 97 | 98 | 99 | } 100 | 101 | 102 | $app = new Framework; 103 | 104 | return $app; 105 | -------------------------------------------------------------------------------- /app/service.php: -------------------------------------------------------------------------------- 1 | set('config', function () { 40 | $config = new Config(['app' => include CONFIG_DIR . "app.php"]); 41 | $c = []; 42 | foreach ($config->path("app.config") as $name => $item) { 43 | $c[$name] = include $item; 44 | } 45 | $config->merge(new Config($c)); 46 | return $config; 47 | }, true); 48 | 49 | 50 | $di->set('lang', new System\Language(), true); 51 | 52 | 53 | $di->set('router', function () use ($di) { 54 | $router = require ROOT_DIR . 'config/routes/web.php'; 55 | $router->setEventsManager($di->get('eventsManager')); 56 | return $router; 57 | }, true); 58 | 59 | 60 | $di->set('logger', function () { 61 | // @docs https://docs.laminas.dev/laminas-log 62 | $wDef = new LogStream(DATA_DIR . 'log/main.log'); 63 | 64 | $wErr = new LogStream(DATA_DIR . 'log/error.log'); 65 | $wErr->addFilter(new \Laminas\Log\Filter\Priority(Logger::ERR)); 66 | 67 | $wWar = new LogStream(DATA_DIR . 'log/warn.log'); 68 | $wWar->addFilter(new \Laminas\Log\Filter\Priority(Logger::WARN, "=")); 69 | 70 | $wInf = new LogStream(DATA_DIR . 'log/info.log'); 71 | $wInf->addFilter(new \Laminas\Log\Filter\Priority(Logger::INFO, "=")); 72 | 73 | $wDeb = new LogStream(DATA_DIR . 'log/debug.log'); 74 | $wDeb->addFilter(new \Laminas\Log\Filter\Priority(Logger::DEBUG, "=")); 75 | 76 | $logger = new Logger(); 77 | $logger->addWriter($wDef); 78 | $logger->addWriter($wErr); 79 | $logger->addWriter($wWar); 80 | $logger->addWriter($wInf); 81 | $logger->addWriter($wDeb); 82 | 83 | return $logger; 84 | }, true); 85 | 86 | 87 | $di->set('crypt', function () use ($di) { 88 | $crypt = new Crypt(); 89 | $crypt->setKey($di['config']->app->key); 90 | return $crypt; 91 | }, true); 92 | 93 | 94 | $di->set('session', function () use ($di) { 95 | $lifetime = $di["config"]->path("session.lifetime"); 96 | switch ($di["config"]->path("session.driver")) { 97 | case "redis": 98 | $options = [ 99 | 'host' => $di["config"]->path("database.redis.host"), 100 | 'port' => $di["config"]->path("database.redis.port"), 101 | 'index' => $di["config"]->path("database.redis.dbname"), 102 | "persistent" => false, 103 | "lifetime" => $lifetime, 104 | ]; 105 | $session = new Manager(); 106 | $serializerFactory = new SerializerFactory(); 107 | $factory = new AdapterFactory($serializerFactory); 108 | $redis = new Redis($factory, $options); 109 | $session->setAdapter($redis)->start(); 110 | break; 111 | 112 | case "file": 113 | 114 | default: 115 | //ini_set('session.save_path', $di["config"]->path('session.files')); 116 | ini_set('session.gc_maxlifetime', $lifetime); 117 | ini_set("session.cookie_lifetime", $lifetime); 118 | ini_set('session.name', 'SID'); 119 | $session = new Manager(); 120 | $files = new Stream( 121 | [ 122 | 'savePath' => $di["config"]->path('session.files'), 123 | ] 124 | ); 125 | $session->setAdapter($files)->start(); 126 | } 127 | return $session; 128 | }, true); 129 | 130 | 131 | $di->set('dispatcher', function () use ($di) { 132 | $dispatcher = new Dispatcher(); 133 | $dispatcher->setDefaultNamespace('App\Http\Controller'); 134 | $dispatcher->setEventsManager($di['eventsManager']); 135 | return $dispatcher; 136 | }, true); 137 | 138 | 139 | $di->set('voltService', function (ViewBaseInterface $view) use ($di) { 140 | $volt = new Volt($view, $di); 141 | $volt->setOptions( 142 | [ 143 | 'always' => true, 144 | 'extension' => '.php', 145 | 'separator' => '_', 146 | 'stat' => true, 147 | 'path' => DATA_DIR . 'cache/', 148 | 'prefix' => 'cache', 149 | ] 150 | ); 151 | return $volt; 152 | }, true); 153 | 154 | 155 | $di->set('view', function () use ($di) { 156 | $view = new View(); 157 | $view->setViewsDir(ROOT_DIR . 'templates/'); 158 | $view->registerEngines([ 159 | '.phtml' => 'voltService', 160 | ]); 161 | return $view; 162 | }, true); 163 | 164 | 165 | $di->set('modelsCache', function () use ($di) { 166 | $frontCache = new FrontData(["lifetime" => 60]); 167 | if ($di['config']->path("cache.driver") == 'redis') { 168 | return new RedisCache($frontCache, [ 169 | "host" => $di["config"]->path("cache.host"), 170 | "port" => $di["config"]->path("cache.port"), 171 | 'index' => $di["config"]->path("cache.dbname"), 172 | 'prefix' => 'cache|', 173 | ]); 174 | } 175 | return new FileCache($frontCache, ['cacheDir' => DATA_DIR . 'cache/', 'prefix' => 'cache_']); 176 | }, true); 177 | 178 | 179 | $di->set('cache', function () use ($di) { 180 | $redis = new \Redis(); 181 | $redis->connect($di["config"]->path("cache.host"), $di["config"]->path("cache.port")); 182 | $redis->select($di["config"]->path("cache.dbname")); 183 | return $redis; 184 | }, true); 185 | 186 | 187 | $di->set('db', function () use ($di) { 188 | $connection = new Mysql([ 189 | 'host' => $di["config"]->path("database.mysql.host"), 190 | 'port' => $di["config"]->path("database.mysql.port"), 191 | 'username' => $di["config"]->path("database.mysql.user"), 192 | 'password' => $di["config"]->path("database.mysql.pass"), 193 | 'dbname' => $di["config"]->path("database.mysql.dbname"), 194 | 'charset' => $di["config"]->path("database.mysql.charset"), 195 | ]); 196 | $connection->setEventsManager($di['eventsManager']); 197 | return $connection; 198 | }, true); 199 | 200 | 201 | $di->set('redis', function () use ($di) { 202 | $redis = new \Redis(); 203 | $redis->connect($di["config"]->path("database.redis.host"), $di["config"]->path("database.redis.port")); 204 | $redis->select($di["config"]->path("database.redis.dbname")); 205 | return $redis; 206 | }, true); 207 | 208 | 209 | $di->set('mongodb', function () use ($di) { 210 | return new MongoDBClient( 211 | "mongodb://" . $di["config"]->path('database.mongodb.host') . ':' . $di["config"]->path('database.mongodb.port'), 212 | array_filter([ 213 | 'username' => $di["config"]->path('database.mongodb.user'), 214 | 'password' => $di["config"]->path('database.mongodb.pass'), 215 | 'authSource' => $di["config"]->path('database.mongodb.dbname') 216 | ])); 217 | }, true); 218 | 219 | 220 | $di->set('support', new Provider\Support\Adaptor($di), true); 221 | 222 | 223 | $di->set('service', new Provider\Service\Adaptor($di), true); 224 | 225 | return $di; 226 | -------------------------------------------------------------------------------- /assets/css/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxtime/phalcon/277b9bb6e42ae231b6a2e91811846aef3df3777a/assets/css/.gitkeep -------------------------------------------------------------------------------- /assets/fonts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxtime/phalcon/277b9bb6e42ae231b6a2e91811846aef3df3777a/assets/fonts/.gitkeep -------------------------------------------------------------------------------- /assets/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxtime/phalcon/277b9bb6e42ae231b6a2e91811846aef3df3777a/assets/images/.gitkeep -------------------------------------------------------------------------------- /assets/js/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxtime/phalcon/277b9bb6e42ae231b6a2e91811846aef3df3777a/assets/js/.gitkeep -------------------------------------------------------------------------------- /assets/lang/en_US/message.php: -------------------------------------------------------------------------------- 1 | env('APP_NAME', 'zLab'), 14 | 15 | /* 16 | |-------------------------------------------------------------------------- 17 | | Application Environment 18 | |-------------------------------------------------------------------------- 19 | | 20 | | This value determines the "environment" your application is currently 21 | | running in. This may determine how you prefer to configure various 22 | | services your application utilizes. Set this in your ".env" file. 23 | | 24 | */ 25 | 'env' => env('APP_ENV', 'prod'), 26 | 27 | /* 28 | |-------------------------------------------------------------------------- 29 | | Timezone 30 | |-------------------------------------------------------------------------- 31 | | 32 | | Default 'UTC'. EXP: 'PRC', 'Asia/Shanghai' 33 | | 34 | */ 35 | 'timezone' => env('APP_TIMEZONE', 'UTC'), 36 | 37 | /* 38 | |-------------------------------------------------------------------------- 39 | | Language 40 | |-------------------------------------------------------------------------- 41 | | 42 | | Default 'en_US' 43 | | 44 | */ 45 | 'lang' => env('APP_LANG', 'en_US'), 46 | 47 | /* 48 | |-------------------------------------------------------------------------- 49 | | URL 50 | |-------------------------------------------------------------------------- 51 | | 52 | | http://localhost 53 | | 54 | */ 55 | 'url' => env('APP_URL'), 56 | 57 | /* 58 | |-------------------------------------------------------------------------- 59 | | App Key 60 | |-------------------------------------------------------------------------- 61 | | 62 | */ 63 | 'key' => env('APP_KEY'), 64 | 65 | /* 66 | |-------------------------------------------------------------------------- 67 | | App Cipher 68 | |-------------------------------------------------------------------------- 69 | | 70 | | Default 'AES-256-CFB' 71 | | 72 | */ 73 | 'cipher' => env('APP_CIPHER', 'AES-256-CFB'), 74 | 75 | /* 76 | |-------------------------------------------------------------------------- 77 | | System Providers 78 | |-------------------------------------------------------------------------- 79 | | 80 | | Providers list 81 | | 82 | */ 83 | 'providers' => [ 84 | ], 85 | 86 | /* 87 | |-------------------------------------------------------------------------- 88 | | Events Listeners 89 | |-------------------------------------------------------------------------- 90 | | 91 | | Events Listener 92 | | 93 | */ 94 | 'listeners' => [ 95 | 'dispatch' => 'App\Provider\Listen\DispatchListener', 96 | 'application' => 'App\Provider\Listen\ApplicationListener', 97 | 'router' => 'App\Provider\Listen\RouterListener', 98 | 'db' => 'App\Provider\Listen\DbListener', 99 | ], 100 | 101 | /* 102 | |-------------------------------------------------------------------------- 103 | | Config Files 104 | |-------------------------------------------------------------------------- 105 | | 106 | | Put files in config dir 107 | | 108 | */ 109 | 'config' => [ 110 | 'session' => CONFIG_DIR . 'session.php', 111 | 'database' => CONFIG_DIR . 'database.php', 112 | 'cache' => CONFIG_DIR . 'cache.php', 113 | ] 114 | 115 | ]; 116 | -------------------------------------------------------------------------------- /config/cache.php: -------------------------------------------------------------------------------- 1 | env('CACHE_HOST', '127.0.0.1'), 12 | 13 | 'port' => env('CACHE_PORT', 6379), 14 | 15 | 'dbname' => env("CACHE_NAME", 0), 16 | 17 | ]; 18 | -------------------------------------------------------------------------------- /config/database.php: -------------------------------------------------------------------------------- 1 | [ 12 | 'host' => env("DB_HOST", "127.0.0.1"), 13 | 'port' => env("DB_PORT", 3306), 14 | 'user' => env("DB_USER"), 15 | 'pass' => env("DB_PASS"), 16 | 'dbname' => env("DB_NAME"), 17 | 'charset' => env("DB_CHAR", 'utf8mb4') 18 | ], 19 | 20 | 'redis' => [ 21 | 'host' => env("REDIS_HOST", "127.0.0.1"), 22 | 'port' => env("REDIS_PORT", 6379), 23 | 'pass' => env("REDIS_PASS"), 24 | 'dbname' => env("REDIS_NAME", 0) 25 | ], 26 | 27 | 'mongodb' => [ 28 | 'host' => env("MONGO_HOST", "127.0.0.1"), 29 | 'port' => env("MONGO_PORT", 27017), 30 | 'user' => env("MONGO_USER"), 31 | 'pass' => env("MONGO_PASS"), 32 | 'dbname' => env("MONGO_NAME") 33 | ], 34 | 35 | ]; 36 | -------------------------------------------------------------------------------- /config/routes/web.php: -------------------------------------------------------------------------------- 1 | addResource('/products', 'V1\Products'); 17 | * $resource->addResource('/news', 'V1\News', '{id:[0-9]{1,10}}')->only('get'); 18 | * @docs https://docs.phalconphp.com/zh/3.3/routing 19 | */ 20 | 21 | use Phalcon\Mvc\Router; 22 | 23 | $router = new Router(false); 24 | $router->removeExtraSlashes(true); 25 | 26 | $router->notFound(['controller' => 'exception', 'action' => 'statusNotFound']); 27 | $router->add('/', ['controller' => 'index', 'action' => 'index']); 28 | 29 | $router->setDefaultNamespace('App\Http\Controller'); 30 | $router->setDefaultController('index'); 31 | $router->setDefaultAction('index'); 32 | 33 | return $router; 34 | -------------------------------------------------------------------------------- /config/session.php: -------------------------------------------------------------------------------- 1 | env('SESSION_DRIVER', 'file'), 14 | 15 | /* 16 | |-------------------------------------------------------------------------- 17 | | Session Lifetime 18 | |-------------------------------------------------------------------------- 19 | | 20 | | Here you may specify the number of seconds that you wish the session 21 | | to be allowed to remain idle before it expires. 22 | | 23 | */ 24 | 25 | 'lifetime' => env('SESSION_LIFETIME', 86400), 26 | 27 | /* 28 | |-------------------------------------------------------------------------- 29 | | Session File Location 30 | |-------------------------------------------------------------------------- 31 | | 32 | | When using the native session driver, we need a location where session 33 | | files may be stored. A default has been set for you but a different 34 | | location may be specified. This is only needed for file sessions. 35 | | 36 | */ 37 | 38 | 'files' => DATA_DIR . 'session/', 39 | ]; 40 | -------------------------------------------------------------------------------- /docs/examples/DemoController.php: -------------------------------------------------------------------------------- 1 | demoModel = new DemoModel(); 48 | 49 | 50 | // 过滤器 51 | $this->filterModel = new Filter(); 52 | $this->filterModel->add('dataFilter', function ($value) { 53 | return preg_replace('/[^0-9a-zA-Z_\-,.#@*:]/', '', $value); 54 | }); 55 | } 56 | 57 | 58 | public function indexAction() 59 | { 60 | dump('Demo Page'); 61 | } 62 | 63 | 64 | // @see https://docs.phalcon.io/4.0/zh-cn/db-models 65 | public function findAction() 66 | { 67 | $robots = $this->demoModel->find( 68 | array( 69 | "conditions" => "id >= :id:", 70 | "columns" => "id, username,password", 71 | "order" => "username DESC", 72 | "offset" => 0, 73 | "limit" => 10, 74 | "group" => "id, username", 75 | "bind" => array("id" => 1), 76 | //"cache" => array("lifetime" => 3600, "key" => "my-find-key") // 缓存结果集 77 | ) 78 | ); 79 | dump($robots->toArray()); 80 | exit; 81 | 82 | 83 | // 也可以这样 84 | $robots = Robots::query() 85 | ->where("type = :type:") 86 | ->andWhere("year < 2000") 87 | ->bind(array("type" => "mechanical")) 88 | ->order("name") 89 | ->execute(); 90 | 91 | 92 | // 单条记录 93 | $data = $this->demoModel->findFirst(); 94 | 95 | } 96 | 97 | 98 | // 创建记录 更多形式参考save方法 99 | public function createAction() 100 | { 101 | // 方法一 102 | $this->demoModel->name = "Joe"; 103 | $this->demoModel->age = "28"; 104 | $this->demoModel->create(); 105 | return $this->demoModel->id; 106 | } 107 | 108 | 109 | // 创建与更新记录 110 | public function saveAction() 111 | { 112 | // 方法一 113 | $this->demoModel->name = "Joe"; 114 | $this->demoModel->age = "28"; 115 | $this->demoModel->save(); 116 | return $this->demoModel->id; 117 | 118 | 119 | // 方法二 120 | $this->demoModel->save( 121 | array( 122 | "type" => "people", 123 | "name" => "JoeChu", 124 | "year" => 1987 125 | ) 126 | ); 127 | 128 | 129 | // 方法三 130 | $this->demoModel->save($_POST); 131 | 132 | 133 | // 方法四 134 | $this->demoModel->save( 135 | $_POST, 136 | array( 137 | 'name', 138 | 'type' 139 | ) 140 | ); 141 | } 142 | 143 | 144 | // 执行原生 sql 145 | public function executeSql() 146 | { 147 | $sql = "UPDATE users SET name= ?"; 148 | $this->db->execute($sql, ["Alina"]); 149 | } 150 | 151 | 152 | public function demoAction() 153 | { 154 | $this->demoModel->demo(); 155 | } 156 | 157 | 158 | // 过滤器 159 | public function filterAction() 160 | { 161 | $data = $this->request->get('id'); 162 | $data = $this->filterModel->sanitize($data, "dataFilter"); 163 | } 164 | 165 | 166 | public function serviceAction() 167 | { 168 | $response = Services::pay('paypal')->notice(); 169 | dump($response); 170 | } 171 | 172 | 173 | public function quequeAction() 174 | { 175 | $queue = new Queue(); 176 | $queue->publish('queue.name', 'this is queue message'); 177 | } 178 | 179 | 180 | // @see https://docs.phalcon.io/4.0/zh-cn/cookies 181 | public function cookiesAction() 182 | { 183 | $this->cookies->set('foo', 'some cookies', time() + 86400); 184 | $this->cookies->send(); 185 | 186 | if ($this->cookies->has('foo')) { 187 | $value = $this->cookies->get('foo')->getValue(); 188 | } 189 | dd($value); 190 | } 191 | 192 | 193 | // @see https://docs.phalcon.io/4.0/zh-cn/volt 194 | public function templateAction() 195 | { 196 | $this->view->data = time(); 197 | $this->view->pick("demo/template"); 198 | } 199 | 200 | 201 | public function qrAction() 202 | { 203 | // 生成二维码 204 | $username = urlencode('账号:') . 'joe@xxtime.com'; 205 | $secretKey = 'DPI45HCE'; 206 | $url = "otpauth://totp/{$username}?secret={$secretKey}&issuer=" . urlencode('XXTIME.COM'); 207 | $qrCode = new QrCode(); 208 | $qrCode 209 | ->setText($url) 210 | ->setSize(200) 211 | ->setPadding(10) 212 | ->setErrorCorrection('low') 213 | ->setForegroundColor(array('r' => 0, 'g' => 0, 'b' => 0, 'a' => 0)) 214 | ->setBackgroundColor(array('r' => 255, 'g' => 255, 'b' => 255, 'a' => 0)) 215 | //->setLabel('xxtime.com') 216 | //->setLabelFontSize(8) 217 | ->setImageType(QrCode::IMAGE_TYPE_PNG); 218 | header('Content-Type: ' . $qrCode->getContentType()); 219 | $qrCode->render(); 220 | exit; 221 | 222 | 223 | // 验证 224 | $totp = new PHPGangsta_GoogleAuthenticator(); 225 | $secretKey = $totp->createSecret(32); 226 | $oneCode = $totp->getCode($secretKey); 227 | $checkResult = $totp->verifyCode($secretKey, $oneCode, 2); // 2 = 2*30sec clock tolerance 228 | if ($checkResult) { 229 | echo 'OK'; 230 | dd($secret, $oneCode); 231 | } 232 | else { 233 | echo 'FAILED'; 234 | } 235 | exit; 236 | } 237 | 238 | 239 | // @see https://docs.phalcon.io/4.0/zh-cn/translate 240 | // @see /ROOT/app/System/Language.php 241 | public function translatorAction() 242 | { 243 | // method one 244 | $this->lang->t('hi', ['name' => 'Joe Chu']); 245 | // method two 246 | $this->lang->_('hi', ['name' => 'Joe Chu']); 247 | 248 | // also can write like this 249 | // $this->view->text = $this->locale; // in the controller 250 | // {{text._('hi', ['name' => 'Joe Chu'])}} // in the view file 251 | // {{text->_('hi', ['name' => 'Joe Chu'])}} // in the view file 252 | } 253 | 254 | 255 | // PHP gettext 256 | // @see http://php.net/manual/en/book.gettext.php 257 | // 258 | // $lang = 'zh_CN'; 259 | // setlocale(LC_ALL, $lang); 260 | // $domain = $lang; 261 | // bind_textdomain_codeset($domain, 'UTF-8'); 262 | // bindtextdomain($domain, APP_DIR . 'locale'); 263 | // textdomain($domain); 264 | 265 | } 266 | -------------------------------------------------------------------------------- /docs/examples/DemoModel.php: -------------------------------------------------------------------------------- 1 | setConnectionService('db'); 30 | $this->setSource("users"); 31 | $this->dbConnectionData = DI::getDefault()->get('db'); 32 | } 33 | 34 | // 写操作 35 | public function demo() 36 | { 37 | // 写操作 SQL占位符 insert update delete 38 | $sql = "INSERT INTO `robots`(`name`, `year`) VALUES (?, ?)"; 39 | $sql = "UPDATE `robots` SET `name` = ? WHERE `id` = ?"; 40 | $sql = "DELETE FROM `robots` WHERE `name`=? AND `id` = ?"; 41 | $success = DI::getDefault()->get('db')->execute($sql, array('JoeChu', 1987)); 42 | 43 | 44 | // 可用以下操作替换上述方法 45 | 46 | 47 | // 插入 方法一 48 | $success = DI::getDefault()->get('db')->insert( 49 | "robots", 50 | array("JoeChu", 1987), 51 | array("name", "year") 52 | ); 53 | 54 | 55 | // 插入 方法二 56 | $success = DI::getDefault()->get('db')->insertAsDict( 57 | "robots", 58 | array( 59 | "name" => "JoeChu", 60 | "year" => 1987 61 | ) 62 | ); 63 | 64 | 65 | // 更新 方法一 66 | $success = DI::getDefault()->get('db')->update( 67 | "robots", 68 | array("name"), 69 | array("JoeChu"), 70 | array( 71 | 'conditions' => 'id = ?', 72 | 'bind' => array(101), 73 | 'bindTypes' => array(PDO::PARAM_INT) // Optional parameter 74 | ) 75 | ); 76 | 77 | 78 | // 更新 方法二 79 | $success = DI::getDefault()->get('db')->updateAsDict( 80 | "robots", 81 | array( 82 | "name" => "JoeChu" 83 | ), 84 | array( 85 | 'conditions' => 'id = ?', 86 | 'bind' => array(101), 87 | 'bindTypes' => array(PDO::PARAM_INT) // Optional parameter 88 | ) 89 | ); 90 | 91 | 92 | // 删除 93 | $success = DI::getDefault()->get('db')->delete("robots", "id = ?", array(101)); 94 | } 95 | 96 | // 读操作 97 | public function findDemo() 98 | { 99 | // link https://docs.phalconphp.com/zh/latest/reference/db.html#binding-parameters 100 | $sql = "SELECT * FROM users WHERE username=:username"; 101 | $bind = array('username' => 'demo@xxtime.com'); 102 | $query = DI::getDefault()->get('db')->query($sql, $bind); //$query->numRows(); 103 | $query->setFetchMode(PDO::FETCH_ASSOC); 104 | $data = $query->fetchAll(); // fetch 105 | dump($sql, $data); 106 | } 107 | 108 | // 事务 @see https://docs.phalcon.io/4.0/zh-cn/db-models-transactions 109 | public function transactionsDemo() 110 | { 111 | 112 | try { 113 | // 开始一个事务 114 | DI::getDefault()->get('db')->begin(); 115 | 116 | // 执行一些操作 117 | DI::getDefault()->get('db')->execute("DELETE `robots` WHERE `id` = 101"); 118 | DI::getDefault()->get('db')->execute("DELETE `robots` WHERE `id` = 102"); 119 | DI::getDefault()->get('db')->execute("DELETE `robots` WHERE `id` = 103"); 120 | 121 | // 提交操作,如果一切正常 122 | DI::getDefault()->get('db')->commit(); 123 | 124 | } catch (Exception $e) { 125 | // 如果发现异常,回滚操作 126 | DI::getDefault()->get('db')->rollback(); 127 | } 128 | 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /docs/examples/LogsComponent.php: -------------------------------------------------------------------------------- 1 | get('config')->mq; 33 | $exchange = 'router'; // direct类型默认交换机 34 | $connection = new AMQPStreamConnection($cfg->host, $cfg->port, $cfg->user, $cfg->pass, $cfg->vhost); 35 | $channel = $connection->channel(); 36 | 37 | 38 | /** 39 | * 声明一个队列 40 | * name: $queue 41 | * passive: false 42 | * durable: true // the queue will survive server restarts 43 | * exclusive: false // the queue can be accessed in other channels 44 | * auto_delete: false //the queue won't be deleted once the channel is closed. 45 | */ 46 | $channel->queue_declare($queue, false, true, false, false); 47 | 48 | 49 | /** 50 | * 声明一个交换器 51 | * name: $exchange 52 | * type: direct 53 | * passive: false 54 | * durable: true // the exchange will survive server restarts 55 | * auto_delete: false //the exchange won't be deleted once the channel is closed. 56 | */ 57 | $channel->exchange_declare($exchange, 'direct', false, true, false); 58 | 59 | 60 | /** 61 | * 绑定队列到交换器 62 | * @param string $queue 63 | * @param string $exchange 64 | * @param string $routing_key 65 | * @param bool $nowait 66 | * @param array $arguments 67 | * @param int $ticket 68 | * @return mixed|null 69 | */ 70 | $channel->queue_bind($queue, $exchange); 71 | 72 | 73 | // 准备发布消息 74 | if (!is_array($messageBody)) { 75 | $messageBody = [$messageBody]; 76 | } 77 | foreach ($messageBody as $msg) { 78 | // 定义消息 79 | $message = new AMQPMessage( 80 | $msg, 81 | array( 82 | 'content_type' => 'text/plain', 83 | 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT 84 | ) 85 | ); 86 | /** 87 | * 发布消息 88 | * @param AMQPMessage $msg 89 | * @param string $exchange 90 | * @param string $routing_key 91 | * @param bool $mandatory 92 | * @param bool $immediate 93 | * @param int $ticket 94 | */ 95 | $channel->basic_publish($message, $exchange); 96 | } 97 | 98 | $channel->close(); 99 | $connection->close(); 100 | return true; 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /docs/examples/routes.php: -------------------------------------------------------------------------------- 1 | addResource('/products', 'V1\Products'); 11 | * $resource->addResource('/news', 'V1\News', '{id:[0-9]{1,10}}')->only('get'); 12 | */ 13 | 14 | use Phalcon\Mvc\Router; 15 | use App\Providers; 16 | 17 | 18 | $router = new Router(false); 19 | $router->removeExtraSlashes(true); 20 | 21 | $router->notFound(['controller' => 'exception', 'action' => 'statusNotFound']); 22 | $router->add('/', ['controller' => 'default', 'action' => 'index']); 23 | 24 | $router->add('/:controller', ['controller' => 1]); 25 | $router->add('/:controller/:action/:params', ['controller' => 1, 'action' => 2, 'params' => 3]); 26 | 27 | $router->add('/(v[0-9]+)/:controller/:action/:params', ['module' => 1, 'controller' => 2, 'action' => 3, 'params' => 4]); 28 | $router->add('/(v[0-9]+)/:controller', ['module' => 1, 'controller' => 2]); 29 | 30 | $router->setDefaultModule('http'); 31 | $router->setDefaultNamespace('App\Http\Controller'); 32 | $router->setDefaultController('index'); 33 | $router->setDefaultAction('index'); 34 | 35 | return $router; 36 | -------------------------------------------------------------------------------- /docs/grpc.md: -------------------------------------------------------------------------------- 1 | ## docs 2 | * https://medium.com/@poyu677/grpc-%E4%BD%BF%E7%94%A8-php-%E5%AF%A6%E4%BD%9C-ab485e9f1044 3 | * https://github.com/grpc/grpc/tree/master/src/php 4 | * https://docs.servicestack.net/grpc-php 5 | * https://github.com/grpc/grpc/tree/master/src/php#build-and-install-the-grpc-c-core-library 6 | 7 | 8 | ## bash 9 | ```bash 10 | protoc --proto_path=src \ 11 | --go_opt=paths=source_relative \ 12 | --go_out=plugins=grpc:build/gen \ 13 | --php_out=build/gen \ 14 | --grpc_out=build/gen \ 15 | --plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin \ 16 | ./src/workspace.proto 17 | ``` 18 | 19 | 20 | ## composer 21 | ```json 22 | { 23 | "description": "示例配置", 24 | "require": { 25 | "grpc/grpc": "~1.30.0", 26 | "google/protobuf": "^v3.12.0" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "GPBMetadata\\": ["grpc/GPBMetadata/"], 31 | "Workspace\\": ["grpc/Workspace/"] 32 | } 33 | } 34 | } 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/gulp/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Getting Started 3 | - Run `npm start` to preview and watch for changes 4 | - Run `npm start -- --port=8080` to preview and watch for changes in port `8080` 5 | - Run `npm install --save ` to install dependencies, frontend included 6 | - Run `npm run serve:test` to run the tests in the browser 7 | - Run `npm run serve:test -- --port=8085` to run the tests in the browser in port `8085` 8 | - Run `npm run build` to build your webapp for production 9 | - Run `npm run serve:dist` to preview the production build 10 | - Run `npm run serve:dist -- --port=5000` to preview the production build in port `5000` 11 | 12 | ## Use Yeoman with generator-webapp 13 | - Install: `npm install --global yo gulp-cli generator-webapp` 14 | - Run `yo webapp` to scaffold your webapp 15 | 16 | ## Docs for webapp 17 | https://github.com/yeoman/generator-webapp -------------------------------------------------------------------------------- /docs/gulp/gulpfile.default.js: -------------------------------------------------------------------------------- 1 | const folder = { 2 | src: 'var/assets/', 3 | tmp: '.tmp/', 4 | dist: 'public/', 5 | dist_assets: 'public/assets/', 6 | } 7 | 8 | const {src, dest, watch, series, parallel} = require('gulp'); 9 | const del = require('del'); 10 | const browserSync = require('browser-sync').create(); 11 | const htmlmin = require('gulp-htmlmin'); // 压缩html 12 | const useref = require('gulp-useref'); 13 | const plumber = require('gulp-plumber'); 14 | const rename = require("gulp-rename"); // 重命名 15 | const gulpif = require('gulp-if'); // 判断 16 | const sass = require('gulp-sass'); // 解析sass 17 | const cssnano = require('cssnano'); // 压缩css 18 | const source = require('vinyl-source-stream'); 19 | const buffer = require('vinyl-buffer'); 20 | const concat = require('gulp-concat'); // 合并文件 21 | const uglify = require('gulp-uglify'); // 压缩js 22 | const sourceMap = require('gulp-sourcemaps'); 23 | const browserify = require('browserify'); 24 | 25 | // 以下两个一起使用,自动处理浏览器兼容问题 26 | const postcss = require('gulp-postcss'); 27 | const autoprefixer = require('autoprefixer'); 28 | 29 | // 暂未使用 30 | function html() { 31 | return src(folder.src + 'views/**/*.phtml') 32 | //.pipe(useref({searchPath: [folder.tmp, '.']})) 33 | //.pipe(gulpif(/\.js$/, uglify({compress: {drop_console: true}}))) 34 | //.pipe(gulpif(/\.css$/, postcss([cssnano({safe: true, autoprefixer: false})]))) 35 | .pipe(gulpif(/\.phtml$/, htmlmin({ 36 | collapseWhitespace: true, 37 | minifyCSS: true, 38 | minifyJS: {compress: {drop_console: true}}, 39 | processConditionalComments: true, 40 | removeComments: true, 41 | removeEmptyAttributes: true, 42 | removeScriptTypeAttributes: true, 43 | removeStyleLinkTypeAttributes: true 44 | }))) 45 | .pipe(dest(folder.dist + 'templates')); 46 | } 47 | 48 | // 编译css 49 | function css() { 50 | return src(folder.src + 'assets/css/**/*.{scss,sass}') 51 | .pipe(plumber()) 52 | .pipe(sass.sync({ 53 | outputStyle: 'expanded', 54 | precision: 10, 55 | includePaths: ['.'] 56 | }).on('error', sass.logError)) 57 | .pipe(postcss([ 58 | autoprefixer() 59 | ])) 60 | .pipe(concat("main.css")) 61 | //.pipe(postcss([cssnano({safe: true, autoprefixer: false})])) 62 | .pipe(dest(folder.dist + 'assets/css')) 63 | } 64 | 65 | // 编译js 66 | function js() { 67 | return src(folder.src + 'assets/js/**/*.js', {sourcemaps: true}) 68 | .pipe(plumber()) 69 | //.pipe($.babel()) 70 | //.pipe(concat('app.min.js')) 71 | //.pipe(gulpif(/\.js$/, uglify({compress: {drop_console: true}}))) 72 | .pipe(concat("main.js")) 73 | .pipe(dest(folder.dist + 'assets/js', {sourcemaps: true})) 74 | } 75 | 76 | // ES6 77 | function script() { 78 | var b = browserify({ 79 | transform: ['babelify'], 80 | entries: folder.src + "assets/js/main.js", 81 | debug: true 82 | }); 83 | 84 | return b.bundle() 85 | .pipe(source('main.js')) 86 | .pipe(buffer()) 87 | .pipe(sourceMap.init({loadMaps: true})) 88 | .pipe(plumber()) 89 | .pipe(dest(folder.dist_assets + 'js')) 90 | .pipe(rename({suffix: ".min"})) 91 | .pipe(uglify()) 92 | .pipe(sourceMap.write('.')) 93 | .pipe(dest(folder.dist_assets + 'js')); 94 | } 95 | 96 | // 压缩输出静态文件 97 | function assetsCompress() { 98 | src(folder.dist + 'assets/css/main.css') 99 | .pipe(plumber()) 100 | .pipe(gulpif(/\.css$/, postcss([cssnano({safe: true, autoprefixer: false})]))) 101 | //.pipe(rename({suffix: ".min"})) 102 | .pipe(dest(folder.dist + 'assets/css')) 103 | 104 | return src(folder.dist + 'assets/js/main.js') 105 | .pipe(plumber()) 106 | .pipe(gulpif(/\.js$/, uglify({compress: {drop_console: true}}))) 107 | //.pipe(rename({suffix: ".min"})) 108 | .pipe(dest(folder.dist + 'assets/js')) 109 | } 110 | 111 | // 清理 112 | function clean() { 113 | return del([folder.dist_assets, folder.tmp]) 114 | } 115 | 116 | function startAppServer() { 117 | browserSync.init({ 118 | notify: false, 119 | port: 3000, 120 | proxy: "phalcon:8080" 121 | /*server: { 122 | baseDir: [folder.tmp, folder.src], 123 | routes: { 124 | '/node_modules': 'node_modules' 125 | } 126 | }*/ 127 | }); 128 | 129 | watch([ 130 | folder.src + 'views/**/*.phtml', 131 | folder.src + 'assets/images/**/*', 132 | folder.src + 'assets/fonts/**/*' 133 | ]).on('change', browserSync.reload); 134 | watch(folder.src + 'assets/css/**/*.{scss,sass}', css).on('change', browserSync.reload); 135 | watch(folder.src + 'assets/js/**/*.js', js).on('change', browserSync.reload); 136 | } 137 | 138 | // 构建 139 | const build = series( 140 | clean, 141 | parallel( 142 | series(parallel(css, js), assetsCompress) 143 | //images, 144 | //fonts, 145 | //extras 146 | ) 147 | ); 148 | 149 | // 开发服务器 150 | const develop = series( 151 | clean, 152 | startAppServer 153 | ); 154 | 155 | exports.js = js; 156 | exports.script = script; 157 | exports.css = css; 158 | exports.html = html; 159 | exports.build = build; 160 | exports.default = develop; 161 | -------------------------------------------------------------------------------- /docs/gulp/gulpfile.webapp.js: -------------------------------------------------------------------------------- 1 | const folder = { 2 | tmp: "storage/.tmp/", 3 | src: "resources/", 4 | dist: "public/", 5 | dist_assets: "public/assets/" 6 | }; 7 | 8 | const { src, dest, watch, series, parallel, lastRun } = require('gulp'); 9 | const gulpLoadPlugins = require('gulp-load-plugins'); 10 | const fs = require('fs'); 11 | const mkdirp = require('mkdirp'); 12 | const Modernizr = require('modernizr'); 13 | const browserSync = require('browser-sync'); 14 | const del = require('del'); 15 | const autoprefixer = require('autoprefixer'); 16 | const cssnano = require('cssnano'); 17 | const { argv } = require('yargs'); 18 | 19 | const $ = gulpLoadPlugins(); 20 | const server = browserSync.create(); 21 | 22 | const port = argv.port || 3000; 23 | 24 | const isProd = process.env.NODE_ENV === 'production'; 25 | const isTest = process.env.NODE_ENV === 'test'; 26 | const isDev = !isProd && !isTest; 27 | 28 | function styles() { 29 | return src(folder.src + 'assets/styles/*.scss') 30 | .pipe($.plumber()) 31 | .pipe($.if(!isProd, $.sourcemaps.init())) 32 | .pipe($.sass.sync({ 33 | outputStyle: 'expanded', 34 | precision: 10, 35 | includePaths: ['.'] 36 | }).on('error', $.sass.logError)) 37 | .pipe($.postcss([ 38 | autoprefixer() 39 | ])) 40 | .pipe($.if(!isProd, $.sourcemaps.write())) 41 | .pipe(dest(folder.tmp + 'assets/styles')) 42 | .pipe(server.reload({stream: true})); 43 | }; 44 | 45 | function scripts() { 46 | return src(folder.src + 'assets/scripts/**/*.js') 47 | .pipe($.plumber()) 48 | .pipe($.if(!isProd, $.sourcemaps.init())) 49 | .pipe($.babel()) 50 | .pipe($.if(!isProd, $.sourcemaps.write('.'))) 51 | .pipe(dest(folder.tmp + 'assets/scripts')) 52 | .pipe(server.reload({stream: true})); 53 | }; 54 | 55 | async function modernizr() { 56 | const readConfig = () => new Promise((resolve, reject) => { 57 | fs.readFile(`${__dirname}/modernizr.json`, 'utf8', (err, data) => { 58 | if (err) reject(err); 59 | resolve(JSON.parse(data)); 60 | }) 61 | }) 62 | const createDir = () => new Promise((resolve, reject) => { 63 | mkdirp(`${__dirname}/${folder.tmp}assets/scripts`, err => { 64 | if (err) reject(err); 65 | resolve(); 66 | }) 67 | }); 68 | const generateScript = config => new Promise((resolve, reject) => { 69 | Modernizr.build(config, content => { 70 | fs.writeFile(`${__dirname}/${folder.tmp}assets/scripts/modernizr.js`, content, err => { 71 | if (err) reject(err); 72 | resolve(content); 73 | }); 74 | }) 75 | }); 76 | 77 | const [config] = await Promise.all([ 78 | readConfig(), 79 | createDir() 80 | ]); 81 | await generateScript(config); 82 | } 83 | 84 | const lintBase = files => { 85 | return src(files) 86 | .pipe($.eslint({ fix: true })) 87 | .pipe(server.reload({stream: true, once: true})) 88 | .pipe($.eslint.format()) 89 | .pipe($.if(!server.active, $.eslint.failAfterError())); 90 | } 91 | function lint() { 92 | return lintBase(folder.src + 'assets/scripts/**/*.js') 93 | .pipe(dest(folder.src + 'assets/scripts')); 94 | }; 95 | function lintTest() { 96 | return lintBase('test/spec/**/*.js') 97 | .pipe(dest('test/spec')); 98 | }; 99 | 100 | function html() { 101 | return src(folder.src + '**/*.phtml') 102 | .pipe($.useref({searchPath: [folder.tmp, folder.src, '.']})) 103 | .pipe($.if(/\.js$/, $.uglify({compress: {drop_console: true}}))) 104 | .pipe($.if(/\.css$/, $.postcss([cssnano({safe: true, autoprefixer: false})]))) 105 | .pipe($.if(/\.phtml$/, $.htmlmin({ 106 | collapseWhitespace: true, 107 | minifyCSS: true, 108 | minifyJS: {compress: {drop_console: true}}, 109 | processConditionalComments: true, 110 | removeComments: true, 111 | removeEmptyAttributes: true, 112 | removeScriptTypeAttributes: true, 113 | removeStyleLinkTypeAttributes: true 114 | }))) 115 | .pipe(dest(folder.dist)); 116 | } 117 | 118 | function images() { 119 | return src(folder.src + 'assets/images/**/*', { since: lastRun(images) }) 120 | .pipe($.imagemin()) 121 | .pipe(dest(folder.dist_assets + 'images')); 122 | }; 123 | 124 | function fonts() { 125 | return src(folder.src + 'assets/fonts/**/*.{eot,svg,ttf,woff,woff2}') 126 | .pipe($.if(!isProd, dest(folder.tmp + 'assets/fonts'), dest(folder.dist_assets + 'fonts'))); 127 | }; 128 | 129 | function extras() { 130 | return src([ 131 | folder.src + '*', 132 | '!' + folder.src + 'lang', 133 | '!' + folder.src + 'views', 134 | '!' + folder.src + '*.html' 135 | ], { 136 | dot: true 137 | }).pipe(dest(folder.dist)); 138 | }; 139 | 140 | function clean() { 141 | return del([folder.tmp, folder.dist_assets]) 142 | } 143 | 144 | function measureSize() { 145 | return src(folder.dist + '**/*') 146 | .pipe($.size({title: 'build', gzip: true})); 147 | } 148 | 149 | const build = series( 150 | clean, 151 | parallel( 152 | lint, 153 | series(parallel(styles, scripts, modernizr), html), 154 | images, 155 | fonts, 156 | extras 157 | ), 158 | measureSize 159 | ); 160 | 161 | function startAppServer() { 162 | server.init({ 163 | notify: false, 164 | port, 165 | server: { 166 | baseDir: [folder.tmp, folder.src], 167 | routes: { 168 | '/node_modules': 'node_modules' 169 | } 170 | } 171 | }); 172 | 173 | watch([ 174 | folder.src + '*.html', 175 | folder.src + 'assets/images/**/*', 176 | folder.tmp + 'assets/fonts/**/*' 177 | ]).on('change', server.reload); 178 | 179 | watch(folder.src + 'assets/styles/**/*.scss', styles); 180 | watch(folder.src + 'assets/scripts/**/*.js', scripts); 181 | watch('modernizr.json', modernizr); 182 | watch(folder.src + 'assets/fonts/**/*', fonts); 183 | } 184 | 185 | function startTestServer() { 186 | server.init({ 187 | notify: false, 188 | port, 189 | ui: false, 190 | server: { 191 | baseDir: 'test', 192 | routes: { 193 | '/scripts': folder.tmp + 'assets/scripts', 194 | '/node_modules': 'node_modules' 195 | } 196 | } 197 | }); 198 | 199 | watch(folder.src + 'assets/scripts/**/*.js', scripts); 200 | watch(['test/spec/**/*.js', 'test/index.html']).on('change', server.reload); 201 | watch('test/spec/**/*.js', lintTest); 202 | } 203 | 204 | function startDistServer() { 205 | server.init({ 206 | notify: false, 207 | port, 208 | server: { 209 | baseDir: folder.dist, 210 | routes: { 211 | '/node_modules': 'node_modules' 212 | } 213 | } 214 | }); 215 | } 216 | 217 | let serve; 218 | if (isDev) { 219 | serve = series(clean, parallel(styles, scripts, modernizr, fonts), startAppServer); 220 | } else if (isTest) { 221 | serve = series(clean, scripts, startTestServer); 222 | } else if (isProd) { 223 | serve = series(build, startDistServer); 224 | } 225 | 226 | exports.serve = serve; 227 | exports.build = build; 228 | exports.default = build; 229 | -------------------------------------------------------------------------------- /docs/gulp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | gulp scaffolding 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 |
27 |
28 | 39 |

gulp scaffolding

40 |
41 | 42 |
43 |

'Allo, 'Allo!

44 |

Always a pleasure scaffolding your apps. base on generator-webapp

45 |

Splendid!

46 |
47 | 48 |
49 |
50 |

HTML5 Boilerplate

51 |

HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or sites.

52 | 53 |

Sass

54 |

Sass is the most mature, stable, and powerful professional grade CSS extension language in the world.

55 | 56 |

Bootstrap

57 |

Sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development.

58 | 59 |

Modernizr

60 |

Modernizr is an open-source JavaScript library that helps you build the next generation of HTML5 and CSS3-powered websites.

61 |
62 |
63 | 64 | 67 |
68 | 69 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /docs/gulp/modernizr.json: -------------------------------------------------------------------------------- 1 | { 2 | "classPrefix": "modernizr-", 3 | "options": [ 4 | "addTest", 5 | "atRule", 6 | "domPrefixes", 7 | "hasEvent", 8 | "html5shiv", 9 | "html5printshiv", 10 | "load", 11 | "mq", 12 | "prefixed", 13 | "prefixes", 14 | "prefixedCSS", 15 | "setClasses", 16 | "testAllProps", 17 | "testProp", 18 | "testStyles" 19 | ], 20 | "feature-detects": [ 21 | "css/supports", 22 | "img/sizes", 23 | "img/srcset", 24 | "serviceworker", 25 | "touchevents" 26 | ] 27 | } -------------------------------------------------------------------------------- /docs/gulp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "engines": { 4 | "node": ">=4" 5 | }, 6 | "dependencies": { 7 | "bootstrap": "^4.1.3", 8 | "jquery": "^3.3.1", 9 | "modernizr": "^3.6.0" 10 | }, 11 | "devDependencies": { 12 | "@babel/core": "^7.1.2", 13 | "@babel/preset-env": "^7.1.0", 14 | "autoprefixer": "^9.4.4", 15 | "babelify": "^10.0.0", 16 | "browser-sync": "^2.2.1", 17 | "browserify": "^16.4.0", 18 | "chai": "^4.2.0", 19 | "cross-env": "^5.2.0", 20 | "cssnano": "^4.1.7", 21 | "del": "^3.0.0", 22 | "gulp": "^4.0.0", 23 | "gulp-babel": "^8.0.0", 24 | "gulp-cli": "^2.0.1", 25 | "gulp-concat": "^2.6.1", 26 | "gulp-eslint": "^5.0.0", 27 | "gulp-filter": "^5.1.0", 28 | "gulp-htmlmin": "^5.0.1", 29 | "gulp-if": "^2.0.2", 30 | "gulp-imagemin": "^5.0.3", 31 | "gulp-load-plugins": "^1.2.4", 32 | "gulp-plumber": "^1.0.1", 33 | "gulp-postcss": "^8.0.0", 34 | "gulp-rename": "^1.4.0", 35 | "gulp-sass": "^4.0.2", 36 | "gulp-size": "^3.0.0", 37 | "gulp-sourcemaps": "^2.6.5", 38 | "gulp-uglify": "^3.0.1", 39 | "gulp-useref": "^3.0.0", 40 | "mkdirp": "^0.5.1", 41 | "mocha": "^5.2.0", 42 | "vinyl-buffer": "^1.0.1", 43 | "vinyl-source-stream": "^2.0.0", 44 | "yargs": "12.0.5" 45 | }, 46 | "scripts": { 47 | "serve:test": "cross-env NODE_ENV=test gulp serve", 48 | "serve:dist": "cross-env NODE_ENV=production gulp serve", 49 | "start": "gulp serve", 50 | "build": "cross-env NODE_ENV=production gulp", 51 | "test": "npm run serve:test", 52 | "tasks": "gulp --tasks" 53 | }, 54 | "browserslist": [ 55 | "> 1%", 56 | "last 2 versions", 57 | "Firefox ESR" 58 | ], 59 | "eslintConfig": { 60 | "parserOptions": { 61 | "sourceType": "module" 62 | }, 63 | "env": { 64 | "es6": true, 65 | "node": true, 66 | "browser": true, 67 | "jquery": true 68 | }, 69 | "rules": { 70 | "quotes": [ 71 | 2, 72 | "single" 73 | ] 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /docs/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | user www; 2 | worker_processes 2; 3 | 4 | error_log /data/logs/nginx/error.log; 5 | 6 | #pid logs/nginx.pid; 7 | worker_rlimit_nofile 8192; 8 | 9 | 10 | events { 11 | worker_connections 4096; 12 | } 13 | 14 | 15 | http { 16 | include mime.types; 17 | default_type application/octet-stream; 18 | 19 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 20 | '$status $body_bytes_sent "$http_referer" ' 21 | '"$http_user_agent" "$http_x_forwarded_for"'; 22 | 23 | sendfile on; 24 | tcp_nopush on; 25 | keepalive_timeout 65; 26 | 27 | gzip on; 28 | gzip_min_length 1100; 29 | gzip_buffers 4 8k; 30 | gzip_types text/plain; 31 | 32 | #autoindex on; 33 | #autoindex_exact_size off; 34 | #autoindex_localtime on; 35 | include conf.d/*; 36 | index index.php index.html index.htm; 37 | } 38 | -------------------------------------------------------------------------------- /docs/nginx/nginx.http.conf: -------------------------------------------------------------------------------- 1 | #upstream php-handler { 2 | # server 127.0.0.1:9000; 3 | # server 127.0.0.1:9000; 4 | #} 5 | 6 | server { 7 | listen 80; 8 | listen [::]:80; 9 | server_name domain.com; 10 | 11 | root /var/www/my-project/public; 12 | index index.php index.html index.htm; 13 | 14 | charset utf-8; 15 | client_max_body_size 2m; 16 | 17 | # access_log /var/log/nginx/$server_name.access.log main; 18 | 19 | # add_header Cache-Control no-cache; 20 | add_header Powered-By zlab.dev; 21 | add_header X-Frame-Options DENY; 22 | add_header X-Content-Type-Options nosniff; 23 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; 24 | fastcgi_hide_header X-Powered-By; 25 | 26 | # include conf.d/ipFilter.conf; 27 | if ($http_user_agent ~ "DNSPod") {return 200; } 28 | if ($http_user_agent ~* (nmap|nikto|wikto|sf|sqlmap|bsqlbf|w3af|acunetix|havij|appscan)) { return 403; } 29 | 30 | # DNS 31 | resolver 8.8.8.8 8.8.4.4 valid=300s; 32 | resolver_timeout 5s; 33 | 34 | # phalcon 35 | location / { try_files $uri $uri/ /index.php?_url=$uri&$args; } 36 | 37 | # laravel 38 | # location / { try_files $uri $uri/ /index.php?$query_string; } 39 | 40 | # symfony 41 | # location / { try_files $uri /index.php$is_args$args; } 42 | 43 | # assets 44 | location = /favicon.ico { access_log off; log_not_found off; } 45 | location = /robots.txt { access_log off; log_not_found off; } 46 | location ^~ /data/ { allow all; } 47 | location ~* ^/.well-known/ { allow all; } 48 | location ~ /\. { access_log off; log_not_found off; return 403; } 49 | location ~ .*\.(js|css|map|ttf|woff)$ { access_log off; expires 7d; } 50 | location ~ .*\.(jpg|jpeg|gif|png|bmp|mp3|mp4)$ { 51 | access_log off; expires 30d; 52 | #valid_referers none blocked www.domain.com abc.domain.com; if ($invalid_referer){ return 403; } 53 | } 54 | 55 | #location ~ \.php$ { 56 | # proxy_pass http://php-handler; 57 | #} 58 | 59 | #fastcgi_pass php-handler; 60 | location ~ \.php$ { 61 | fastcgi_pass 127.0.0.1:9000; 62 | # fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; 63 | fastcgi_index index.php; 64 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 65 | include fastcgi_params; 66 | fastcgi_buffer_size 32k; 67 | fastcgi_buffers 8 32k; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /docs/nginx/nginx.https.conf: -------------------------------------------------------------------------------- 1 | #upstream php-handler { 2 | # server 127.0.0.1:9000; 3 | # server 127.0.0.1:9000; 4 | #} 5 | 6 | server { 7 | listen 80; 8 | server_name www.domain.com domain.com; 9 | root /var/www/my-project/public;; 10 | 11 | if ($request_uri !~* ^/.well-known/) { 12 | rewrite ^(.*)$ https://$host$1 permanent; 13 | } 14 | } 15 | 16 | server { 17 | listen 443 ssl default_server; 18 | listen [::]:443 ssl default_server ipv6only=on; 19 | server_name domain.com; 20 | 21 | root /var/www/my-project/public; 22 | index index.php index.html index.htm; 23 | 24 | charset utf-8; 25 | client_max_body_size 2m; 26 | 27 | # access_log /var/log/nginx/$server_name.access.log main; 28 | 29 | # add_header Cache-Control no-cache; 30 | add_header Powered-By zlab.dev; 31 | add_header X-Frame-Options DENY; 32 | add_header X-Content-Type-Options nosniff; 33 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; 34 | fastcgi_hide_header X-Powered-By; 35 | 36 | # include conf.d/ipFilter.conf; 37 | if ($http_user_agent ~ "DNSPod") {return 200; } 38 | if ($http_user_agent ~* (nmap|nikto|wikto|sf|sqlmap|bsqlbf|w3af|acunetix|havij|appscan)) { return 403; } 39 | 40 | # SSL https://cipherli.st nginx >= 1.5.9 41 | ssl on; 42 | ssl_certificate /etc/letsencrypt/live/xxtime.com/fullchain.pem; 43 | ssl_certificate_key /etc/letsencrypt/live/xxtime.com/privkey.pem; 44 | ssl_trusted_certificate /etc/letsencrypt/live/xxtime.com/chain.pem; 45 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 46 | ssl_prefer_server_ciphers on; 47 | ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; 48 | ssl_ecdh_curve secp384r1; 49 | ssl_session_cache shared:SSL:10m; 50 | ssl_session_tickets off; 51 | ssl_stapling on; 52 | ssl_stapling_verify on; 53 | 54 | # DNS 55 | resolver 8.8.8.8 8.8.4.4 valid=300s; 56 | resolver_timeout 5s; 57 | 58 | # phalcon 59 | location / { try_files $uri $uri/ /index.php?_url=$uri&$args; } 60 | 61 | # laravel 62 | # location / { try_files $uri $uri/ /index.php?$query_string; } 63 | 64 | # symfony 65 | # location / { try_files $uri /index.php$is_args$args; } 66 | 67 | # assets 68 | location = /favicon.ico { access_log off; log_not_found off; } 69 | location = /robots.txt { access_log off; log_not_found off; } 70 | location ^~ /data/ { allow all; } 71 | location ~* ^/.well-known/ { allow all; } 72 | location ~ /\. { access_log off; log_not_found off; return 403; } 73 | location ~ .*\.(js|css|map|ttf|woff)$ { access_log off; expires 7d; } 74 | location ~ .*\.(jpg|jpeg|gif|png|bmp|mp3|mp4)$ { 75 | access_log off; expires 30d; 76 | #valid_referers none blocked www.domain.com abc.domain.com; if ($invalid_referer){ return 403; } 77 | } 78 | 79 | #location ~ \.php$ { 80 | # proxy_pass http://php-handler; 81 | #} 82 | 83 | #fastcgi_pass php-handler; 84 | location ~ \.php$ { 85 | fastcgi_pass 127.0.0.1:9000; 86 | # fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; 87 | fastcgi_index index.php; 88 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 89 | include fastcgi_params; 90 | fastcgi_buffer_size 32k; 91 | fastcgi_buffers 8 32k; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | AddDefaultCharset UTF-8 2 | 3 | 4 | RewriteEngine On 5 | RewriteCond %{REQUEST_FILENAME} !-d 6 | RewriteCond %{REQUEST_FILENAME} !-f 7 | RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L] 8 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxtime/phalcon/277b9bb6e42ae231b6a2e91811846aef3df3777a/public/favicon.ico -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | boot(); 28 | -------------------------------------------------------------------------------- /templates/default/default.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ZLab 9 | 10 | 11 | 12 | 13 | 14 | 71 | 72 | 73 |
74 | 75 |
76 |
77 | ZLabphalcon {{pha_version}} 78 |
79 |

awesome framework running on php {{php_version}}

80 | 86 |
87 |
88 | 89 | 90 | -------------------------------------------------------------------------------- /templates/default/statusNotFound.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Not Found 9 | 10 | 11 | 12 | 13 | 14 | 60 | 61 | 62 |
63 | 64 |
65 |
66 | Not Found 67 |
68 | 69 | 75 |
76 |
77 | 78 | 79 | -------------------------------------------------------------------------------- /templates/html/defaultHandler.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | An Error Occurred 7 | 11 | 12 | 13 |
14 |

Oops! An Error Occurred

15 |

The server returned an error.

16 | 17 |

18 | Something is broken. Please let us know what you were doing when this error occurred. 19 | We will fix it as soon as possible. Sorry for any inconvenience caused. 20 |

21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /var/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /var/log/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /var/session/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | --------------------------------------------------------------------------------