unzip 优化

This commit is contained in:
walkor 2022-09-17 16:08:45 +08:00
parent 58b408cfd5
commit efc44a2a54

View File

@ -6,6 +6,7 @@ use GuzzleHttp\Client;
use plugin\admin\api\Auth;
use plugin\admin\app\controller\Base;
use plugin\admin\app\Util;
use support\exception\BusinessException;
use support\Log;
use support\Request;
use function base_path;
@ -89,53 +90,38 @@ class AppController extends Base
'message' => '请登录'
]);
}
$client = $this->httpClient();
$response = $client->post('/api/app/download', [
'form_params' => [
'name' => $name,
'uid' => $user['uid'],
'token' => session('app-plugin-token'),
'referer' => $host,
'version' => $version,
]
]);
$content = $response->getBody()->getContents();
$data = json_decode($content, true);
if (!$data) {
$msg = "/api/app/download return $content";
echo "msg\r\n";
Log::error($msg);
}
if ($data['code']) {
// 获取下载zip文件url
$data = $this->getDownloadUrl($name, $user['uid'], $host, $version);
if ($data['code'] == -1) {
return $this->json(0, '请登录', [
'code' => 401,
'message' => '请登录'
]);
}
return $this->json($data['code'], $data['msg']);
}
$url = $data['result']['url'];
$client = $this->downloadClient();
$response = $client->get($url);
$body = $response->getBody();
$status = $response->getStatusCode();
if ($status == 404) {
return $this->json(1, '安装包不存在');
}
$zip_content = $body->getContents();
if (empty($zip_content)) {
return $this->json(1, '安装包不存在');
}
// 下载zip文件
$base_path = base_path() . "/plugin/$name";
$zip_file = "$base_path.zip";
file_put_contents($zip_file, $zip_content);
$extract_to = base_path() . '/plugin/';
$this->downloadZipFile($data['result']['url'], $zip_file);
$has_zip_archive = class_exists(\ZipArchive::class, false);
if (!$has_zip_archive) {
$cmd = $this->getUnzipCmd($zip_file, $extract_to);
if (!$cmd) {
throw new BusinessException('请给php安装zip模块或者给系统安装unzip命令');
}
if (!function_exists('proc_open')) {
throw new BusinessException('请解除proc_open函数的禁用或者给php安装zip模块');
}
}
// 解压zip到plugin目录
if ($has_zip_archive) {
$zip = new \ZipArchive;
$zip->open($zip_file, \ZIPARCHIVE::CHECKCONS);
}
$context = null;
$install_class = "\\plugin\\$name\\api\\Install";
@ -146,7 +132,13 @@ class AppController extends Base
}
}
if (!empty($zip)) {
$zip->extractTo(base_path() . '/plugin/');
unset($zip);
} else {
$this->unzipWithCmd($cmd);
}
unlink($zip_file);
if ($installed_version) {
@ -258,11 +250,137 @@ class AppController extends Base
return $this->json(0);
}
protected function getPluginVersion($name)
/**
* 获取zip下载url
*
* @param $name
* @param $uid
* @param $host
* @param $version
* @return mixed
* @throws BusinessException
* @throws \GuzzleHttp\Exception\GuzzleException
*/
protected function getDownloadUrl($name, $uid, $host, $version)
{
return config("plugin.$name.app.version");
$client = $this->httpClient();
$response = $client->post('/api/app/download', [
'form_params' => [
'name' => $name,
'uid' => $uid,
'token' => session('app-plugin-token'),
'referer' => $host,
'version' => $version,
]
]);
$content = $response->getBody()->getContents();
$data = json_decode($content, true);
if (!$data) {
$msg = "/api/app/download return $content";
Log::error($msg);
throw new BusinessException('访问官方接口失败');
}
if ($data['code'] && $data['code'] != -1) {
throw new BusinessException($data['msg']);
}
if ($data['code'] == 0 && !isset($data['result']['url'])) {
throw new BusinessException('官方接口返回数据错误');
}
return $data;
}
/**
* 下载zip
*
* @param $url
* @param $file
* @return void
* @throws BusinessException
* @throws \GuzzleHttp\Exception\GuzzleException
*/
protected function downloadZipFile($url, $file)
{
$client = $this->downloadClient();
$response = $client->get($url);
$body = $response->getBody();
$status = $response->getStatusCode();
if ($status == 404) {
throw new BusinessException('安装包不存在');
}
$zip_content = $body->getContents();
if (empty($zip_content)) {
throw new BusinessException('安装包不存在');
}
file_put_contents($file, $zip_content);
}
/**
* 获取系统支持的解压命令
*
* @param $zip_file
* @param $extract_to
* @return mixed|string|null
*/
protected function getUnzipCmd($zip_file, $extract_to)
{
if ($cmd = $this->findCmd('unzip')) {
$cmd = "$cmd -qq $zip_file -d $extract_to";
} else if ($cmd = $this->findCmd('7z')) {
$cmd = "$cmd x -bb0 -y $zip_file -o$extract_to";
} else if ($cmd= $this->findCmd('7zz')) {
$cmd = "$cmd x -bb0 -y $zip_file -o$extract_to";
}
return $cmd;
}
/**
* 使用解压命令解压
*
* @param $cmd
* @return void
* @throws BusinessException
*/
protected function unzipWithCmd($cmd)
{
$desc = [
0 => STDIN,
1 => STDOUT,
2 => ["pipe", "w"],
];
$handler = proc_open($cmd, $desc, $pipes);
if (!is_resource($handler)) {
throw new BusinessException("解压zip时出错:proc_open调用失败");
}
$err = fread($pipes[2], 1024);
fclose($pipes[2]);
proc_close($handler);
if ($err) {
throw new BusinessException("解压zip时出错:$err");
}
}
/**
* 获取本地插件版本
*
* @param $name
* @return array|mixed|null
*/
protected function getPluginVersion($name)
{
if (!is_file($file = base_path() . "/plugin/$name/config/app.php")) {
return null;
}
$config = include $file;
return $config['version'] ?? null;
}
/**
* 删除目录
*
* @param $src
* @return void
*/
protected function rmDir($src)
{
$dir = opendir($src);
@ -280,6 +398,11 @@ class AppController extends Base
rmdir($src);
}
/**
* 获取httpclient
*
* @return Client
*/
protected function httpClient()
{
// 下载zip
@ -301,6 +424,11 @@ class AppController extends Base
return new Client($options);
}
/**
* 获取下载httpclient
*
* @return Client
*/
protected function downloadClient()
{
// 下载zip
@ -320,4 +448,49 @@ class AppController extends Base
return new Client($options);
}
/**
* 查找系统命令
*
* @param string $name
* @param string|null $default
* @param array $extraDirs
* @return mixed|string|null
*/
function findCmd(string $name, string $default = null, array $extraDirs = [])
{
if (\ini_get('open_basedir')) {
$searchPath = array_merge(explode(\PATH_SEPARATOR, \ini_get('open_basedir')), $extraDirs);
$dirs = [];
foreach ($searchPath as $path) {
if (@is_dir($path)) {
$dirs[] = $path;
} else {
if (basename($path) == $name && @is_executable($path)) {
return $path;
}
}
}
} else {
$dirs = array_merge(
explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
$extraDirs
);
}
$suffixes = [''];
if ('\\' === \DIRECTORY_SEPARATOR) {
$pathExt = getenv('PATHEXT');
$suffixes = array_merge($pathExt ? explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
}
foreach ($suffixes as $suffix) {
foreach ($dirs as $dir) {
if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
return $file;
}
}
}
return $default;
}
}