Files
sam-manage/app/Services/ESign/DocxToPdfConverter.php
김보곤 ab3f26321b fix:LibreOffice HOME 디렉토리 권한 오류 수정
www-data 사용자의 홈 디렉토리에 쓰기 권한이 없어 변환 실패하는 문제.
HOME을 임시 디렉토리로 지정하여 해결.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 10:11:14 +09:00

89 lines
2.8 KiB
PHP

<?php
namespace App\Services\ESign;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use RuntimeException;
class DocxToPdfConverter
{
/**
* Word 파일이면 PDF로 변환, PDF면 그대로 저장.
*
* @return array{path: string, name: string, hash: string, size: int}
*/
public function convertAndStore(UploadedFile $file, string $storagePath): array
{
if (!$this->isWordFile($file)) {
// PDF는 그대로 저장
$path = $file->store($storagePath, 'local');
return [
'path' => $path,
'name' => $file->getClientOriginalName(),
'hash' => hash_file('sha256', $file->getRealPath()),
'size' => $file->getSize(),
];
}
// Word → PDF 변환
$originalName = $file->getClientOriginalName();
$pdfName = preg_replace('/\.(docx?|DOCX?)$/', '.pdf', $originalName);
$tmpDir = sys_get_temp_dir() . '/esign_convert_' . Str::random(16);
mkdir($tmpDir, 0755, true);
try {
$tmpWordPath = $tmpDir . '/' . 'source.' . $file->getClientOriginalExtension();
copy($file->getRealPath(), $tmpWordPath);
$command = sprintf(
'HOME=%s libreoffice --headless --convert-to pdf --outdir %s %s 2>&1',
escapeshellarg($tmpDir),
escapeshellarg($tmpDir),
escapeshellarg($tmpWordPath)
);
exec($command, $output, $exitCode);
if ($exitCode !== 0) {
throw new RuntimeException(
'LibreOffice 변환 실패 (exit code: ' . $exitCode . '): ' . implode("\n", $output)
);
}
$tmpPdfPath = $tmpDir . '/source.pdf';
if (!file_exists($tmpPdfPath)) {
throw new RuntimeException('변환된 PDF 파일을 찾을 수 없습니다.');
}
$hash = hash_file('sha256', $tmpPdfPath);
$size = filesize($tmpPdfPath);
// 최종 저장 경로
$finalPath = $storagePath . '/' . Str::random(40) . '.pdf';
Storage::disk('local')->put($finalPath, file_get_contents($tmpPdfPath));
return [
'path' => $finalPath,
'name' => $pdfName,
'hash' => $hash,
'size' => $size,
];
} finally {
// 임시 파일 정리
array_map('unlink', glob($tmpDir . '/*'));
@rmdir($tmpDir);
}
}
public function isWordFile(UploadedFile $file): bool
{
$ext = strtolower($file->getClientOriginalExtension());
return in_array($ext, ['doc', 'docx']);
}
}