222 lines
6.2 KiB
PHP
222 lines
6.2 KiB
PHP
<?php
|
|
/**
|
|
* @brief pacKman, a plugin for Dotclear 2
|
|
*
|
|
* @package Dotclear
|
|
* @subpackage Plugin
|
|
*
|
|
* @author Jean-Christian Denis
|
|
*
|
|
* @copyright Jean-Christian Denis
|
|
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
|
*/
|
|
declare(strict_types=1);
|
|
|
|
namespace Dotclear\Plugin\pacKman;
|
|
|
|
use dcCore;
|
|
use dcModuleDefine;
|
|
use dcModules;
|
|
use Dotclear\Helper\File\Files;
|
|
use Dotclear\Helper\File\Path;
|
|
use Dotclear\Helper\File\Zip\Unzip;
|
|
|
|
class Core
|
|
{
|
|
public static function quote_exclude(array $exclude): array
|
|
{
|
|
foreach ($exclude as $k => $v) {
|
|
$exclude[$k] = '#(^|/)(' . str_replace(
|
|
['.', '*'],
|
|
['\.', '.*?'],
|
|
trim($v)
|
|
) . ')(/|$)#';
|
|
}
|
|
|
|
return $exclude;
|
|
}
|
|
|
|
public static function getPackages(string $root): array
|
|
{
|
|
$res = [];
|
|
|
|
if (!is_dir($root) || !is_readable($root)) {
|
|
return $res;
|
|
}
|
|
|
|
$files = Files::scanDir($root);
|
|
$zip_files = [];
|
|
foreach ($files as $file) {
|
|
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,
|
|
];
|
|
|
|
$i = 0;
|
|
foreach ($zip_files as $zip_file) {
|
|
$zip_file = $root . DIRECTORY_SEPARATOR . $zip_file;
|
|
$zip = new Unzip($zip_file);
|
|
$zip->getList(false, '#(^|/)(__MACOSX|\.svn|\.hg.*|\.git.*|\.DS_Store|\.directory|Thumbs\.db)(/|$)#');
|
|
|
|
$zip_root_dir = $zip->getRootDir();
|
|
if ($zip_root_dir != false) {
|
|
$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;
|
|
} else {
|
|
$target = dirname($zip_file) . DIRECTORY_SEPARATOR . preg_replace('/\.([^.]+)$/', '', basename($zip_file));
|
|
$path = $target;
|
|
$define = dcModules::MODULE_FILE_DEFINE;
|
|
$init = dcModules::MODULE_FILE_INIT;
|
|
}
|
|
|
|
if ($zip->isEmpty()) {
|
|
$zip->close();
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!$zip->hasFile($define)) {
|
|
$zip->close();
|
|
|
|
continue;
|
|
}
|
|
|
|
foreach ($sandboxes as $type => $sandbox) {
|
|
try {
|
|
Files::makeDir($path, true);
|
|
|
|
// can't load twice _init.php file !
|
|
$unlink = false;
|
|
if ($zip->hasFile($init)) {
|
|
$unlink = true;
|
|
$zip->unzip($init, $path);
|
|
}
|
|
|
|
$zip->unzip($define, $path);
|
|
|
|
$sandbox->resetModulesList();
|
|
$sandbox->requireDefine($path, basename($path));
|
|
|
|
if ($unlink) {
|
|
unlink($target . DIRECTORY_SEPARATOR . $init);
|
|
}
|
|
|
|
unlink($target . DIRECTORY_SEPARATOR . $define);
|
|
|
|
if (!$sandbox->getErrors()) {
|
|
$module = $sandbox->getDefine(basename($path));
|
|
if ($module->isDefined() && $module->get('type') == $type) {
|
|
$res[$i] = $module;
|
|
$res[$i]->set('root', $zip_file);
|
|
$i++;
|
|
}
|
|
}
|
|
} catch (Exception $e) {
|
|
}
|
|
Files::deltree($path);
|
|
}
|
|
$zip->close();
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
public static function pack(dcModuleDefine $define, string $root, array $files, bool $overwrite = false, array $exclude = [], bool $nocomment = false, bool $fixnewline = false): bool
|
|
{
|
|
// check define
|
|
if (!$define->isDefined()
|
|
|| empty($define->get('root'))
|
|
|| !is_dir($define->get('root'))
|
|
) {
|
|
throw new Exception(__('Failed to get module info'));
|
|
}
|
|
|
|
// check root
|
|
$root = (string) Path::real($root);
|
|
if (!is_dir($root) || !is_writable($root)) {
|
|
throw new Exception(__('Directory is not writable'));
|
|
}
|
|
|
|
//set excluded
|
|
$exclude = self::quote_exclude(array_merge(My::EXCLUDED_FILES, $exclude));
|
|
|
|
foreach ($files as $file) {
|
|
if (empty($file)) {
|
|
continue;
|
|
}
|
|
|
|
// check path
|
|
$path = $root . DIRECTORY_SEPARATOR . self::getFile($file, $define);
|
|
if (file_exists($path) && !$overwrite) {
|
|
// don't break loop
|
|
continue;
|
|
}
|
|
|
|
@set_time_limit(300);
|
|
|
|
if ($nocomment) {
|
|
Zip::$remove_comment = true;
|
|
}
|
|
if ($fixnewline) {
|
|
Zip::$fix_newline = true;
|
|
}
|
|
$zip = new Zip($path);
|
|
|
|
foreach ($exclude as $e) {
|
|
$zip->addExclusion($e);
|
|
}
|
|
$zip->addDirectory(
|
|
(string) Path::real($define->get('root'), false),
|
|
$define->getId(),
|
|
true
|
|
);
|
|
|
|
$zip->close();
|
|
unset($zip);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static function getFile(string $file, dcModuleDefine $define): string
|
|
{
|
|
$file = str_replace(
|
|
[
|
|
'\\',
|
|
'%type%',
|
|
'%id%',
|
|
'%version%',
|
|
'%author%',
|
|
'%time%',
|
|
],
|
|
[
|
|
'/',
|
|
$define->get('type'),
|
|
$define->getId(),
|
|
$define->get('version'),
|
|
$define->get('author'),
|
|
time(),
|
|
],
|
|
$file
|
|
);
|
|
$parts = explode('/', $file);
|
|
foreach ($parts as $i => $part) {
|
|
$parts[$i] = Files::tidyFileName($part);
|
|
}
|
|
|
|
return implode(DIRECTORY_SEPARATOR, $parts) . '.zip';
|
|
}
|
|
}
|