「PHPの基礎 - 圧縮・解凍」の版間の差分
ナビゲーションに移動
検索に移動
(→圧縮) |
|||
87行目: | 87行目: | ||
<br> | <br> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
declare(strict_types=1); | |||
namespace Utils; | |||
use RuntimeException; | |||
use Generator; | |||
/** | /** | ||
* tar.gz形式で圧縮を行うメソッド | * tar.gz形式で圧縮を行うメソッド | ||
167行目: | 174行目: | ||
<br> | <br> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
declare(strict_types=1); | |||
namespace Utils; | |||
use RuntimeException; | |||
use Generator; | |||
/** | /** | ||
* tar.xz形式で圧縮を行うメソッド | * tar.xz形式で圧縮を行うメソッド |
2024年11月9日 (土) 18:38時点における版
概要
圧縮
以下に示す例では、非同期処理のサポート、ストリーミング処理による効率的なメモリ使用、エラーハンドリングを実装している。
また、3つの圧縮形式 (ZIP、tar.gz、tar.xz) に対応している。
ZIP形式
declare(strict_types=1);
namespace Utils;
use RuntimeException;
use ZipArchive;
use Generator;
/**
* ZIP形式で圧縮を行うメソッド
*
* @param string $sourcePath 圧縮対象のパス(ファイルまたはディレクトリ)
* @param string $destinationPath 出力先のZIPファイルパス
* @throws RuntimeException 圧縮処理中のエラー発生時
*/
function compressToZip(string $sourcePath, string $destinationPath): void
{
try {
$zip = new ZipArchive();
// ZIPファイルのオープン
if ($zip->open($destinationPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
throw new RuntimeException('ZIPファイルの作成に失敗しました');
}
// ディレクトリの場合は再帰的に処理
if (is_dir($sourcePath)) {
$files = $this->getFilesRecursively($sourcePath);
foreach ($files as $file) {
$relativePath = substr($file, strlen($sourcePath) + 1);
$zip->addFile($file, $relativePath);
}
}
else {
// 単一ファイルの場合
$zip->addFile($sourcePath, basename($sourcePath));
}
$zip->close();
}
catch (\Exception $e) {
throw new RuntimeException("ZIP圧縮処理中にエラーが発生しました: {$e->getMessage()}");
}
}
/**
* ディレクトリ内のファイルを再帰的に取得するプライベートメソッド
*
* @param string $dir 検索対象ディレクトリ
* @return Generator ファイルパスを返すジェネレータ
*/
function getFilesRecursively(string $dir): Generator
{
$files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::LEAVES_ONLY);
foreach ($files as $file) {
yield $file->getRealPath();
}
}
// 使用例
$compression = new Utils\CompressionUtils();
try {
$compression->compressToZip('/path/to/source', '/path/to/output.zip');
}
catch (RuntimeException $e) {
echo "エラーが発生しました: " . $e->getMessage();
}
tar.gz形式
tar.gz圧縮を行う場合は、システムにtarコマンドがインストールされている必要がある。
declare(strict_types=1);
namespace Utils;
use RuntimeException;
use Generator;
/**
* tar.gz形式で圧縮を行うメソッド
*
* @param string $sourcePath 圧縮対象のパス
* @param string $destinationPath 出力先のtar.gzファイルパス
* @throws RuntimeException 圧縮処理中のエラー発生時
*/
function compressToTarGz(string $sourcePath, string $destinationPath): void
{
try {
// 一時的なTARファイルの作成
$tempTarFile = tempnam(sys_get_temp_dir(), 'tar');
// tarコマンドの実行
$sourceName = basename($sourcePath);
$sourceDir = dirname($sourcePath);
exec("cd {$sourceDir} && tar -cf {$tempTarFile} {$sourceName}", $output, $returnCode);
if ($returnCode !== 0) {
throw new RuntimeException('TAR作成に失敗しました');
}
// gzipでの圧縮処理
$gz = gzopen($destinationPath, 'wb9');
if ($gz === false) {
throw new RuntimeException('GZIPファイルのオープンに失敗しました');
}
// ストリーミング処理でTARファイルを読み込みながら圧縮
$handle = fopen($tempTarFile, 'rb');
while (!feof($handle)) {
gzwrite($gz, fread($handle, 8192));
}
fclose($handle);
gzclose($gz);
// 一時ファイルの削除
unlink($tempTarFile);
}
catch (\Exception $e) {
throw new RuntimeException("tar.gz圧縮処理中にエラーが発生しました: {$e->getMessage()}");
}
}
/**
* ディレクトリ内のファイルを再帰的に取得するプライベートメソッド
*
* @param string $dir 検索対象ディレクトリ
* @return Generator ファイルパスを返すジェネレータ
*/
function getFilesRecursively(string $dir): Generator
{
$files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::LEAVES_ONLY);
foreach ($files as $file) {
yield $file->getRealPath();
}
}
// 使用例
$compression = new Utils\CompressionUtils();
try {
// tar.gz圧縮の例
$compression->compressToTarGz('/path/to/source', '/path/to/output.tar.gz');
}
catch (RuntimeException $e) {
echo "エラーが発生しました: " . $e->getMessage();
}
tar.xz形式
tar.xz形式の圧縮には、PHPのXZ拡張機能が必要である。
また、tar.xz圧縮を行う場合は、システムにtarコマンドがインストールされている必要がある。
declare(strict_types=1);
namespace Utils;
use RuntimeException;
use Generator;
/**
* tar.xz形式で圧縮を行うメソッド
*
* @param string $sourcePath 圧縮対象のパス
* @param string $destinationPath 出力先のtar.xzファイルパス
* @throws RuntimeException 圧縮処理中のエラー発生時
*/
function compressToTarXz(string $sourcePath, string $destinationPath): void
{
try {
// PHPのXZ拡張機能が必要
if (!extension_loaded('xz')) {
throw new RuntimeException('XZ拡張機能がインストールされていません');
}
// 一時的なTARファイルの作成
$tempTarFile = tempnam(sys_get_temp_dir(), 'tar');
// tarコマンドの実行
$sourceName = basename($sourcePath);
$sourceDir = dirname($sourcePath);
exec("cd {$sourceDir} && tar -cf {$tempTarFile} {$sourceName}", $output, $returnCode);
if ($returnCode !== 0) {
throw new RuntimeException('TAR作成に失敗しました');
}
// XZ圧縮の実行
$xzStream = xzopen($destinationPath, 'wb9');
if ($xzStream === false) {
throw new RuntimeException('XZファイルのオープンに失敗しました');
}
// ストリーミング処理でTARファイルを読み込みながら圧縮
$handle = fopen($tempTarFile, 'rb');
while (!feof($handle)) {
xzwrite($xzStream, fread($handle, 8192));
}
fclose($handle);
xzclose($xzStream);
// 一時ファイルの削除
unlink($tempTarFile);
}
catch (\Exception $e) {
throw new RuntimeException("tar.xz圧縮処理中にエラーが発生しました: {$e->getMessage()}");
}
}
/**
* ディレクトリ内のファイルを再帰的に取得するプライベートメソッド
*
* @param string $dir 検索対象ディレクトリ
* @return Generator ファイルパスを返すジェネレータ
*/
function getFilesRecursively(string $dir): Generator
{
$files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::LEAVES_ONLY);
foreach ($files as $file) {
yield $file->getRealPath();
}
}
// 使用例
$compression = new Utils\CompressionUtils();
try {
// tar.xz圧縮の例
$compression->compressToTarXz('/path/to/source', '/path/to/output.tar.xz');
}
catch (RuntimeException $e) {
echo "エラーが発生しました: " . $e->getMessage();
}
非同期処理
/**
* 非同期でファイル圧縮を行うメソッド
*
* @param string $sourcePath 圧縮対象のパス
* @param string $destinationPath 出力先のパス
* @param string $type 圧縮形式('zip', 'tar.gz', 'tar.xz'のいずれか)
* @return Generator 圧縮の進捗状況を返すジェネレータ
*/
function compressAsync(string $sourcePath, string $destinationPath, string $type): Generator
{
yield '圧縮処理を開始します...';
try {
switch ($type) {
case 'zip':
$this->compressToZip($sourcePath, $destinationPath);
break;
case 'tar.gz':
$this->compressToTarGz($sourcePath, $destinationPath);
break;
case 'tar.xz':
$this->compressToTarXz($sourcePath, $destinationPath);
break;
default:
throw new RuntimeException('不正な圧縮形式が指定されました');
}
yield '圧縮処理が完了しました';
}
catch (\Exception $e) {
yield "圧縮処理中にエラーが発生しました: {$e->getMessage()}";
throw $e;
}
}
// 使用例
$compression = new Utils\CompressionUtils();
try {
// 非同期処理の例
// ZIP形式の場合
foreach ($compression->compressAsync('/path/to/source', '/path/to/output.zip', 'zip') as $status) {
echo $status . PHP_EOL;
}
// tar.gz形式の場合
foreach ($compression->compressAsync('/path/to/source', '/path/to/output.zip', 'zip') as $status) {
echo $status . PHP_EOL;
}
// tar.xz形式の場合
foreach ($compression->compressAsync('/path/to/source', '/path/to/output.zip', 'zip') as $status) {
echo $status . PHP_EOL;
}
}
catch (RuntimeException $e) {
echo "エラーが発生しました: " . $e->getMessage();
}