// 将 ip 转换成 city
function ip2City($ip)
{
$url = "https://apis.map.qq.com/ws/location/v1/ip?ip={$ip}&key=XXXXXXXX";
$res = curl($url, false, false, true);
$data = [];
try {
if ($res) {
$res = json_decode($res, true);
}
if ($res && $res['status'] == 0 && $res['result']) {
$data['latitude'] = $res['result']['location']['lat'];
$data['longitude'] = $res['result']['location']['lng'];
$data['city'] = $res['result']['ad_info']['city'] ? $res['result']['ad_info']['city'] : '未知';
$data['citycode'] = $res['result']['ad_info']['adcode'] && $res['result']['ad_info']['adcode'] > 0 ? $res['result']['ad_info']['adcode'] : 0;
}
} catch (Exception $e) {
}
return $data;
}
/**
* @param string $url 请求网址
* @param bool $params 请求参数
* @param bool $post 请求方式,是否是post
* @param bool $https 请求http协议,是否是https
* @return bool|mixed
*/
function curl($url, $params = false, $post = false, $https = false)
{
$httpInfo = array();
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36');
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if ($post === true) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_URL, $url);
} else {
if ($params === false) {
curl_setopt($ch, CURLOPT_URL, $url);
} else {
if (is_array($params)) {
$params = http_build_query($params);
}
curl_setopt($ch, CURLOPT_URL, $url . '?' . $params);
}
}
if ($https === true) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在
}
$response = curl_exec($ch);
if ($response === false) {
Illuminate\Support\Facades\Log::error(sprintf('curl 错误。 url:%s, error:%s', $url, curl_error($ch)));
return false;
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$httpInfo = array_merge($httpInfo, curl_getinfo($ch));
curl_close($ch);
return $response;
}
Root composer.json requires php ^7.3 but your php version (8.1.0) does not satisfy that requirement.
处理 Root composer.json requires php ^7.3 but your php version (8.1.0) does not satisfy that requirement.
# 使用
composer install --ignore-platform-reqs
操作起来
# 执行下边命令,生产各个 view
php artisan vendor:publish --tag=laravel-errors
可参考
相关问题
这里是客服相关的配置
api 配置入口:https://work.weixin.qq.com/api/doc/10514
微信客服底部 api: https://work.weixin.qq.com/wework_admin/frame#/app/servicer
上传临时文件调用接口:
https://open.work.weixin.qq.com/wwopen/devtool/interface?doc_id=10112
各个语言实例: https://work.weixin.qq.com/api/doc/90000/90138/90307
这里是用户相关的配置
https://work.weixin.qq.com/wework_admin/frame#/customer/analysis
mysql 计算距离并按距离远近升序排序
$latitude = 22.531162063479226;
$longitude = 113.954436585508;
$query = Model::query()->select(['latitude', 'longitude', 'address',]);
$query->where('latitude', '>', 0);
$query->addSelect(DB::raw("acos(cos(" . $latitude . "*pi()/180)*cos(latitude*pi()/180)*cos(" . $longitude . "*pi()/180-longitude*pi()/180)+sin(" . $latitude . "*pi()/180)*sin(latitude * pi()/180)) * 6367000 AS distance"));
$res = $query->orderBy('distance', 'asc')->get();
参考:
SELECT
id,
latitude,
longitude,
ROUND(
6378.138 * 2 * ASIN(
SQRT(
POW(
SIN(
(
23.163292 * PI() / 180 - latitude * PI() / 180
) / 2
),
2
) + COS(23.163292 * PI() / 180) * COS(latitude * PI() / 180) * POW(
SIN(
(
113.3114676 * PI() / 180 - longitude * PI() / 180
) / 2
),
2
)
)
) * 1000
) AS distance
FROM
cw_party
ORDER BY
distance asc
Laravel Octane 通过使用功能强大的应用程序服务器(包括 Swoole 和 RoadRunner )为应用程序提供服务,从而增强了应用程序的性能。Octane引导您的应用程序一次,将其保存在内存中,然后以超音速提供请求。
安装条件
- PHP8+
- laravel v.8.37+
安装
可以通过Composer软件包管理器安装Octane:
composer require laravel/octane
安装Octane之后,您可以执行 octane:install Artisan 命令,该命令会将Octane的配置文件安装到您的应用程序中:
php artisan octane:install
RoadRunner
RoadRunner 由使用 Go 构建的 RoadRunner 二进制文件提供动力。首次启动基于 RoadRunner 的 Octane 服务器时,Octane 将为您下载并安装 RoadRunner 二进制文件。
RoadRunner Via Laravel Sail
RoadRunner 具体使用可以查看原文。
启动你的服务
可以通过 octane:startArtisan 命令启动 Octane 服务器。默认情况下,此命令将利用 server 应用程序 octane 配置文件的配置选项指定的服务器:
php artisan octane:start
# 设置应用HTTPS.配置
OCTANE_HTTPS=false
# 设置启动服务的容器
OCTANE_SERVER=swoole
# 应用代码热加载
php artisan octane:start --watch
注意 使用该命令之前,应该确保本地安装了Node 服务.您应该在您的project:library中安装Chokidar 文件监视库:
npm install --save-dev chokidar
您可以使用 watch 应用程序的 config/octane.php 配置文件中的配置选项来配置应监视的目录和文件。
指定worker进程数
默认情况下,Octane 将为您的计算机提供的每个 CPU 内核启动一个应用程序请求工作程序。然后,这些工作程序将在进入您的应用程序时用于处理传入的HTTP请求。您可以--workers在调用 octane:star t命令时手动指定要使用该选项的工人数量:
php artisan octane:start --workers=4
如果使用的是 Swoole 应用程序服务器,则还可以指定要启动的“任务工作者”数量:
php artisan octane:start --workers=4 --task-workers=6
指定最大的请求数
php artisan octane:start --max-requests=250
服务重启
您可以使用以下 octane:reload 命令正常重启 Octane 服务器的应用程序工作程序。通常,应在部署后执行此操作,以便将新部署的代码加载到内存中并用于处理后续请求:
php artisan octane:reload
服务停止
您可以使用 octane:stopArtisan 命令停止 Octane 服务器:
php artisan octane:stop
查看服务状态
php artisan octane:status
Octane 依赖注入
由于 Octane 会一次引导您的应用程序并在处理请求时将其保存在内存中,因此在构建应用程序时应注意一些注意事项。例如,您的应用程序服务提供商的registerand boot 方法仅在请求启动程序最初启动时执行一次。在后续请求中,相同的应用程序实例将被重用。
有鉴于此,在将应用程序服务容器或请求注入到任何对象的构造函数中时,应格外小心。这样,该对象可能具有旧版本的容器或后续请求中的请求。
Octane 将自动处理重置请求之间的任何第一方框架状态。但是,Octane 并不总是知道如何重置应用程序创建的全局状态。因此,您应该了解如何以Octane 友好的方式构建应用程序。下面,我们将讨论使用辛烷值时可能引起问题的最常见情况。
容器注入
通常,应避免将应用程序服务容器或 HTTP 请求实例注入其他对象的构造函数中。例如,以下绑定将整个应用程序服务容器注入到作为单例绑定的对象中:
use App\Service;
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->singleton(Service::class, function ($app) {
return new Service($app);
});
}
在此示例中,如果 Service 在应用程序启动过程中解析了该实例,则该容器将被注入到服务中,并且该 Service 实例将在后续请求中保留该容器。对于您的特定应用程序,这可能不是问题;但是,这可能导致容器意外丢失在引导周期后期或后续请求中添加的绑定。
解决方法是,您可以停止将绑定注册为单例,也可以将容器解析器闭包注入始终解析当前容器实例的服务中:
use App\Service;
use Illuminate\Container\Container;
$this->app->bind(Service::class, function ($app) {
return new Service($app);
});
$this->app->singleton(Service::class, function () {
return new Service(fn () => Container::getInstance());
});
全局 app 帮助器和 Container::getInstance() 方法将始终返回应用程序容器的最新版本。
请求注入
通常,应避免将应用程序服务容器或HTTP请求实例注入其他对象的构造函数中。例如,以下绑定将整个请求实例注入到作为单例绑定的对象中:
use App\Service;
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->singleton(Service::class, function ($app) {
return new Service($app['request']);
});
}
在此示例中,如果Service在应用程序启动过程中解析了实例,则HTTP请求将被注入到服务中,并且该Service实例将在后续请求中保留相同的请求。因此,所有标头,输入和查询字符串数据以及所有其他请求数据都将不正确。
解决方法是,您可以停止将绑定注册为单例,或者可以将请求解析程序闭包注入始终解析当前请求实例的服务中。或者,最推荐的方法只是在运行时将对象需要的特定请求信息传递给对象的方法之一:
use App\Service;
$this->app->bind(Service::class, function ($app) {
return new Service($app['request']);
});
$this->app->singleton(Service::class, function ($app) {
return new Service(fn () => $app['request']);
});
// Or...
$service->method($request->input('name'));
全局 request 帮助程序将始终返回应用程序当前正在处理的请求,因此可以在您的应用程序中安全使用。
配置文件注入
通常,应避免将配置实例注入其他对象的构造函数中。例如,以下绑定将配置注入到作为单例绑定的对象中:
use App\Service;
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->singleton(Service::class, function ($app) {
return new Service($app->make('config'));
});
}
在此示例中,如果配置值在两次请求之间更改,则该服务将无法访问新值,因为它取决于原始存储库实例。
解决方法是,您可以停止将绑定注册为单例,或者可以将配置存储库解析器闭包注入到该类中:
use App\Service;
use Illuminate\Container\Container;
$this->app->bind(Service::class, function ($app) {
return new Service($app->make('config'));
});
$this->app->singleton(Service::class, function () {
return new Service(fn () => Container::getInstance()->make('config'));
});
全局 config 将始终返回配置的最新版本,因此可以在您的应用程序中安全使用。
管理内存泄漏
请记住,Octane 在两次请求之间将您的应用程序保留在内存中;因此,将数据添加到静态维护的阵列将导致内存泄漏。例如,由于对应用程>序的每个请求将继续向静态$data数组添加数据,因此以下控制器发生内存泄漏:
use App\Service;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @return void
*/
public function index(Request $request)
{
Service::$data[] = Str::random(10);
// ...
}
并发任务
提示该功能需要使用 Swoole
使用 Swoole 时,您可以通过轻量级后台任务同时执行操作。您可以使用 Octane:: tick concurrently 方法完成此操作。您可以将此方法与PHP数组解>构相结合,以检索每个操作的结果:
use App\User;
use App\Server;
use Laravel\Octane\Facades\Octane;
[$users, $servers] = Octane::concurrently([
fn () => User::all(),
fn () => Server::all(),
]);
由 Octane 处理的并发任务利用 Swoole 的 “task workers”,并在与传入请求完全不同的过程中执行。可用于处理并发任务的工作者数量由 --task-workers命令上的 octane:start 指令确定:
php artisan octane:start --workers=4 --task-workers=6
定时器 & 时间间隔
- 提示该功能需要使用Swoole
使用 Swoole 时,您可以注册将在每指定的秒数内执行的 “tick” 操作。您可以通过 tick 方法注册 “ tick” 回调。提供给该tick方法的第一个参数应该是代表股票行情指示器名称的字符串。第二个参数应该是可调用的,它将在指定的时间间隔被调用。
在此示例中,我们将注册一个闭包,每10秒调用一次。通常,tick应在boot应用程序的服务提供者之一的方法内调用该方法:
Octane::tick('simple-ticker', fn () => ray('Ticking...'))
->seconds(10);
使用该 immediate 方法,您可以指示 Octane 在 Octane 服务器最初启动时立即调用 tick 回调,此后每隔 N 秒:
Octane::tick('simple-ticker', fn () => ray('Ticking...'))
->seconds(10)
->immediate();
Octane 缓存
- 这功能依赖于Swoole
使用 Swoole 时,您可以利用 Octane 缓存驱动程序,该驱动程序提供每秒高达 200 万次操作的读写速度。因此,对于需要从其缓存层实现极高读/写速度的应用程序而言,此缓存驱动程序是一个绝佳选择。
该缓存驱动程序由 Swoole 表提供动力。缓存中存储的所有数据对服务器上的所有工作人员均可用。但是,重新启动服务器后,将刷新缓存的数据:
Cache::store('octane')->put('framework', 'Laravel', 30);
缓存间隔
除了 Laravel 缓存系统提供的典型方法外,Octane 缓存驱动程序还具有基于间隔的缓存。这些缓存将按指定的时间间隔自动刷新,并应使用 boot 您的应用程序的服务提供商之一的方法进行注册。例如,以下缓存将每五秒钟刷新一次:
use Illuminate\Support\Str;
Cache::store('octane')->interval('random', function () {
return Str::random(10);
}, seconds: 5);
进程间共享内存 (table)
使用 Swoole 时,您可以定义自己的任意 Swoole 表并与之交互。Swoole 表提供了极高的性能吞吐量,并且服务器上的所有工作人员都可以访问这些表中的数据。但是,重新启动服务器后,其中的数据将丢失。
表应在tables应用程序的octane配置文件的配置数组中定义。已经为您配置了一个示例表,该表最多允许1000行。可以通过在列类型之后指定列大小来配置字符串列的最大大小,如下所示:
'tables' => [
'example:1000' => [
'name' => 'string:1000',
'votes' => 'int',
],
],
要访问表,可以使用以下 Octane::table 方法:
use Laravel\Octane\Facades\Octane;
Octane::table('example')->set('uuid', [
'name' => 'Nuno Maduro',
'votes' => 1000,
]);
return Octane::table('example')->get('uuid');
通过Swoole table 支持的列类型:string,int,和 float。
参考
运营商如果不是一成不变。那么就要面对更换所要面临的问题。先换 oss 到 cos
换吧
迁移工具: https://cloud.tencent.com/document/product/436/15392
liunx 下,下载好工具,配置好 config。安装必须的环境(JAVA),执行 sh start_migrate.sh 开始迁移。等到结束就 ok。
换到 cos,laravel 的工具包也跟着换了 https://github.com/overtrue/laravel-filesystem-cos
从零开始,来吧
php 下载地址集:https://www.php.net/downloads
先下载解压 php 包
# 先把文件下到这个目录下来
cd /usr/local/src/php
wget https://www.php.net/distributions/php-7.4.25.tar.gz
# 提示说 错误: “www.php.net” 的证书不可信 错误: “www.php.net” 的证书使用不安全的算法签名。
# wget 搞不定,我们用 curl 来弄
curl -o php-7.4.25.tar.gz https://www.php.net/distributions/php-7.4.25.tar.gz
# 再解压
tar -xzvf php-7.4.25.tar.gz
安装依赖包
能用 yum 装的就用 yum 装,不行的再源码编译安装
yum -y install gcc gcc-c++
yum -y install sqlite-devel
yum install libxslt-devel
yum install cmake
# 还是要手动安装 oniguruma
请参考:[https://blog.vini123.com/379](https://blog.vini123.com/379)
yum -y install libxml2-devel openssl-devel curl-devel libjpeg-devel libpng-devel libicu-devel freetype-devel openldap-devel openldap openldap-devel
安装 gd库,freetype2,libzip ,请参考:https://blog.vini123.com/378
安装
如果之前没建立其用户组,先建立一个用户组
groupadd nginx
useradd -g nginx -M nginx
参考
oss 上传 api 中,一个是上传 file ,有个是上传 content 。如何处理各种文件以及数据格式呢。常见的一种操作是上传图片。这里就弄弄看。
操作一波
如果上传的图片是 base64 ,先要转换。我们这里定义一个函数。
function base64ToImage($file)
{
if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $file, $result)) {
$image = base64_decode(str_replace($result[1], '', $file));
return $image;
}
return null;
}
我们还知道怎么拼接完成的 url。
# 这样就可以获取公网 url,当然你也可以获取内网 url
$url = App\Services\Oss::getPublicObjectURL($ossKey);
在这里,我们是先将文件传到服务器,再从服务器将文件传到 oss 上。这时,就用内网上传即可。流量要钱的,这样蛮好的。为什么不直接传 oss 上呢。直接传服务端逻辑不方便操作,直接传权限控制不好处理。反正就这种操作吧。
上边的还没说完,转换后,需要内网上传。
$file = base64ToImage($request->file);
$ossKey = ''upload/images/meets/1.jpg;
if($file) {
$uploaded = Oss::privateUploadContent($ossKey, $file);
}
想要删也可以的
Oss::privateDeleteObject($ossKey);
