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']); } }