0x1998 - MANAGER
Edit File: fpdf_protection.php
<?php /**************************************************************************** * Software: FPDF_Protection * * Version: 1.03 * * Date: 2009-11-29 * * Author: Klemen VODOPIVEC * * License: FPDF * * * * Thanks: Cpdf (http://www.ros.co.nz/pdf) was my working sample of how to * * implement protection in pdf. * ****************************************************************************/ require('fpdf.php'); if(function_exists('mcrypt_encrypt')) { function RC4($key, $data) { return mcrypt_encrypt(MCRYPT_ARCFOUR, $key, $data, MCRYPT_MODE_STREAM, ''); } } else { function RC4($key, $data) { static $last_key, $last_state; if($key != $last_key) { $k = str_repeat($key, 256/strlen($key)+1); $state = range(0, 255); $j = 0; for ($i=0; $i<256; $i++){ $t = $state[$i]; $j = ($j + $t + ord($k[$i])) % 256; $state[$i] = $state[$j]; $state[$j] = $t; } $last_key = $key; $last_state = $state; } else $state = $last_state; $len = strlen($data); $a = 0; $b = 0; $out = ''; for ($i=0; $i<$len; $i++){ $a = ($a+1) % 256; $t = $state[$a]; $b = ($b+$t) % 256; $state[$a] = $state[$b]; $state[$b] = $t; $k = $state[($state[$a]+$state[$b]) % 256]; $out .= chr(ord($data[$i]) ^ $k); } return $out; } } class FPDF_Protection extends FPDF { var $encrypted = false; //whether document is protected var $Uvalue; //U entry in pdf document var $Ovalue; //O entry in pdf document var $Pvalue; //P entry in pdf document var $enc_obj_id; //encryption object id /** * Function to set permissions as well as user and owner passwords * * - permissions is an array with values taken from the following list: * copy, print, modify, annot-forms * If a value is present it means that the permission is granted * - If a user password is set, user will be prompted before document is opened * - If an owner password is set, document can be opened in privilege mode with no * restriction if that password is entered */ function SetProtection($permissions=array(), $user_pass='', $owner_pass=null) { $options = array('print' => 4, 'modify' => 8, 'copy' => 16, 'annot-forms' => 32 ); $protection = 192; foreach($permissions as $permission) { if (!isset($options[$permission])) $this->Error('Incorrect permission: '.$permission); $protection += $options[$permission]; } if ($owner_pass === null) $owner_pass = uniqid(rand()); $this->encrypted = true; $this->padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08". "\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A"; $this->_generateencryptionkey($user_pass, $owner_pass, $protection); } /**************************************************************************** * * * Private methods * * * ****************************************************************************/ function _putstream($s) { if ($this->encrypted) { $s = RC4($this->_objectkey($this->n), $s); } parent::_putstream($s); } function _textstring($s) { if ($this->encrypted) { $s = RC4($this->_objectkey($this->n), $s); } return parent::_textstring($s); } /** * Compute key depending on object number where the encrypted data is stored */ function _objectkey($n) { return substr($this->_md5_16($this->encryption_key.pack('VXxx',$n)),0,10); } function _putresources() { parent::_putresources(); if ($this->encrypted) { $this->_newobj(); $this->enc_obj_id = $this->n; $this->_out('<<'); $this->_putencryption(); $this->_out('>>'); $this->_out('endobj'); } } function _putencryption() { $this->_out('/Filter /Standard'); $this->_out('/V 1'); $this->_out('/R 2'); $this->_out('/O ('.$this->_escape($this->Ovalue).')'); $this->_out('/U ('.$this->_escape($this->Uvalue).')'); $this->_out('/P '.$this->Pvalue); } function _puttrailer() { parent::_puttrailer(); if ($this->encrypted) { $this->_out('/Encrypt '.$this->enc_obj_id.' 0 R'); $this->_out('/ID [()()]'); } } /** * Get MD5 as binary string */ function _md5_16($string) { return pack('H*',md5($string)); } /** * Compute O value */ function _Ovalue($user_pass, $owner_pass) { $tmp = $this->_md5_16($owner_pass); $owner_RC4_key = substr($tmp,0,5); return RC4($owner_RC4_key, $user_pass); } /** * Compute U value */ function _Uvalue() { return RC4($this->encryption_key, $this->padding); } /** * Compute encryption key */ function _generateencryptionkey($user_pass, $owner_pass, $protection) { // Pad passwords $user_pass = substr($user_pass.$this->padding,0,32); $owner_pass = substr($owner_pass.$this->padding,0,32); // Compute O value $this->Ovalue = $this->_Ovalue($user_pass,$owner_pass); // Compute encyption key $tmp = $this->_md5_16($user_pass.$this->Ovalue.chr($protection)."\xFF\xFF\xFF"); $this->encryption_key = substr($tmp,0,5); // Compute U value $this->Uvalue = $this->_Uvalue(); // Compute P value $this->Pvalue = -(($protection^255)+1); } function RotatedText($x,$y,$txt,$angle) { //Rotation du texte autour de son origine $this->Rotate($angle,$x,$y); $this->Text($x,$y,$txt); $this->Rotate(0); } function Rotate($angle,$x=-1,$y=-1) { if($x==-1) $x=$this->x; if($y==-1) $y=$this->y; if(isset($this->angle) && $this->angle!=0) $this->_out('Q'); $this->angle=$angle; if($angle!=0) { $angle*=M_PI/180; $c=cos($angle); $s=sin($angle); $cx=$x*$this->k; $cy=($this->h-$y)*$this->k; $this->_out(sprintf('q %.5F %.5F %.5F %.5F %.2F %.2F cm 1 0 0 1 %.2F %.2F cm',$c,$s,-$s,$c,$cx,$cy,-$cx,-$cy)); } } function EAN13($x,$y,$barcode,$h=16,$w=.35) { $this->Barcode($x,$y,$barcode,$h,$w,13); } function UPC_A($x,$y,$barcode,$h=16,$w=.35) { $this->Barcode($x,$y,$barcode,$h,$w,12); } function GetCheckDigit($barcode) { //Compute the check digit $sum=0; for($i=1;$i<=11;$i+=2) $sum+=3*$barcode{$i}; for($i=0;$i<=10;$i+=2) $sum+=$barcode{$i}; $r=$sum%10; if($r>0) $r=10-$r; return $r; } function TestCheckDigit($barcode) { //Test validity of check digit $sum=0; for($i=1;$i<=11;$i+=2) $sum+=3*$barcode{$i}; for($i=0;$i<=10;$i+=2) $sum+=$barcode{$i}; return ($sum+$barcode{12})%10==0; } function Barcode($x,$y,$barcode,$h,$w,$len) { //Padding $barcode=str_pad($barcode,$len-1,'0',STR_PAD_LEFT); if($len==12) $barcode='0'.$barcode; //Add or control the check digit if(strlen($barcode)==12) $barcode.=$this->GetCheckDigit($barcode); elseif(!$this->TestCheckDigit($barcode)) $this->Error('Incorrect check digit'); //Convert digits to bars $codes=array( 'A'=>array( '0'=>'0001101','1'=>'0011001','2'=>'0010011','3'=>'0111101','4'=>'0100011', '5'=>'0110001','6'=>'0101111','7'=>'0111011','8'=>'0110111','9'=>'0001011'), 'B'=>array( '0'=>'0100111','1'=>'0110011','2'=>'0011011','3'=>'0100001','4'=>'0011101', '5'=>'0111001','6'=>'0000101','7'=>'0010001','8'=>'0001001','9'=>'0010111'), 'C'=>array( '0'=>'1110010','1'=>'1100110','2'=>'1101100','3'=>'1000010','4'=>'1011100', '5'=>'1001110','6'=>'1010000','7'=>'1000100','8'=>'1001000','9'=>'1110100') ); $parities=array( '0'=>array('A','A','A','A','A','A'), '1'=>array('A','A','B','A','B','B'), '2'=>array('A','A','B','B','A','B'), '3'=>array('A','A','B','B','B','A'), '4'=>array('A','B','A','A','B','B'), '5'=>array('A','B','B','A','A','B'), '6'=>array('A','B','B','B','A','A'), '7'=>array('A','B','A','B','A','B'), '8'=>array('A','B','A','B','B','A'), '9'=>array('A','B','B','A','B','A') ); $code='101'; $p=$parities[$barcode{0}]; for($i=1;$i<=6;$i++) $code.=$codes[$p[$i-1]][$barcode{$i}]; $code.='01010'; for($i=7;$i<=12;$i++) $code.=$codes['C'][$barcode{$i}]; $code.='101'; //Draw bars for($i=0;$i<strlen($code);$i++) { if($code{$i}=='1') $this->Rect($x+$i*$w,$y,$w,$h,'F'); } } } ?>