hyperf-搭建初始化
官方文档
* https://hyperf.wiki/2.0/#/README
初步搭建
1. 安装项目
composer create-project hyperf/hyperf-skeleton
2. 项目根目录配置为当前目录的安装目录根目录,即不存在public目录
3. 配置Nginx反向代理
# 至少需要一个 Hyperf 节点,多个配置多行
upstream hyperf {
# Hyperf HTTP Server 的 IP 及 端口
server 127.0.0.1:9501;
server 127.0.0.1:9502;
} server {
# 监听端口
listen 80;
# 绑定的域名,填写您的域名
server_name proxy.hyperf.io; location / {
# 将客户端的 Host 和 IP 信息一并转发到对应节点
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 转发Cookie,设置 SameSite
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict"; # 执行代理访问真实服务器
proxy_pass http://hyperf;
}
}
4. 宝塔Nginx配置为(同LNMP的Nginx配置)
upstream hyperf {
# Hyperf HTTP Server 的 IP 及 端口
server 127.0.0.1:9501;
server 127.0.0.1:9502;
}
server
{
listen 80;
server_name hyperf.com.net;
index index.php index.html index.htm default.php default.htm default.html;
root /www/wwwroot/hyperf-skeleton;
#SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
#error_page 404/404.html;
#SSL-END
#ERROR-PAGE-START 错误页配置,可以注释、删除或修改
#error_page 404 /404.html;
#error_page 502 /502.html;
#ERROR-PAGE-END
#PHP-INFO-START PHP引用配置,可以注释或修改
include enable-php-74.conf;
#PHP-INFO-END
location / {
# 将客户端的 Host 和 IP 信息一并转发到对应节点
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 转发Cookie,设置 SameSite
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
# 执行代理访问真实服务器
proxy_pass http://hyperf;
}
#REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效
include /www/server/panel/vhost/rewrite/hyperf.kefu.com.net.conf;
#REWRITE-END
#禁止访问的文件或目录
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
{
return 404;
}
#一键申请SSL证书验证目录相关设置
location ~ \.well-known{
allow all;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
error_log off;
access_log /dev/null;
}
location ~ .*\.(js|css)?$
{
expires 12h;
error_log off;
access_log /dev/null;
}
access_log /www/wwwlogs/hyperf.kefu.com.net.log;
error_log /www/wwwlogs/hyperf.kefu.com.net.error.log;
}
5.启动http服务命令
php bin/hyperf.php start
或者重写启动文件watch。执行命令为:php watch
#!/usr/bin/env php
<?php /**
* Hyperf Watch Hot Reload Scripts
* From: https://github.com/ha-ni-cc/hyperf-watch
* Author: hanicc@qq.com
* Usage:
* Open the terminal console in the project root directory and enter:php watch
* 在项目根目录下打开终端控制台,输入:php watch
* If you want to clean the /runtime/container cache, enter: php watch -c
* 如果你想要清除/runtime/container缓存,则输入:php watch -c
*/ # PHP Bin File PHP程序所在路径(默认自动获取)
const PHP_BIN_FILE = 'which php';
# Watch Dir 监听目录(默认监听脚本所在的根目录)
const WATCH_DIR = __DIR__ . '/';
# Watch Ext 监听扩展名(多个可用英文逗号隔开)
const WATCH_EXT = 'php,env';
# Exclude Dir 排除目录(不监听的目录,数组形式)
const EXCLUDE_DIR = ['vendor', 'runtime', 'public'];
# Entry Point File 入口文件
const ENTRY_POINT_FILE = __DIR__ . '/bin/hyperf.php';
# Start Command 启动命令
const START_COMMAND = [ENTRY_POINT_FILE, 'start'];
# PID File Path PID文件路径
const PID_FILE_PATH = __DIR__ . '/runtime/hyperf.pid';
# Scan Interval 扫描间隔(毫秒,默认2000)
const SCAN_INTERVAL = 2000; if (!function_exists('exec')) {
echo '[x] 请在php.ini配置中取消禁用exec方法' . PHP_EOL;
exit(1);
} define('PHP', PHP_BIN_FILE == 'which php' ? exec('which php') : PHP_BIN_FILE); if (!file_exists(PHP) || !is_executable(PHP)) {
echo '[x] PHP bin (" ' . PHP . ' ") 路径没有找到或无法执行,请确认路径正确?' . PHP_EOL;
exit(1);
} if (!file_exists(ENTRY_POINT_FILE)) {
echo '[x] 入口文件 ("' . ENTRY_POINT_FILE . '") 没有找到,请确认文件存在?' . PHP_EOL;
exit(1);
} # 加载env
$content = @file_get_contents('.env');
$values = array_filter(preg_split("/(\r\n|\n|\r)/", $content));
foreach ($values as $val) {
if (substr($val, 0, 1) === '#') {
continue;
}
list($name, $value) = explode('=', $val);
$_ENV[$name] = $value;
} use Swoole\Process;
use Swoole\Timer;
use Swoole\Event; swoole_async_set(['enable_coroutine' => false, 'log_level' => SWOOLE_LOG_INFO]);
$hashes = [];
$serve = null;
echo " Start @ " . date('Y-m-d H:i:s') . PHP_EOL;
start();
state();
Timer::tick(SCAN_INTERVAL, 'watch'); function killOldProcess()
{
// pid存在则关闭存在的进程
if (file_exists(PID_FILE_PATH) && $pid = @file_get_contents(PID_FILE_PATH)) {
if (!@posix_kill($pid)) forceKill();
} else forceKill();
} function forceKill($match = '')
{
if (!$match) {
$match = @$_ENV['APP_NAME'] . '.Master';
}
// 适配MacOS
if (PHP_OS == 'Darwin') $match = ENTRY_POINT_FILE;
$command = "ps -ef | grep '$match' | grep -v grep | awk '{print $2}' | xargs kill -9 2>&1";
// 找不到pid,强杀进程
exec($command);
} function start()
{
// 杀旧进程
killOldProcess();
global $serve;
$serve = new Process('serve', true);
$serve->start();
if (false === $serve->pid) {
echo swoole_strerror(swoole_errno()) . PHP_EOL;
exit(1);
}
addEvent($serve);
} function addEvent($serve)
{
Event::add($serve->pipe, function () use (&$serve) {
$message = @$serve->read();
if (!empty($message)) {
echo $message;
}
});
} function watch()
{
global $hashes;
foreach ($hashes as $pathName => $currentHash) {
if (!file_exists($pathName)) {
unset($hashes[$pathName]);
continue;
}
$newHash = fileHash($pathName);
if ($newHash != $currentHash) {
change();
state();
break;
}
}
} function state()
{
global $hashes;
$files = phpFiles(WATCH_DIR);
$hashes = array_combine($files, array_map('fileHash', $files));
$count = count($hashes);
echo " Watching $count files..." . PHP_EOL;
} function change()
{
global $serve;
echo " Restart @ " . date('Y-m-d H:i:s') . PHP_EOL;
Process::kill($serve->pid);
start();
} function serve(Process $serve)
{
$opt = getopt('c');
# if (isset($opt['c'])) echo exec(PHP . ' ' . ENTRY_POINT_FILE . ' di:init-proxy') . '..' . PHP_EOL;
if (isset($opt['c'])) delDir('./runtime/container');
$serve->exec(PHP, START_COMMAND);
} function fileHash(string $pathname): string
{
$contents = @file_get_contents($pathname);
if (false === $contents) {
return 'deleted';
}
return md5($contents);
} function phpFiles(string $dirname): array
{
$directory = new RecursiveDirectoryIterator($dirname);
$filter = new Filter($directory);
$iterator = new RecursiveIteratorIterator($filter);
return array_map(function ($fileInfo) {
return $fileInfo->getPathname();
}, iterator_to_array($iterator));
} function delDir($path)
{
if (is_dir($path)) {
//扫描一个目录内的所有目录和文件并返回数组
$dirs = scandir($path);
foreach ($dirs as $dir) {
//排除目录中的当前目录(.)和上一级目录(..)
if ($dir != '.' && $dir != '..') {
//如果是目录则递归子目录,继续操作
$sonDir = $path . '/' . $dir;
if (is_dir($sonDir)) {
//递归删除
delDir($sonDir);
//目录内的子目录和文件删除后删除空目录
@rmdir($sonDir);
} else {
//如果是文件直接删除
@unlink($sonDir);
}
}
}
@rmdir($path);
}
} class Filter extends RecursiveFilterIterator
{
public function accept()
{
if ($this->current()->isDir()) {
if (preg_match('/^\./', $this->current()->getFilename())) {
return false;
}
return !in_array($this->current()->getFilename(), EXCLUDE_DIR);
}
$list = array_map(function (string $item): string {
return "\.$item";
}, explode(',', WATCH_EXT));
$list = implode('|', $list);
return preg_match("/($list)$/", $this->current()->getFilename());
}
}
6. 启动报错
ERROR Swoole short name have to disable before start server, please set swoole.use_shortname = off into your php.ini.
php.ini文件最后一行新增 swoole.use_shortname = off 即可
7. 访问当前配置域名返回
hyperf-搭建初始化的更多相关文章
- Activiti工作流搭建---初始化数据库
Activiti介绍 Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理.工作流.服务协作等领域的一个开源的.灵活的.易扩展的可执 ...
- vue3.0+vite+ts项目搭建--初始化项目(一)
vite 初始化项目 使用npm npm init vite@latest 使用yarn yarn create vite 使用pnpm pnpx create-vite 根据提示输入项目名称,选择v ...
- 图解Hyperf框架:Hyperf 的初始化
- vue二、脚手架搭建
1:安装nodeJs(下载一路回车) https://nodejs.org/zh-cn/ 2:检验nodeJs是否安装成功 (注意nodeJs是否添加到window路径中) 进入cmd -> n ...
- finger-guessing game:1场景搭建
场景搭建 //初始化legend组件 init(50, "div_caiquan", 800, 400, main); //定义游戏层 //游戏背景层,结果显示层,点击层 var ...
- TypeScript完全解读(26课时)_1.TypeScript完全解读-开发环境搭建
1.TypeScript完全解读-开发环境搭建 初始化项目 手动创建文件夹 D:\MyDemos\tsDemo\client-demo 用VSCode打开 npm init:初始化项目 然后我们的项目 ...
- 使用VuePress搭建个人博客
使用VuePress搭建个人博客 VuePress 是一个基于 Vue 的静态网站生成器.其中主要用到:Vue,VueRouter,Webpack. 类似的工具:hexo 基于 Markdown 语法 ...
- rollup 开发环境搭建
rollup 开发环境搭建 初始化项目使用lerna管理项目 使用npm init 初始化项目 npm init -y 安装lerna并初始化项目 npm install lerna --save-d ...
- 【迁移】—Entity Framework实例详解 转
一.Entity Framework 迁移命令(get-help EntityFramework) Enable-Migrations 启用迁移 Add-Migration 为挂起的Model变化添加 ...
- Node.js高级编程读书笔记 - 4 构建Web应用程序
Outline 5 构建Web应用程序 5.1 构建和使用HTTP中间件 5.2 用Express.js创建Web应用程序 5.3 使用Socket.IO创建通用的实时Web应用程序 5 构建Web应 ...
随机推荐
- 3. 安装部署MGR集群 | 深入浅出MGR
GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 目录 1. 安装准备 2. 初始化MySQL Server 3. 初始化MGR第一个节点 4. 继续设置另外两个节点 5. ...
- P1980 计数问题 - 记录
P1980 计数问题 题目描述 试计算在区间 1 到 n的所有整数中,数字x(0 ≤ x ≤ 9)共出现了多少次?例如,在 1到11中,即在 1,2,3,4,5,6,7,8,9,10,11中,数字1出 ...
- WebView2 通过 PuppeteerSharp 实现爬取 王者 壁纸 (案例版)
此案例是<.Net WebView2 项目,实现 嵌入 WEB 页面 Chromium内核>文的续集. 主要是针对WebView2的一些微软自己封装的不熟悉的API,有一些人已经对 Pup ...
- 飞书前端提到的竞态问题,在 Android 上怎么解决?
请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 GitHub · AndroidFamily 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] ...
- ASP.NET Core 6框架揭秘实例演示[32]:错误页面的集中呈现方式
由于ASP.NET是一个同时处理多个请求的Web应用框架,所以在处理某个请求过程中出现异常并不会导致整个应用的中止.出于安全方面的考量,为了避免敏感信息外泄,客户端在默认情况下并不会得到详细的出错信息 ...
- 我和Apache DolphinScheduler的缘分
关于 DolphinScheduler社区 Apache DolphinScheduler(incubator) 于17年在易观数科立项,19年3月开源, 19 年8月进入Apache 孵化器,社区发 ...
- MySQL事务概念与流程和索引控制
MySQL事务概念与流程和索引控制 视图 1.什么是视图 我们在执行SQL语句其实就是对表进行操作,所得到的其实也是一张表,而我们需要经常对这些表进行操作,拼接什么的都会产生一张虚拟表,我们可以基于该 ...
- 「题解报告」P4577 [FJOI2018]领导集团问题
题解 P4577 [FJOI2018]领导集团问题 题解区好像没有线段树上又套了二分的做法,于是就有了这片题解. 题目传送门 怀着必 WA 的决心交了两发,一不小心就过了. 题意 求一个树上最长不下降 ...
- Bypass Windows Defender Dump Lsass(手法拙劣)
0x00.前言 Windows Defender是一款内置在Windows操作系统的杀毒软件程序,本文旨在记录实战环境中,服务器存在Windows Defender情况下转储凭证的渗透手法,技术简单粗 ...
- .NET 7 SDK 开始 支持构建容器化应用程序
微软于 8 月 25 日在.NET官方博客上,.NET 7 SDK 将包括对创建容器化应用程序的支持,作为构建发布过程的一部分,从而绕过需要.显式 Docker 构建阶段. 这一决定背后的基本认知是简 ...