المقدمة

عندما يتلقى قسم الشؤون القانونية عدة ملفات PDF لعقود، غالبًا ما يضيف كل مراجع كلمة مرور خاصة به لحماية البنود السرية. يصبح دمج هذه الملفات في ملف واحد كابوسًا لأن كلمات المرور مختلفة ولا يمكن دمج الملفات مباشرة. فك التشفير يدويًا يستغرق وقتًا طويلاً وعرضة للأخطاء، خاصةً عند التعامل مع العشرات من ملفات PDF.

Password‑merge هو سير عمل GroupDocs.Merger للـ Java يقوم بفك تشفير ملفات PDF المتنوعة ثم يعيد حماية النتيجة المدمجة ببيانات اعتماد واحدة. يشرح هذا الدرس كيفية اكتشاف ملفات PDF المحمية، فك تشفيرها، دمج المحتوى، وإمكانية تدوير كلمة المرور الموحدة.

ستتعلم كيفية تكوين API الخاص بـ Merger، معالجة تدفقات البايتات، وإنشاء ملف PDF موحد وآمن بأقل من 30 سطرًا من كود Java.

متى يجب دمج ملفات PDF المحمية بكلمة مرور؟

يكون دمج ملفات PDF المحمية بكلمة مرور منطقيًا كلما احتجت إلى أرشيف واحد قابل للبحث يحترم سياسات الأمان مع القضاء على عبء التعامل مع كلمات مرور متعددة. تشمل السيناريوهات الشائعة حزم التقارير المالية ربع السنوية، ملفات العقود للمراجعات، وملفات القضايا القانونية حيث يضيف كل مساهم كلمة مرور مختلفة. من خلال فك حماية كل ملف برمجيًا وتطبيق كلمة مرور موحدة، تحافظ على أمان الأرشيف وتبسط عمليات المراجعة اللاحقة. يمكن أتمتة العملية بالكامل في خط أنابيب CI، مما يوفر ساعات من العمل اليدوي.

المتطلبات المسبقة

  • Java 11 أو أحدث
  • GroupDocs.Merger للـ Java 24.6+ (temporary license)
  • مجموعة من ملفات PDF، كل منها قد يكون مرتبطًا بكلمة مرور

تثبيت المكتبة عبر Maven:

mvn dependency:copy -Dartifact=com.groupdocs:groupdocs-merger:24.6

الخطوة 1 – اكتشاف ما إذا كان ملف PDF محميًا بكلمة مرور

قبل محاولة فك تشفير ملف، تحقق مما إذا كان يحمل كلمة مرور بالفعل. هذا يجنب المعالجة غير الضرورية ويسمح لك بتسجيل الملفات التي تحتاج إلى بيانات اعتماد.

// Returns true if the PDF at `path` has an owner or user password
public boolean isDocumentProtected(String path, String password) {
    Merger merger;
    if (password == null || password.isEmpty()) {
        merger = new Merger(path);
    } else {
        merger = new Merger(path, new LoadOptions(password));
    }
    try {
        return merger.isPasswordSet();
    } finally {
        merger.dispose();
    }
}

نقاط رئيسية:

  • LoadOptions يحمل كلمة مرور معروفة؛ إذا لم تُقدم أي كلمة مرور يُفتح الملف بشكل طبيعي.
  • isPasswordSet() يُعيد true لكل من كلمات مرور المالك والمستخدم.
  • احرص دائمًا على تحرير كائن Merger لتحرير الموارد الأصلية.

الخطوة 2 – فك حماية كل PDF وجمع البايتات الخام

تجول عبر خريطة يكون المفتاح فيها مسار الملف والقيمة هي كلمة المرور (null إذا لا توجد). تُعيد الطريقة قائمة من مصفوفات البايت التي تمثل ملفات PDF غير المشفرة.

public List<byte[]> unlockAll(Map<String, String> sources) throws IOException {
    List<byte[]> unlocked = new ArrayList<>();
    for (Map.Entry<String, String> e : sources.entrySet()) {
        String path = e.getKey();
        String password = e.getValue();
        System.out.println("Unlocking (credentials=" +
                (password != null ? "yes" : "no") + "): " + path);
        if (password == null || password.isEmpty()) {
            unlocked.add(Files.readAllBytes(Paths.get(path)));
        } else {
            LoadOptions opts = new LoadOptions(password);
            ByteArrayOutputStream buf = new ByteArrayOutputStream();
            Merger m = new Merger(path, opts);
            try {
                m.removePassword();
                m.save(buf);
            } finally {
                m.dispose();
            }
            unlocked.add(buf.toByteArray());
        }
    }
    return unlocked;
}

نقاط رئيسية:

  • removePassword() يزيل الحماية الحالية.
  • يُكتب المحتوى المفك إلى ByteArrayOutputStream للمعالجة في الذاكرة.
  • تُقرأ الملفات التي لا تحتوي على كلمة مرور مباشرةً لتبسيط التدفق.

الخطوة 3 – دمج ملفات PDF غير المشفرة وتطبيق كلمة مرور موحدة

أنشئ كائن Merger من تدفق الـ PDF الأول، ثم أضف التدفقات المتبقية. أخيرًا، احمِ المستند المدمج باستخدام AddPasswordOptions.

public void mergeAndProtect(List<byte[]> unlockedPdfs,
                            String unifiedPassword,
                            String outputPath) {
    InputStream first = new ByteArrayInputStream(unlockedPdfs.get(0));
    Merger merger = new Merger(first);
    try {
        for (int i = 1; i < unlockedPdfs.size(); i++) {
            merger.join(new ByteArrayInputStream(unlockedPdfs.get(i)));
        }
        merger.addPassword(new AddPasswordOptions(unifiedPassword));
        merger.save(outputPath);
    } finally {
        merger.dispose();
    }
    System.out.println("Merged output: " + new File(outputPath).getAbsolutePath());
    System.out.println("Unified password: " + unifiedPassword);
}

نقاط رئيسية:

  • addPassword يُشفّر ملف PDF النهائي ببيانات الاعتماد المقدمة.
  • جميع العمليات تتم في الذاكرة؛ يُكتب الملف النهائي فقط إلى القرص.
  • حرّر كائن Merger لإطلاق المقابض الأصلية.

الخطوة 4 – تدوير كلمة المرور على ملف PDF محمي بالفعل (اختياري)

إذا كانت مؤسستك تُجري تدويرًا دوريًا لكلمات المرور، يمكنك تحديث كلمة المرور دون الحاجة لإعادة دمج الملفات المصدر.

public void rotateUnifiedPassword(String path,
                                 String oldPassword,
                                 String newPassword,
                                 String outputPath) {
    Merger merger = new Merger(path, new LoadOptions(oldPassword));
    try {
        merger.updatePassword(new UpdatePasswordOptions(newPassword));
        merger.save(outputPath);
    } finally {
        merger.dispose();
    }
    System.out.println("Rotated output: " + new File(outputPath).getAbsolutePath());
    System.out.println("New password: " + newPassword);
}

نقاط رئيسية:

  • حمّل ملف PDF المحمي باستخدام كلمة المرور الحالية.
  • updatePassword يستبدلها بالبيانات الجديدة.
  • هذه العملية سريعة لأنها لا تعيد معالجة محتوى PDF.

تطبيق عملي

واجهت هذا الموقف عند دمج خمس عقود مستثمرين كان لكل منها كلمة مرور مراجع مختلفة. باستخدام الخطوات السابقة، فكّيت جميع الملفات، دمجتها في ملف واحد، وطبقت كلمة مرور واحدة تتماشى مع سياسات الشركة. استغرق العملية بأكملها أقل من دقيقتين على حاسوب محمول عادي.

أفضل الممارسات

  • التحقق من كلمات المرور مبكرًا: استخدم isDocumentProtected لتحديد الملفات التي قد تحتاج إلى تدخل يدوي.
  • تقليل استهلاك الذاكرة: بالنسبة لملفات PDF الكبيرة، قم بتدفقها إلى القرص بدلاً من الاحتفاظ بجميع مصفوفات البايت في الذاكرة.
  • تحرير الكائنات فورًا: فئة Merger تحتفظ بموارد أصلية؛ احرص دائمًا على استدعاء dispose() داخل كتلة finally.
  • استخدام ترخيص مؤقت فقط للتطوير؛ احصل على ترخيص إنتاج قبل الإصدار.

الخلاصة

يقدم GroupDocs.Merger للـ Java واجهة برمجة تطبيقات نظيفة لفك تشفير، دمج، وإعادة تأمين مجموعات PDF. باتباع الخطوات الأربع — اكتشاف الحماية، فك التشفير، الدمج بكلمة مرور موحدة، وتدوير كلمة المرور إذا لزم الأمر — يمكنك أتمتة إنشاء ملفات PDF آمنة دون تدخل يدوي.

الخطوات التالية:

  • استكشف خيارات إضافية مثل تعيين بيانات تعريف PDF بعد الدمج (documentation).
  • تعلّم كيفية دمج ملفات PDF مع الحفاظ على العلامات المرجعية (API reference).
  • اطلع على المشروع الكامل على GitHub لتطبيق جاهز للتشغيل.

موارد إضافية