0%

[DotnetCore]Reader系列-Pdf檔案:iTextSharp

前情提要

筆者這邊有一個需求是,pdf檔案在上傳時就判斷好是否有加密,避免後面流程中需要解析pdf檔案時,遇到解密的問題,因此為避免後面流程複雜去防呆,直接於上傳檔案時築一道防線擋掉,是最佳解。筆者在搜尋了一下c# detect password protected pdf的關鍵字時,基本上會跳出使用iTextSharp的解法,筆者就參考此解法寫一個Extension,主要都是參考StackOverFlow的解法,程式碼本身沒甚麼變動,此篇以解釋為準。

內容

筆者這邊驗證的方式使用Linqpad也程式碼片段,因此測試過程需要

  • 使用Microsoft Word製作一個包含簡單內容的文件,已另存新檔案的方式存成pdf檔案
  • 透過pdf加密程式碼片段,產生已加密的pdf檔案
  • 透過偵測是否加密的程式碼片段,偵測該pdf檔案是否有加密

接著在講述一下iTextSharpLicense5.0以下才是標示LGPLLicense,且已經無法在nuget上面搜尋得到,好佳在網路上的大神們,有把iTextSharp4.1.6版本(LGPL)轉成dotnet core版本,因此筆者才得以在dotnet core專案上使用。

https://github.com/VahidN/iTextSharp.LGPLv2.Core

製作Test.pdf

筆者這邊使用敘述的方式,基本上打開word軟體後,寫一些簡單內容,1234之類的,接著使用另存新檔的方式,存檔至桌面,副檔名選擇pdf格式,並且將檔案命名為Test.pdf備用。

製作Test_enc.pdf

接著因為筆者環境本身沒有pdf加密軟體,只好用iTextSharp的程式片段來製作加密檔案

1
2
3
4
5
6
7
8
9
10
11
12
string WorkingFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string InputFile = Path.Combine(WorkingFolder, "Test.pdf");
string OutputFile = Path.Combine(WorkingFolder, "Test_enc.pdf");

using (Stream input = new FileStream(InputFile, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (Stream output = new FileStream(OutputFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
PdfReader reader = new PdfReader(input);
PdfEncryptor.Encrypt(reader, output, true, "1234", "1234", PdfWriter.ALLOW_SCREENREADERS);
}
}

筆者這邊就密碼設定為1234,產生一個輸入密碼才能打開的pdf檔案,名為Test_enc.pdf備用。

撰寫判斷pdf檔案是否加密

iTextSharp有一個方法可以呼叫,是IsEncrypted(),而此方法會回傳bool型別的結果,然而若會加密檔案則會得到BadPasswordException,然而基本上只要宣告PdfReader實體,基本上就會爆一樣的Exception,因此只要利用宣告PdfReader實體,得到BadPasswordException則表示有密碼保護,用這個原理判斷即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static class PdfExtension
{
public static bool IsPasswordProtected(string pdfFullname)
{
try
{
PdfReader pdfReader = new PdfReader(pdfFullname);
return false;
}
catch (BadPasswordException)
{
return true;
}
}
}

寫完Extension方法後,在Linqpad中的Main中呼叫其對應方法即可得到是否有加密的判斷結果,我們利用上個步驟的兩個檔案即可。

1
2
3
4
5
6
7
8
9
10
11
12
void Main()
{
string WorkingFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string InputFile = Path.Combine(WorkingFolder, "Test.pdf");
string OutputFile = Path.Combine(WorkingFolder, "Test_enc.pdf");

PdfExtension.IsPasswordProtected(InputFile).Dump();
PdfExtension.IsPasswordProtected(OutputFile).Dump();
}
# Linqpad結果
False
True

結論

真的是要感謝網路上的資源,但是要自己要有判斷能力,且不得不推Linqpad的偉大,透過Linqpad,能夠快速驗證腦中的想法及程式碼片段,不需要透過整個API生命週期,才能測試你的想法,非常易用,且付費版本是一次付,終生有效,非常值得購買,這篇就到這了,希望幫助到有跟我一樣需求的大家。

參考