pacKman/src/Core.php

266 lines
7.2 KiB
PHP
Raw Normal View History

2021-08-16 20:48:26 +00:00
<?php
2021-09-02 20:14:32 +00:00
/**
* @brief pacKman, a plugin for Dotclear 2
2021-11-01 10:39:02 +00:00
*
2021-09-02 20:14:32 +00:00
* @package Dotclear
* @subpackage Plugin
2021-11-01 10:39:02 +00:00
*
2021-09-02 20:14:32 +00:00
* @author Jean-Christian Denis
2021-11-01 10:39:02 +00:00
*
2021-09-02 20:14:32 +00:00
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
2022-12-17 21:12:10 +00:00
declare(strict_types=1);
2022-12-18 23:21:11 +00:00
namespace Dotclear\Plugin\pacKman;
2021-08-16 20:48:26 +00:00
use dcCore;
2022-12-17 21:12:10 +00:00
use dcModules;
use files;
2023-03-18 15:58:55 +00:00
use Dotclear\Helper\File\Zip\Unzip;
2022-12-17 21:12:10 +00:00
use path;
class Core
2021-08-16 20:48:26 +00:00
{
2021-11-08 21:19:07 +00:00
public static function quote_exclude(array $exclude): array
2021-08-23 13:07:29 +00:00
{
foreach ($exclude as $k => $v) {
2021-08-23 13:07:29 +00:00
$exclude[$k] = '#(^|/)(' . str_replace(
['.', '*'],
['\.', '.*?'],
trim($v)
) . ')(/|$)#';
}
return $exclude;
}
2022-11-12 20:42:05 +00:00
public static function getPackages(string $root): array
2021-08-23 13:07:29 +00:00
{
2021-10-23 14:46:03 +00:00
$res = [];
2021-08-23 13:07:29 +00:00
2023-03-19 22:12:34 +00:00
$cache = self::getCache() . DIRECTORY_SEPARATOR;
2021-08-23 13:07:29 +00:00
if (!is_dir($root) || !is_readable($root)) {
return $res;
}
2021-11-01 10:39:02 +00:00
$files = files::scanDir($root);
2021-10-23 14:46:03 +00:00
$zip_files = [];
2021-11-01 10:39:02 +00:00
foreach ($files as $file) {
2021-08-23 13:07:29 +00:00
if (!preg_match('#(^|/)(.*?)\.zip(/|$)#', $file)) {
continue;
}
$zip_files[] = $file;
}
if (empty($zip_files)) {
return $res;
}
$sandboxes = [
'theme' => clone dcCore::app()->themes,
'plugin' => clone dcCore::app()->plugins,
];
2021-08-23 13:07:29 +00:00
$i = 0;
2021-11-01 10:39:02 +00:00
foreach ($zip_files as $zip_file) {
$zip_file = $root . DIRECTORY_SEPARATOR . $zip_file;
2023-03-18 15:58:55 +00:00
$zip = new Unzip($zip_file);
$zip->getList(false, '#(^|/)(__MACOSX|\.svn|\.hg.*|\.git.*|\.DS_Store|\.directory|Thumbs\.db)(/|$)#');
2021-08-23 13:07:29 +00:00
$zip_root_dir = $zip->getRootDir();
if ($zip_root_dir != false) {
2023-03-18 16:20:48 +00:00
$target = dirname($zip_file);
$path = $target . DIRECTORY_SEPARATOR . $zip_root_dir;
$define = $zip_root_dir . '/' . dcModules::MODULE_FILE_DEFINE;
$init = $zip_root_dir . '/' . dcModules::MODULE_FILE_INIT;
2021-08-23 13:07:29 +00:00
} else {
2023-03-18 16:20:48 +00:00
$target = dirname($zip_file) . DIRECTORY_SEPARATOR . preg_replace('/\.([^.]+)$/', '', basename($zip_file));
$path = $target;
$define = dcModules::MODULE_FILE_DEFINE;
$init = dcModules::MODULE_FILE_INIT;
2021-08-23 13:07:29 +00:00
}
if ($zip->isEmpty()) {
$zip->close();
2021-08-23 13:07:29 +00:00
continue;
}
2023-03-18 15:58:55 +00:00
if (!$zip->hasFile($define)) {
$zip->close();
2021-08-23 13:07:29 +00:00
continue;
2021-08-23 13:07:29 +00:00
}
foreach ($sandboxes as $type => $sandbox) {
try {
2023-03-18 15:58:55 +00:00
files::makeDir($path, true);
// can't load twice _init.php file !
$unlink = false;
2023-03-18 15:58:55 +00:00
if ($zip->hasFile($init)) {
$unlink = true;
2023-03-18 15:58:55 +00:00
$zip->unzip($init, $path);
}
2023-03-18 15:58:55 +00:00
$zip->unzip($define, $path);
$sandbox->resetModulesList();
2023-03-18 15:58:55 +00:00
$sandbox->requireDefine($path, basename($path));
if ($unlink) {
2023-03-18 15:58:55 +00:00
unlink($target . DIRECTORY_SEPARATOR . $init);
}
2023-03-18 15:58:55 +00:00
unlink($target . DIRECTORY_SEPARATOR . $define);
2023-03-18 15:58:55 +00:00
if (!$sandbox->getErrors()) {
$module = $sandbox->getDefine(basename($path));
if ($module->isDefined() && $module->get('type') == $type) {
$res[$i] = $module->dump();
$res[$i]['root'] = $zip_file;
$i++;
}
}
} catch (Exception $e) {
}
2023-03-18 15:58:55 +00:00
files::deltree($path);
2022-02-01 20:39:38 +00:00
}
2023-03-18 15:58:55 +00:00
$zip->close();
2021-08-23 13:07:29 +00:00
}
return $res;
}
2021-11-08 21:19:07 +00:00
public static function pack(array $info, string $root, array $files, bool $overwrite = false, array $exclude = [], bool $nocomment = false, bool $fixnewline = false): bool
2021-08-23 13:07:29 +00:00
{
if (!($info = self::getInfo($info))
2021-10-23 14:46:03 +00:00
|| !($root = self::getRoot($root))
) {
2021-08-23 13:07:29 +00:00
return false;
}
$exclude = self::getExclude($exclude);
2021-11-01 10:39:02 +00:00
foreach ($files as $file) {
2021-08-23 13:07:29 +00:00
if (!($file = self::getFile($file, $info))
2021-10-23 14:46:03 +00:00
|| !($dest = self::getOverwrite($overwrite, $root, $file))
) {
2021-08-23 13:07:29 +00:00
continue;
}
@set_time_limit(300);
if ($nocomment) {
2023-03-18 15:58:55 +00:00
Zip::$remove_comment = true;
}
if ($fixnewline) {
2023-03-18 15:58:55 +00:00
Zip::$fix_newline = true;
}
2023-03-18 15:58:55 +00:00
$zip = new Zip($dest);
2021-08-23 13:07:29 +00:00
2021-11-01 10:39:02 +00:00
foreach ($exclude as $e) {
2021-08-23 13:07:29 +00:00
$zip->addExclusion($e);
}
$zip->addDirectory(
path::real($info['root']),
$info['id'],
true
);
$zip->close();
unset($zip);
}
return true;
}
2021-11-08 21:19:07 +00:00
private static function getRoot(string $root): string
2021-08-23 13:07:29 +00:00
{
2021-11-08 21:19:07 +00:00
$root = (string) path::real($root);
2021-08-23 13:07:29 +00:00
if (!is_dir($root) || !is_writable($root)) {
2022-11-26 21:20:11 +00:00
throw new Exception(__('Directory is not writable'));
2021-08-23 13:07:29 +00:00
}
return $root;
}
2021-11-08 21:19:07 +00:00
private static function getInfo(array $info): array
2021-08-23 13:07:29 +00:00
{
2021-11-01 10:39:02 +00:00
if (!isset($info['root'])
|| !isset($info['id'])
2021-10-23 14:46:03 +00:00
|| !is_dir($info['root'])
) {
2022-11-26 21:20:11 +00:00
throw new Exception(__('Failed to get module info'));
2021-08-23 13:07:29 +00:00
}
return $info;
}
2021-11-08 21:19:07 +00:00
private static function getExclude(array $exclude): array
2021-08-23 13:07:29 +00:00
{
2023-03-11 17:46:23 +00:00
$exclude = array_merge(My::EXCLUDED_FILES, $exclude);
2021-08-23 13:07:29 +00:00
return self::quote_exclude($exclude);
}
2021-11-08 21:19:07 +00:00
private static function getFile(string $file, array $info): ?string
2021-08-23 13:07:29 +00:00
{
if (empty($file) || empty($info)) {
return null;
}
$file = str_replace(
[
2023-03-19 09:47:24 +00:00
'\\',
2021-08-23 13:07:29 +00:00
'%type%',
'%id%',
'%version%',
'%author%',
2022-11-26 21:22:42 +00:00
'%time%',
2021-08-23 13:07:29 +00:00
],
[
2023-03-19 09:47:24 +00:00
'/',
2021-08-23 13:07:29 +00:00
$info['type'],
$info['id'],
$info['version'],
$info['author'],
2022-11-26 21:22:42 +00:00
time(),
2021-08-23 13:07:29 +00:00
],
$file
);
$parts = explode('/', $file);
2021-11-01 10:39:02 +00:00
foreach ($parts as $i => $part) {
2021-08-23 13:07:29 +00:00
$parts[$i] = files::tidyFileName($part);
}
2021-11-01 10:39:02 +00:00
2023-03-19 09:47:24 +00:00
return implode(DIRECTORY_SEPARATOR, $parts) . '.zip';
2021-08-23 13:07:29 +00:00
}
2021-11-08 21:19:07 +00:00
private static function getOverwrite(bool $overwrite, string $root, string$file): ?string
2021-08-23 13:07:29 +00:00
{
2023-03-19 09:47:24 +00:00
$path = $root . DIRECTORY_SEPARATOR . $file;
2021-08-23 13:07:29 +00:00
if (file_exists($path) && !$overwrite) {
// don't break loop
//throw new Exception('File already exists');
return null;
}
return $path;
}
2021-11-08 21:19:07 +00:00
private static function getCache(): string
2021-08-23 13:07:29 +00:00
{
2023-03-19 09:47:24 +00:00
$c = DC_TPL_CACHE . DIRECTORY_SEPARATOR . 'packman';
2021-08-23 13:07:29 +00:00
if (!file_exists($c)) {
@files::makeDir($c);
2021-08-23 13:07:29 +00:00
}
if (!is_writable($c)) {
2022-11-26 21:20:11 +00:00
throw new Exception(__('Failed to get temporary directory'));
2021-08-23 13:07:29 +00:00
}
return $c;
}
2021-11-06 13:56:29 +00:00
}