Merge pull request 'fix: package_build.php Joomla package builds + PHPStan level 2' (#95) from dev into main
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 4s
Generic: Repo Health / Access control (push) Successful in 2s
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Release configuration (push) Successful in 5s
Generic: Repo Health / Scripts governance (push) Successful in 5s
Generic: Repo Health / Repository health (push) Successful in 12s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 1m2s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 4s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 38s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 39s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Failing after 40s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Failing after 40s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Failing after 41s
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 4s
Generic: Repo Health / Access control (push) Successful in 2s
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Release configuration (push) Successful in 5s
Generic: Repo Health / Scripts governance (push) Successful in 5s
Generic: Repo Health / Repository health (push) Successful in 12s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 1m2s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 4s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 38s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 39s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Failing after 40s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Failing after 40s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Failing after 41s
Platform: moko-platform CI / CI Summary (push) Has been cancelled
This commit was merged in pull request #95.
This commit is contained in:
@@ -26,6 +26,7 @@ Version format: `XX.YY.ZZ` (zero-padded semver).
|
|||||||
### Fixed
|
### Fixed
|
||||||
- `release_cascade.php`: accept `release-candidate` as stability value (was only accepting `rc`, causing cascade to silently skip)
|
- `release_cascade.php`: accept `release-candidate` as stability value (was only accepting `rc`, causing cascade to silently skip)
|
||||||
- PHPStan bumped from level 0 to level 2 — fixed 67 type errors (undefined variables, missing methods, wrong signatures, dead code)
|
- PHPStan bumped from level 0 to level 2 — fixed 67 type errors (undefined variables, missing methods, wrong signatures, dead code)
|
||||||
|
- `package_build.php`: fix 0-byte ZIP for Joomla package extensions — sub-zips now in `packages/` subdir, no double `pkg_pkg_` prefix, includes `language/` dir (closes #92)
|
||||||
|
|
||||||
## [06.00.00] - 2026-05-25
|
## [06.00.00] - 2026-05-25
|
||||||
|
|
||||||
|
|||||||
+225
-163
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env php
|
#!/usr/bin/env php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
@@ -37,17 +38,29 @@ $elementOverride = null;
|
|||||||
$githubOutput = false;
|
$githubOutput = false;
|
||||||
|
|
||||||
foreach ($argv as $i => $arg) {
|
foreach ($argv as $i => $arg) {
|
||||||
if ($arg === '--path' && isset($argv[$i + 1])) $path = $argv[$i + 1];
|
if ($arg === '--path' && isset($argv[$i + 1])) {
|
||||||
if ($arg === '--version' && isset($argv[$i + 1])) $version = $argv[$i + 1];
|
$path = $argv[$i + 1];
|
||||||
if ($arg === '--output-dir' && isset($argv[$i + 1])) $outputDir = $argv[$i + 1];
|
}
|
||||||
if ($arg === '--type-prefix' && isset($argv[$i + 1])) $typePrefixOverride = $argv[$i + 1];
|
if ($arg === '--version' && isset($argv[$i + 1])) {
|
||||||
if ($arg === '--element' && isset($argv[$i + 1])) $elementOverride = $argv[$i + 1];
|
$version = $argv[$i + 1];
|
||||||
if ($arg === '--github-output') $githubOutput = true;
|
}
|
||||||
|
if ($arg === '--output-dir' && isset($argv[$i + 1])) {
|
||||||
|
$outputDir = $argv[$i + 1];
|
||||||
|
}
|
||||||
|
if ($arg === '--type-prefix' && isset($argv[$i + 1])) {
|
||||||
|
$typePrefixOverride = $argv[$i + 1];
|
||||||
|
}
|
||||||
|
if ($arg === '--element' && isset($argv[$i + 1])) {
|
||||||
|
$elementOverride = $argv[$i + 1];
|
||||||
|
}
|
||||||
|
if ($arg === '--github-output') {
|
||||||
|
$githubOutput = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($version === null) {
|
if ($version === null) {
|
||||||
fwrite(STDERR, "Usage: package_build.php --path . --version XX.YY.ZZ [--output-dir /tmp]\n");
|
fwrite(STDERR, "Usage: package_build.php --path . --version XX.YY.ZZ [--output-dir /tmp]\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$root = realpath($path) ?: $path;
|
$root = realpath($path) ?: $path;
|
||||||
@@ -55,15 +68,15 @@ $root = realpath($path) ?: $path;
|
|||||||
// -- Determine source directory -----------------------------------------------
|
// -- Determine source directory -----------------------------------------------
|
||||||
$sourceDir = null;
|
$sourceDir = null;
|
||||||
foreach (['src', 'htdocs'] as $candidate) {
|
foreach (['src', 'htdocs'] as $candidate) {
|
||||||
if (is_dir("{$root}/{$candidate}")) {
|
if (is_dir("{$root}/{$candidate}")) {
|
||||||
$sourceDir = "{$root}/{$candidate}";
|
$sourceDir = "{$root}/{$candidate}";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($sourceDir === null) {
|
if ($sourceDir === null) {
|
||||||
fwrite(STDERR, "No src/ or htdocs/ directory found in {$root}\n");
|
fwrite(STDERR, "No src/ or htdocs/ directory found in {$root}\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Determine element and type prefix from manifest --------------------------
|
// -- Determine element and type prefix from manifest --------------------------
|
||||||
@@ -73,54 +86,80 @@ $extType = '';
|
|||||||
$isPackage = false;
|
$isPackage = false;
|
||||||
|
|
||||||
if ($extElement === null || $typePrefixOverride === null) {
|
if ($extElement === null || $typePrefixOverride === null) {
|
||||||
// Find manifest
|
// Find manifest
|
||||||
$manifest = null;
|
$manifest = null;
|
||||||
foreach (glob("{$sourceDir}/pkg_*.xml") ?: [] as $f) {
|
foreach (glob("{$sourceDir}/pkg_*.xml") ?: [] as $f) {
|
||||||
if (strpos(file_get_contents($f), '<extension') !== false) {
|
if (strpos(file_get_contents($f), '<extension') !== false) {
|
||||||
$manifest = $f;
|
$manifest = $f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($manifest === null) {
|
if ($manifest === null) {
|
||||||
foreach (glob("{$sourceDir}/*.xml") ?: [] as $f) {
|
foreach (glob("{$sourceDir}/*.xml") ?: [] as $f) {
|
||||||
if (strpos(file_get_contents($f), '<extension') !== false) {
|
if (strpos(file_get_contents($f), '<extension') !== false) {
|
||||||
$manifest = $f;
|
$manifest = $f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($manifest !== null) {
|
if ($manifest !== null) {
|
||||||
$xml = file_get_contents($manifest);
|
$xml = file_get_contents($manifest);
|
||||||
|
|
||||||
if ($extElement === null) {
|
if ($extElement === null) {
|
||||||
if (preg_match('/<element>([^<]+)<\/element>/', $xml, $m)) $extElement = $m[1];
|
if (preg_match('/<element>([^<]+)<\/element>/', $xml, $m)) {
|
||||||
elseif (preg_match('/plugin="([^"]+)"/', $xml, $m)) $extElement = $m[1];
|
$extElement = $m[1];
|
||||||
elseif (preg_match('/module="([^"]+)"/', $xml, $m)) $extElement = $m[1];
|
} elseif (preg_match('/plugin="([^"]+)"/', $xml, $m)) {
|
||||||
else $extElement = strtolower(pathinfo($manifest, PATHINFO_FILENAME));
|
$extElement = $m[1];
|
||||||
}
|
} elseif (preg_match('/module="([^"]+)"/', $xml, $m)) {
|
||||||
|
$extElement = $m[1];
|
||||||
|
} else {
|
||||||
|
$extElement = strtolower(pathinfo($manifest, PATHINFO_FILENAME));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (preg_match('/<extension[^>]*type="([^"]+)"/', $xml, $m)) $extType = $m[1];
|
if (preg_match('/<extension[^>]*type="([^"]+)"/', $xml, $m)) {
|
||||||
$extFolder = '';
|
$extType = $m[1];
|
||||||
if (preg_match('/<extension[^>]*group="([^"]+)"/', $xml, $m)) $extFolder = $m[1];
|
}
|
||||||
|
$extFolder = '';
|
||||||
|
if (preg_match('/<extension[^>]*group="([^"]+)"/', $xml, $m)) {
|
||||||
|
$extFolder = $m[1];
|
||||||
|
}
|
||||||
|
|
||||||
if ($typePrefixOverride === null) {
|
if ($typePrefixOverride === null) {
|
||||||
switch ($extType) {
|
switch ($extType) {
|
||||||
case 'plugin': $typePrefix = "plg_{$extFolder}_"; break;
|
case 'plugin':
|
||||||
case 'module': $typePrefix = 'mod_'; break;
|
$typePrefix = "plg_{$extFolder}_";
|
||||||
case 'component': $typePrefix = 'com_'; break;
|
break;
|
||||||
case 'template': $typePrefix = 'tpl_'; break;
|
case 'module':
|
||||||
case 'library': $typePrefix = 'lib_'; break;
|
$typePrefix = 'mod_';
|
||||||
case 'package': $typePrefix = 'pkg_'; break;
|
break;
|
||||||
}
|
case 'component':
|
||||||
}
|
$typePrefix = 'com_';
|
||||||
|
break;
|
||||||
|
case 'template':
|
||||||
|
$typePrefix = 'tpl_';
|
||||||
|
break;
|
||||||
|
case 'library':
|
||||||
|
$typePrefix = 'lib_';
|
||||||
|
break;
|
||||||
|
case 'package':
|
||||||
|
$typePrefix = 'pkg_';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$isPackage = ($extType === 'package' && is_dir("{$sourceDir}/packages"));
|
$isPackage = ($extType === 'package' && is_dir("{$sourceDir}/packages"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($extElement === null) {
|
if ($extElement === null) {
|
||||||
$extElement = strtolower(basename($root));
|
$extElement = strtolower(basename($root));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent double prefix (e.g. pkg_pkg_mokogallery)
|
||||||
|
if ($typePrefix !== '' && str_starts_with($extElement, rtrim($typePrefix, '_'))) {
|
||||||
|
$extElement = substr($extElement, strlen(rtrim($typePrefix, '_')) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$zipName = "{$typePrefix}{$extElement}-{$version}.zip";
|
$zipName = "{$typePrefix}{$extElement}-{$version}.zip";
|
||||||
@@ -130,87 +169,106 @@ $tarPath = "{$outputDir}/{$tarName}";
|
|||||||
|
|
||||||
// -- Exclude patterns ---------------------------------------------------------
|
// -- Exclude patterns ---------------------------------------------------------
|
||||||
$excludePatterns = [
|
$excludePatterns = [
|
||||||
'.ftpignore',
|
'.ftpignore',
|
||||||
'sftp-config*',
|
'sftp-config*',
|
||||||
'*.ppk',
|
'*.ppk',
|
||||||
'*.pem',
|
'*.pem',
|
||||||
'*.key',
|
'*.key',
|
||||||
'.env*',
|
'.env*',
|
||||||
];
|
];
|
||||||
|
|
||||||
// -- Build packages -----------------------------------------------------------
|
// -- Build packages -----------------------------------------------------------
|
||||||
if ($isPackage) {
|
if ($isPackage) {
|
||||||
echo "=== Building Joomla PACKAGE (multi-extension) ===\n";
|
echo "=== Building Joomla PACKAGE (multi-extension) ===\n";
|
||||||
|
|
||||||
$stagingDir = sys_get_temp_dir() . '/moko-pkg-' . uniqid();
|
$stagingDir = sys_get_temp_dir() . '/moko-pkg-' . uniqid();
|
||||||
mkdir($stagingDir, 0755, true);
|
$packagesDir = "{$stagingDir}/packages";
|
||||||
|
mkdir($packagesDir, 0755, true);
|
||||||
|
|
||||||
// ZIP each sub-extension
|
// ZIP each sub-extension into packages/
|
||||||
foreach (glob("{$sourceDir}/packages/*/") ?: [] as $extDir) {
|
foreach (glob("{$sourceDir}/packages/*/") ?: [] as $extDir) {
|
||||||
$subName = basename($extDir);
|
$subName = basename($extDir);
|
||||||
echo " Packaging sub-extension: {$subName}\n";
|
echo " Packaging sub-extension: {$subName}\n";
|
||||||
|
|
||||||
$subZip = new ZipArchive();
|
$subZip = new ZipArchive();
|
||||||
$subZipPath = "{$stagingDir}/{$subName}.zip";
|
$subZipPath = "{$packagesDir}/{$subName}.zip";
|
||||||
if ($subZip->open($subZipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
|
if ($subZip->open($subZipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
|
||||||
fwrite(STDERR, "Failed to create ZIP for {$subName}\n");
|
fwrite(STDERR, "Failed to create ZIP for {$subName}\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
addDirectoryToZip($subZip, $extDir, '', $excludePatterns);
|
addDirectoryToZip($subZip, $extDir, '', $excludePatterns);
|
||||||
$subZip->close();
|
$subZip->close();
|
||||||
}
|
echo " -> packages/{$subName}.zip (" . filesize($subZipPath) . " bytes)\n";
|
||||||
|
}
|
||||||
|
|
||||||
// Copy package-level files
|
// Copy package-level files (manifest, script.php, etc.)
|
||||||
foreach (array_merge(glob("{$sourceDir}/*.xml") ?: [], glob("{$sourceDir}/*.php") ?: []) as $f) {
|
foreach (array_merge(glob("{$sourceDir}/*.xml") ?: [], glob("{$sourceDir}/*.php") ?: []) as $f) {
|
||||||
copy($f, "{$stagingDir}/" . basename($f));
|
copy($f, "{$stagingDir}/" . basename($f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create ZIP from staging
|
// Copy language directory if present
|
||||||
$zip = new ZipArchive();
|
if (is_dir("{$sourceDir}/language")) {
|
||||||
if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
|
$langDest = "{$stagingDir}/language";
|
||||||
fwrite(STDERR, "Failed to create ZIP: {$zipPath}\n");
|
mkdir($langDest, 0755, true);
|
||||||
exit(1);
|
$langIterator = new RecursiveIteratorIterator(
|
||||||
}
|
new RecursiveDirectoryIterator("{$sourceDir}/language", RecursiveDirectoryIterator::SKIP_DOTS),
|
||||||
addDirectoryToZip($zip, $stagingDir, '', []);
|
RecursiveIteratorIterator::SELF_FIRST
|
||||||
$zip->close();
|
);
|
||||||
|
foreach ($langIterator as $item) {
|
||||||
|
$target = $langDest . '/' . substr($item->getPathname(), strlen("{$sourceDir}/language") + 1);
|
||||||
|
if ($item->isDir()) {
|
||||||
|
mkdir($target, 0755, true);
|
||||||
|
} else {
|
||||||
|
copy($item->getPathname(), $target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create tar.gz — all arguments are escaped via escapeshellarg()
|
// Create ZIP from staging
|
||||||
$tarCmd = sprintf(
|
$zip = new ZipArchive();
|
||||||
'tar -czf %s -C %s .',
|
if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
|
||||||
escapeshellarg($tarPath),
|
fwrite(STDERR, "Failed to create ZIP: {$zipPath}\n");
|
||||||
escapeshellarg($stagingDir)
|
exit(1);
|
||||||
);
|
}
|
||||||
passthru($tarCmd, $tarReturn);
|
addDirectoryToZip($zip, $stagingDir, '', []);
|
||||||
|
$zip->close();
|
||||||
|
|
||||||
// Cleanup staging
|
// Create tar.gz — all arguments are escaped via escapeshellarg()
|
||||||
$cleanCmd = sprintf('rm -rf %s', escapeshellarg($stagingDir));
|
$tarCmd = sprintf(
|
||||||
passthru($cleanCmd);
|
'tar -czf %s -C %s .',
|
||||||
|
escapeshellarg($tarPath),
|
||||||
|
escapeshellarg($stagingDir)
|
||||||
|
);
|
||||||
|
passthru($tarCmd, $tarReturn);
|
||||||
|
|
||||||
|
// Cleanup staging
|
||||||
|
$cleanCmd = sprintf('rm -rf %s', escapeshellarg($stagingDir));
|
||||||
|
passthru($cleanCmd);
|
||||||
} else {
|
} else {
|
||||||
echo "=== Building standard extension package ===\n";
|
echo "=== Building standard extension package ===\n";
|
||||||
|
|
||||||
// ZIP
|
// ZIP
|
||||||
$zip = new ZipArchive();
|
$zip = new ZipArchive();
|
||||||
if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
|
if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
|
||||||
fwrite(STDERR, "Failed to create ZIP: {$zipPath}\n");
|
fwrite(STDERR, "Failed to create ZIP: {$zipPath}\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
addDirectoryToZip($zip, $sourceDir, '', $excludePatterns);
|
addDirectoryToZip($zip, $sourceDir, '', $excludePatterns);
|
||||||
$zip->close();
|
$zip->close();
|
||||||
|
|
||||||
// tar.gz — all arguments are escaped via escapeshellarg()
|
// tar.gz — all arguments are escaped via escapeshellarg()
|
||||||
$excludeArgs = '';
|
$excludeArgs = '';
|
||||||
foreach ($excludePatterns as $pattern) {
|
foreach ($excludePatterns as $pattern) {
|
||||||
$excludeArgs .= ' --exclude=' . escapeshellarg($pattern);
|
$excludeArgs .= ' --exclude=' . escapeshellarg($pattern);
|
||||||
}
|
}
|
||||||
$tarCmd = sprintf(
|
$tarCmd = sprintf(
|
||||||
'tar -czf %s -C %s%s .',
|
'tar -czf %s -C %s%s .',
|
||||||
escapeshellarg($tarPath),
|
escapeshellarg($tarPath),
|
||||||
escapeshellarg($sourceDir),
|
escapeshellarg($sourceDir),
|
||||||
$excludeArgs
|
$excludeArgs
|
||||||
);
|
);
|
||||||
passthru($tarCmd, $tarReturn);
|
passthru($tarCmd, $tarReturn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Calculate SHA-256 --------------------------------------------------------
|
// -- Calculate SHA-256 --------------------------------------------------------
|
||||||
@@ -224,29 +282,31 @@ echo "\n";
|
|||||||
echo "ZIP: {$zipName} ({$zipSize} bytes)\n";
|
echo "ZIP: {$zipName} ({$zipSize} bytes)\n";
|
||||||
echo " SHA-256: {$sha256Zip}\n";
|
echo " SHA-256: {$sha256Zip}\n";
|
||||||
if ($tarSize > 0) {
|
if ($tarSize > 0) {
|
||||||
echo "TAR: {$tarName} ({$tarSize} bytes)\n";
|
echo "TAR: {$tarName} ({$tarSize} bytes)\n";
|
||||||
echo " SHA-256: {$sha256Tar}\n";
|
echo " SHA-256: {$sha256Tar}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Export to GITHUB_OUTPUT --------------------------------------------------
|
// -- Export to GITHUB_OUTPUT --------------------------------------------------
|
||||||
if ($githubOutput) {
|
if ($githubOutput) {
|
||||||
$ghOutput = getenv('GITHUB_OUTPUT');
|
$ghOutput = getenv('GITHUB_OUTPUT');
|
||||||
$lines = [
|
$lines = [
|
||||||
"zip_name={$zipName}",
|
"zip_name={$zipName}",
|
||||||
"tar_name={$tarName}",
|
"tar_name={$tarName}",
|
||||||
"zip_path={$zipPath}",
|
"zip_path={$zipPath}",
|
||||||
"tar_path={$tarPath}",
|
"tar_path={$tarPath}",
|
||||||
"sha256_zip={$sha256Zip}",
|
"sha256_zip={$sha256Zip}",
|
||||||
"sha256_tar={$sha256Tar}",
|
"sha256_tar={$sha256Tar}",
|
||||||
"type_prefix={$typePrefix}",
|
"type_prefix={$typePrefix}",
|
||||||
"ext_element={$extElement}",
|
"ext_element={$extElement}",
|
||||||
];
|
];
|
||||||
if ($ghOutput) {
|
if ($ghOutput) {
|
||||||
file_put_contents($ghOutput, implode("\n", $lines) . "\n", FILE_APPEND);
|
file_put_contents($ghOutput, implode("\n", $lines) . "\n", FILE_APPEND);
|
||||||
fwrite(STDERR, "Exported " . count($lines) . " fields to GITHUB_OUTPUT\n");
|
fwrite(STDERR, "Exported " . count($lines) . " fields to GITHUB_OUTPUT\n");
|
||||||
} else {
|
} else {
|
||||||
foreach ($lines as $line) echo "{$line}\n";
|
foreach ($lines as $line) {
|
||||||
}
|
echo "{$line}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
@@ -256,33 +316,35 @@ exit(0);
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
function addDirectoryToZip(ZipArchive $zip, string $dir, string $prefix, array $excludes): void
|
function addDirectoryToZip(ZipArchive $zip, string $dir, string $prefix, array $excludes): void
|
||||||
{
|
{
|
||||||
$iterator = new RecursiveIteratorIterator(
|
$iterator = new RecursiveIteratorIterator(
|
||||||
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
|
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
|
||||||
RecursiveIteratorIterator::SELF_FIRST
|
RecursiveIteratorIterator::SELF_FIRST
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($iterator as $file) {
|
foreach ($iterator as $file) {
|
||||||
$filePath = $file->getPathname();
|
$filePath = $file->getPathname();
|
||||||
$relativePath = $prefix . substr($filePath, strlen($dir) + 1);
|
$relativePath = $prefix . substr($filePath, strlen($dir) + 1);
|
||||||
|
|
||||||
// Check excludes
|
// Check excludes
|
||||||
$basename = basename($filePath);
|
$basename = basename($filePath);
|
||||||
$skip = false;
|
$skip = false;
|
||||||
foreach ($excludes as $pattern) {
|
foreach ($excludes as $pattern) {
|
||||||
if (fnmatch($pattern, $basename)) {
|
if (fnmatch($pattern, $basename)) {
|
||||||
$skip = true;
|
$skip = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($skip) continue;
|
if ($skip) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Normalize path separators for ZIP
|
// Normalize path separators for ZIP
|
||||||
$relativePath = str_replace('\\', '/', $relativePath);
|
$relativePath = str_replace('\\', '/', $relativePath);
|
||||||
|
|
||||||
if ($file->isDir()) {
|
if ($file->isDir()) {
|
||||||
$zip->addEmptyDir($relativePath);
|
$zip->addEmptyDir($relativePath);
|
||||||
} else {
|
} else {
|
||||||
$zip->addFile($filePath, $relativePath);
|
$zip->addFile($filePath, $relativePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user