PHP FPDF: Bagaimana Melindungi File PDF ?

Ada kalanya kita menginginkan suatu file PDF yang digenerate on-the-fly oleh PHP dapat terlindungi dari perubahan oleh pengguna. Di halaman lain mungkin kita menginginkan agar file PDF hanya bisa dicetak tanpa boleh diedit. Dan pada kebutuhan lainnya, kita ingin menambahkan password di file PDF sehingga pengguna yang tidak berhak (tidak mengetahui passwordnya) tidak dapat membukanya. Nah, pada tutorial kali ini akan disampaikan bagaimana melindungi file PDF yang dihasilkan menggunakan library FPDF. Sebelum memulai tutorial, bagi yang belum mengenal library FPDF, ada baiknya mempelajari tutorial saya sebelumnya mengenai bagaimana membuat file PDF dengan FPDF.

pdf-password

Untuk memproteksi file PDF yang dihasilkan dengan library FPDF, kita dapat menggunakan class Protection yang ditulis oleh Klemen Vodopivec yang berlisensi FPDF. Terdapat 3 pengaturan yang menjadi masukan dari class ini, yaitu:

  1. permissions: mengatur jenis hak akses, default-nya kosong (hanya bisa view).
  2. user_pass: password user, defaultnya kosong.
  3. owner_pass: password pemilik file PDF. Jika tidak ditentukan, maka akan digenerate password secara random.

Adapun nilai hak akses (permission) yang dapat dipilih adalah sbb:

  • copy: hak akses dapat meng-copy teks dan gambar.
  • print: hak akses pencetakan dokumen.
  • modify: hak akses mengubah dokumen (kecuali untuk anotasi dan form).
  • annot-forms: hak akses menambahkan anotasi (catatan) dan form

Berikut ini class Protection yang perlu dipanggil / disertakan saat kita mau menambahkan perlindungan terhadap file PDF.

  1. <?php
  2. /****************************************************************************
  3. * Software: FPDF_Protection *
  4. * Version: 1.03 *
  5. * Date: 2009-11-29 *
  6. * Author: Klemen VODOPIVEC *
  7. * License: FPDF *
  8. * *
  9. * Thanks: Cpdf (http://www.ros.co.nz/pdf) was my working sample of how to *
  10. * implement protection in pdf. *
  11. ****************************************************************************/
  12.  
  13. require('fpdf17/fpdf.php');
  14.  
  15. if(function_exists('mcrypt_encrypt'))
  16. {
  17. function RC4($key, $data)
  18. {
  19. return mcrypt_encrypt(MCRYPT_ARCFOUR, $key, $data, MCRYPT_MODE_STREAM, '');
  20. }
  21. }
  22. else
  23. {
  24. function RC4($key, $data)
  25. {
  26. static $last_key, $last_state;
  27.  
  28. if($key != $last_key)
  29. {
  30. $k = str_repeat($key, 256/strlen($key)+1);
  31. $state = range(0, 255);
  32. $j = 0;
  33. for ($i=0; $i<256; $i++){
  34. $t = $state[$i];
  35. $j = ($j + $t + ord($k[$i])) % 256;
  36. $state[$i] = $state[$j];
  37. $state[$j] = $t;
  38. }
  39. $last_key = $key;
  40. $last_state = $state;
  41. }
  42. else
  43. $state = $last_state;
  44.  
  45. $len = strlen($data);
  46. $a = 0;
  47. $b = 0;
  48. $out = '';
  49. for ($i=0; $i<$len; $i++){
  50. $a = ($a+1) % 256;
  51. $t = $state[$a];
  52. $b = ($b+$t) % 256;
  53. $state[$a] = $state[$b];
  54. $state[$b] = $t;
  55. $k = $state[($state[$a]+$state[$b]) % 256];
  56. $out .= chr(ord($data[$i]) ^ $k);
  57. }
  58. return $out;
  59. }
  60. }
  61.  
  62. class FPDF_Protection extends FPDF
  63. {
  64. var $encrypted = false; //whether document is protected
  65. var $Uvalue; //U entry in pdf document
  66. var $Ovalue; //O entry in pdf document
  67. var $Pvalue; //P entry in pdf document
  68. var $enc_obj_id; //encryption object id
  69.  
  70. /**
  71.   * Function to set permissions as well as user and owner passwords
  72.   *
  73.   * - permissions is an array with values taken from the following list:
  74.   * copy, print, modify, annot-forms
  75.   * If a value is present it means that the permission is granted
  76.   * - If a user password is set, user will be prompted before document is opened
  77.   * - If an owner password is set, document can be opened in privilege mode with no
  78.   * restriction if that password is entered
  79.   */
  80. function SetProtection($permissions=array(), $user_pass='', $owner_pass=null)
  81. {
  82. $options = array('print' => 4, 'modify' => 8, 'copy' => 16, 'annot-forms' => 32 );
  83. $protection = 192;
  84. foreach($permissions as $permission)
  85. {
  86. if (!isset($options[$permission]))
  87. $this->Error('Incorrect permission: '.$permission);
  88. $protection += $options[$permission];
  89. }
  90. if ($owner_pass === null)
  91. $owner_pass = uniqid(rand());
  92. $this->encrypted = true;
  93. $this->padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08".
  94. "\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A";
  95. $this->_generateencryptionkey($user_pass, $owner_pass, $protection);
  96. }
  97.  
  98. /****************************************************************************
  99. * *
  100. * Private methods *
  101. * *
  102. ****************************************************************************/
  103.  
  104. function _putstream($s)
  105. {
  106. if ($this->encrypted) {
  107. $s = RC4($this->_objectkey($this->n), $s);
  108. }
  109. parent::_putstream($s);
  110. }
  111.  
  112. function _textstring($s)
  113. {
  114. if ($this->encrypted) {
  115. $s = RC4($this->_objectkey($this->n), $s);
  116. }
  117. return parent::_textstring($s);
  118. }
  119.  
  120. /**
  121.   * Compute key depending on object number where the encrypted data is stored
  122.   */
  123. function _objectkey($n)
  124. {
  125. return substr($this->_md5_16($this->encryption_key.pack('VXxx',$n)),0,10);
  126. }
  127.  
  128. function _putresources()
  129. {
  130. parent::_putresources();
  131. if ($this->encrypted) {
  132. $this->_newobj();
  133. $this->enc_obj_id = $this->n;
  134. $this->_out('<<');
  135. $this->_putencryption();
  136. $this->_out('>>');
  137. $this->_out('endobj');
  138. }
  139. }
  140.  
  141. function _putencryption()
  142. {
  143. $this->_out('/Filter /Standard');
  144. $this->_out('/V 1');
  145. $this->_out('/R 2');
  146. $this->_out('/O ('.$this->_escape($this->Ovalue).')');
  147. $this->_out('/U ('.$this->_escape($this->Uvalue).')');
  148. $this->_out('/P '.$this->Pvalue);
  149. }
  150.  
  151. function _puttrailer()
  152. {
  153. parent::_puttrailer();
  154. if ($this->encrypted) {
  155. $this->_out('/Encrypt '.$this->enc_obj_id.' 0 R');
  156. $this->_out('/ID [()()]');
  157. }
  158. }
  159.  
  160. /**
  161.   * Get MD5 as binary string
  162.   */
  163. function _md5_16($string)
  164. {
  165. return pack('H*',md5($string));
  166. }
  167.  
  168. /**
  169.   * Compute O value
  170.   */
  171. function _Ovalue($user_pass, $owner_pass)
  172. {
  173. $tmp = $this->_md5_16($owner_pass);
  174. $owner_RC4_key = substr($tmp,0,5);
  175. return RC4($owner_RC4_key, $user_pass);
  176. }
  177.  
  178. /**
  179.   * Compute U value
  180.   */
  181. function _Uvalue()
  182. {
  183. return RC4($this->encryption_key, $this->padding);
  184. }
  185.  
  186. /**
  187.   * Compute encryption key
  188.   */
  189. function _generateencryptionkey($user_pass, $owner_pass, $protection)
  190. {
  191. // Pad passwords
  192. $user_pass = substr($user_pass.$this->padding,0,32);
  193. $owner_pass = substr($owner_pass.$this->padding,0,32);
  194. // Compute O value
  195. $this->Ovalue = $this->_Ovalue($user_pass,$owner_pass);
  196. // Compute encyption key
  197. $tmp = $this->_md5_16($user_pass.$this->Ovalue.chr($protection)."\xFF\xFF\xFF");
  198. $this->encryption_key = substr($tmp,0,5);
  199. // Compute U value
  200. $this->Uvalue = $this->_Uvalue();
  201. // Compute P value
  202. $this->Pvalue = -(($protection^255)+1);
  203. }
  204. }
  205.  
  206. ?>

Berikut ini beberapa contoh penggunaan class Protection di atas.

Contoh 1: Melindungi File PDF dari meng-copy isi, namun diijinkan mencetak dokumen.

  1. <?php
  2. require('fpdf_protection.php');
  3.  
  4. $pdf=new FPDF_Protection();
  5. $pdf->SetProtection(array('print'));
  6. $pdf->AddPage();
  7. $pdf->SetFont('Arial');
  8. $pdf->Write(10,'You can print me but not copy my text.');
  9. $pdf->Output('contoh1.pdf','D');
  10. ?>

Contoh 2: Melindungi File PDF dengan menambahkan Password untuk membukanya.

  1. <?php
  2. require('fpdf_protection.php');
  3.  
  4. $pdf=new FPDF_Protection();
  5. $pdf->SetProtection(array('print'), 'qwerty');
  6. $pdf->AddPage();
  7. $pdf->SetFont('Arial');
  8. $pdf->Write(10,'Anda berhasil membuka dokumen rahasia ini.');
  9. $pdf->Output('contoh2.pdf','D');
  10. ?>

Demikian beberapa contoh melindungi file PDF. Semoga bermanfaat.

Demo dan Download

Berbagi itu indah...Share on Facebook0Share on Google+0Tweet about this on TwitterShare on LinkedIn0Pin on Pinterest0Digg this

Leave a Reply

Your email address will not be published. Required fields are marked *