I am trying to merge few PDF files with Setasign FPDI. This packages is working fine for some PDF format but failing for others.
There are three different formats of PDF i could find.
Format 1:
%PDF-1.4
%´µ¶·
%
1 0 obj
<<
/Type /Catalog
/PageMode /UseNone
/ViewerPreferences 2 0 R
/Pages 3 0 R
/PageLayout /OneColumn
>>
Format 2:
--uuid:3c4caf6a-2a7e-4ca5-9e0a-63346610deae
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-ID: <1>
%PDF-1.4
%âãÏÓ
1 0 obj
<</ColorSpace/DeviceGray/Subtype/Image
Format 3:
2550 4446 2d31 2e34 0a25 aaab acad 0a34
2030 206f 626a 0a3c 3c0a 2f43 7265 6174
6f72 2028 4170 6163 6865 2046 4f50 2056
6572 7369 6f6e 2031 2e30 290a 2f50 726f
6475 6365 7220 2841 7061 6368 6520 464f
5020 5665 7273 696f 6e20 312e 3029 0a2f
4372 6561 7469 6f6e 4461 7465 2028 443a
3230 3136 3131 3130 3135 3437 3532 5a29
0a3e 3e0a 656e 646f 626a 0a35 2030 206f
FPDI works great with Format 1 but it is failing for format 2.
When i tried to merge two files from Format 2 from Another PDF Merging Website, i got combined pdf in Format 3.
My question is how can merge 2 Format 2 files in to any format in PHP.
And if anyone can explain these formats, that would be great too.
"Format 2" is a corrupted file, because it includes invalid header data which will corrupt the byte offset positions in the PDF (FPDI will not repair such files but requires valid PDFs).
"Format 3" is only a bunch of hex values not a PDF file.
Thanks to Setasign's Answer, I have cleaned the invalid format to a valid one.
I am using simple content splitting.
public function parseRawResponse($raw, $from)
{
$positionMap = [
'PDF' => [ 'init' => "%PDF-1.4\n", 'end' => "\n%%EOF"]
];
$initPos = strpos($raw,$positionMap[$from]['init']);
$endPos = strrpos($raw, $positionMap[$from]['end']) + strlen($positionMap[$from]['end']);
$content = substr($raw, $initPos, ($endPos - $initPos));
return $content;
}
Where $raw is format 2 and $content is actual content for PDF.
Related
I am signing PDF files server side with PHP and I want Adobe Reader to display this banner on my resulting PDF saying that the file has been successfuly signed :
I am using code from the TCPDF library to achieve this (I had to modify some code to fit my needs).
I based my work on these two documents from Adobe official documentation : doc1 and doc2.
What I do :
Add the signature tags to the PDF file :
// The ID of the last object of the PDF + 1
$sigobjid = preg_match_all("/([0-9]+) 0 obj/", $pdfdoc, $output_array);
$sigobjid = end($output_array[1]) + 1;
// Write the signature tags where needed
$index_to_write = strrpos($pdfdoc,"endobj") + 6;
$signature_tag = PHP_EOL . $sigobjid . ' 0 obj '. PHP_EOL . '<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached '. TCPDF_STATIC::$byterange_string . ' /Contents<'.str_repeat('0', $tcpdf->get_signature_max_length()).'> >>' . PHP_EOL . 'endobj';
$pdfdoc = substr_replace($pdfdoc, $signature_tag, $index_to_write, 0);
Compute and replace the ByteRange
Compute the hash of the file like this :
$hash_result = hash('sha256', $pdfdoc);
Sign the resulting hash client side with forge.js : I use a PFX file that I parse and then create a PKCS7 using the data contained in the PFX.
Send the hash to server.
Add the signature to the PDF in the Content tag.
EDIT : Thanks to #mkl comment I also tried to reference my Sig object with the AcroForm with the following lines into my PDF file :
11 0 obj
<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /ByteRange[0 2846 14590 507] /Contents< ...
endobj
12 0 obj
<</AcroForm 11 0 R >>
endobj
It is not working either. How should I fill the AcroForm field ?
The resulting PDF is readable by Adobe Reader but the blue banner does not appear, why ?
Okay I solved it myself so for these who were wondering, you need those fields :
1 0 obj
<<
/Type /Catalog /AcroForm << /Fields [12 0 R 13 0 R] /NeedAppearances false /SigFlags 3 /DR << /Font << /F1 14 0 R >> >> /DA (/F1 0 Tf 0 g) /Q 0 >> /Perms << /DocMDP 11 0 R >>
>>
endobj
4 0 obj
<<
/Type /Page
...
endobj
11 0 obj
<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /ByteRange[0 3153 14897 922] /Contents<...> /Reference [ << /Type /SigRef /DigestMethod /SHA256 /TransformMethod /DocMDP /TransformParams << /Type /TransformParams /P 2 /V /1.2 >> >> ] >>
endobj
12 0 obj
<< /Type /Annot /Subtype /Widget /Rect [510.236220 572.598661 552.755906 615.118346] /P 4 0 R /F 4 /FT /Sig /T (Signer Name) /Ff 0 >>
endobj
13 0 obj
<< /Type /Annot /Subtype /Widget /Rect [510.236220 572.598661 552.755906 615.118346] /P 4 0 R /F 4 /FT /Sig /T (Signer Name) /Ff 0 /V 11 0 R >>
endobj
14 0 obj
<</Type /Font /Subtype /Type1 /BaseFont /Helvetica /Name /F1 /Encoding /WinAnsiEncoding >>
endobj
You basically need :
1 Font object (obj 14 in this example)
1 Sig object (obj 11) containing the signature in the 'contents' field
1 Page object (obj 4)
2 Annot object (obj 12 and 13) referencing the first page object with the P flag and the Sig object with the V flag
1 AcroForm field inside your main Catalog (obj 1) referencing your 2 Annot object in the Fields array, referencing your font in the F1 field, and your signature in the DocMDP field.
EDIT : The DocMDP field is not mendatory and only one Annot is needed. No Font required either.
I am Trying to Generate PDF output into string but it generates garbage output.
<?php
//here some code will come
require('fpdf.php');
$pdf =new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial','B',16);
$pdf->Cell(40,10,'Hello World!');
$pdf->Output('file.pdf','D');
?>
FPDF works fine when i use simply example code but when i use same code into my project it returns garbage values like
%PDF-1.3 3 0 obj <> endobj 4 0 obj <> stream x�3R��2�35W(�r Q�w3T04�30PISp �Z*�[����(hx����+���(j*�d��7W endstream endobj 1 0 obj <> endobj 5 0 obj <> stream x�]R�n�0��>��L�%�DI�8���~�%E*r�ﻻvҪHX�gvVk?/���Ῑ��`]�[�x5 �3\z��P�}����PO���j�Jݍ^���x6/f�����������|���4}�z�����}���#�,ۖ-��˺E�u�^�,���<� �Z_�K� IQ����Yd����C�K�_�%q�8>�!J"V!2&bGģ%r"H��D��\}2EL1n��h�j���e��"a*H����:��d��9c���[�X1~��"�3�g��Ñ�;O��> endobj 2 0 obj << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] /Font << /F1 6 0 R >> /XObject << >> >> endobj 7 0 obj << /Producer (FPDF 1.81) /CreationDate (D:20170323090213) >> endobj 8 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 9 0000000000 65535 f 0000000228 00000 n 0000000867 00000 n 0000000009 00000 n 0000000087 00000 n 0000000315 00000 n 0000000749 00000 n 0000000971 00000 n 0000001047 00000 n trailer << /Size 9 /Root 8 0 R /Info 7 0 R >> startxref 1096 %%EOF
please check your character set encoding if they are supporting or not. rather follow this link to read more about fpdf offcial page.
FAQ
Don't use UTF-8 with the standard fonts; they expect text encoded in ISO-8859-1 or windows-1252. You can use utf8_decode() to perform a conversion to ISO-8859-1:
$str = utf8_decode($str);
But some characters such as Euro won't be translated correctly. If the iconv extension is available, the right way to do it is the following:
$str = iconv('UTF-8', 'windows-1252', $str);
You must convert used fonts here. After that move converted files to the /fonts directory.
I have a PHP array, which contains bytes, and the actual bytes represent a ZIP file (which contains multiple files inside the ZIP).
This is returned from a third party API, so I have no choice but to work with this format.
So I'm trying to convert this into the ZIP file.
Example of byte array returned by API:
[bytes] => Array
(
[0] => 37
[1] => 80
[2] => 68
[3] => 70
[4] => 45
[5] => 49
[6] => -46
... continues to close to 20,000
)
I have tried simply getting the browser to return it by creating a complete byte string, and adapting browser headers... using:
foreach($bytes as $byte)
{
$byteString .= $byte;
}
header("Content-type: application/zip");
header("Content-Disposition: inline; filename='test.zip'");
echo $byteString;
This does create a zip file, but it's invalid / corrupted.
I have also tried this which I found elsewhere on Stackoverflow:
$fp = fopen('/myfile.zip', 'wb+');
while(!empty($bytes)) {
$byte1 = array_shift($bytes);
$byte2 = array_shift($bytes);
if(!$byte2) {
$byte2 = 0;
}
fwrite($fp, pack("n*", ($byte1 << 8) + $byte2));
}
close($fp);
But again, the ZIP is created, but it's invalid / corrupted.
Any pointers, most appreciated.
Thanks
With the help of an ascii table it's easy to decode the data you're receiving, and you will see that it starts with
%PDF
which means that the returned data is in PDF format, not zip. Zip files start with PK, the initials of the inventor of the format, the late Phil Katz.
As a general note, knowing about the common file type signatures is quite useful and can save you lots of time.
I'm trying to parse PDF files into plain text (strings) with pure PHP, because I've no access to exec or system or other function denied by the server I'm working on.
Those PDF files can't be parsed by the functions I found online.
This is what I get from an echo file_get_contents("file.pdf");
%PDF-1.4 5 0 obj << /Type /XObject /Subtype /Image /Filter /DCTDecode /Length 6536 /Width 200 /Height 125 /BitsPerComponent 8 /ColorSpace /DeviceRGB >> stream ÿØÿàJFIFÿÛC %# , #&')*)-0-(0%()(ÿÛC ((((
and then all the content.
So this is a PDF 1.4 5 0.
Here you are the function I was using for PDF 1.2-1.3 (not working with those files):
function decomprimiPDF($pdfdata) {
if (strlen ($pdfdata) < 1000 && file_exists ($pdfdata))
$pdfdata = file_get_contents ($pdfdata);
$result = '';
if (preg_match_all ('/<<[^>]*FlateDecode[^>]*>>\s*stream(.+)endstream/Uis', $pdfdata, $m))
foreach ($m[1] as $chunk) {
$chunk = gzuncompress(ltrim ($chunk));
$a = preg_match_all ('/\[([^\]]+)\]/', $chunk, $m2) ? $m2[1] : array ($chunk);
foreach ($a as $subchunk) {
if (preg_match_all ('/\(([^\)]+)\)/', $subchunk, $m3)) {
$result .= (join ('', $m3[1]) . '*');
}
}
}
Anyone here can help me with a function in PHP (I repeat it, I tried almost any function already online, and also a few classes, but they don't work with the PDF files I'm talking about).
Thanks for your support ;)
I am uploading file(pdf for now) like this: (It is uploading content of file in blob field of mysql)
$organizationModel = new Model_Organization_Object( organizationId );
$myFile = file_get_contents( '../path/to/my/file/filename.ext' );
$organizationModel->setOrganizationProfile( $myFile );
$organizationModel->save();
Now I want to get that file from database and want to download. I doing this in controller's action: (I am aspecting pdf file here therefore it is hardcoded below. But in future I want to download any file from blob field)
$organizationModel = new Model_Organization_Object( $organizationId );
$content = $organizationModel->getOrganizationProfile();
header('Content-Type: application/octet-stream');
header("Content-Length: " . strlen($content) );
header('Content-Disposition: attachment; filename=orgProfile.pdf');
$this->view->organizationProfile = $content;
Now in view file I am doing this:
echo $this->organizationProfile;
But above download process print(echo) the content of file in firbug and does not download file in orignal format. My echo output in firebug is like this:
%PDF-1.3
%����
84 0 obj
<<
/Linearized 1
/O 86
/H [ 541 212 ]
/L 958398
/E 11238
/N 27
/T 956600
>>
endobj
xref
84 7
0000000016 00000 n
0000000486 00000 n
0000000753 00000 n
0000000982 00000 n
0000001102 00000 n
0000000541 00000 n
0000000732 00000 n
trailer
<<
/Size 91
/Info 83 0 R
/Root 85 0 R
/Prev 956590
/ID[<0a8d7035bf08791da591e8cae39b8c49><0a8d7035bf08791da591e8cae39b8c49>]
>>
startxref
0
%%EOF
85 0 obj
<<
/Type /Catalog
/Pages 82 0 R
>>
endobj
89 0 obj
<< /S 151 /Filter /FlateDecode /Length 90 0 R >>
stream
H�b```f``�e`b`�f`#\0�.����\\I~aV$�Xƈ�dǪ����bA�Az�lv1o#�{-����1+�ʪG�����N`�b�
>�-��
\0\0D40
endstream
endobj
90 0 obj
106
endobj
86 0 obj
<<
/Type /Page
/Contents 87 0 R
/Parent 79 0 R
/Resources << /XObject << /img0 88 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >>
/MediaBox [ 0 0 612 792 ]
/CropBox [ 0 0 612 792 ]
/Rotate 0
>>
endobj�#.\0���
endstream
endobj
88 0 obj
<< /Filter /FlateDecode \0\0\0\0\0\0\0\0\0\\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\
\0\0\0\0\0\0\0\0\0\0\\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\
\0\0\0\0\0\0\0\0|n�FT*,�
��
�j#Q��uT~r:}\\�_؛�ҵ��v��ϭ8Q�&� ���T�S�I\"�(>Y�ܾ����}H��aj�3��u�h�T�X�Z�-~��c\'P�^��d�ם�ߔ?����]_�ڿ�z��O]�q�����7寋�|�mN%�����̖T�����o�ߓ�sUzT���m�v8ͯq�
��e]�wS���C~Ta���.��[%!������2x]n~�7�Ϫ����6.����K��;c
}����r�)V��
u���*�7�$c\\���m�~���r��)U{�λ�廳˺��ԟ�R��
��D1L_����WUog�>��/������ߦ��~�%���M���}\'�� ;���y��K`�����O�,�߫����<�,0���;3 #��m�v���aZ=�N�u�J`��dwnm;��.Ѣ�k�n�K1-M�7����H&��ʨ���s�C?��
�}Z�1����c�(0�q�_1��7�%���G7U/��h9I������S�Q��4nc�Lq��H6��;�꺒c(/O��2�٫�-�*_����%�I؏/?�I�o����ô�k��<����q��\'��]v�\"��+�˗ݯ�,��ɏ�qxgk�\\\\�6���7��Y���.G��ҽY��8��.��*���M_��J�hu1����z��W�o_��F�/���s�:�Y~��>0�g\\E�l�K5e���&L�/����k$����{ں:\\>�̥Fs?-��l�>c�亪o���Λ�9�V+�2;��}q�4
�zS�|u�A`dK���n~�sΛ��K�hiY�j��#p���S�M\\���0P2䗶\\*�m+?L5Er����[W�>9|�̑�iY�u�j�M�_���n&��7O�f��s��z`.`�,W��#�l��n���s�՛\'�����=��&#�z�M7_����s���x��y�
��u�p�G���0ͨe�G���۸8]{�䓷N�1}��}~Q�[)�XF��_��*? p7iQ����M�(�l�����������f��6����*��Ų;#~\\k�i��w_��*�#�Ւ�^�j�\\�L��/�}�Y�[��V��t~�w�n��a���m�O�(.�n;��ji:��W�ZnQ[9�n=�^��sE9��;�.��u3\"ږ��<�Ļ��y8�<H���g��u��\\�q��Ȥ71p�U��}ם��f`�Y��m3b*C�t{�SX��7m<��6��8K��[Qs��&_��(M��:�Z���W��Հ��W寚
��4d��4�Aڔ�ɪ�lw�e�d�>�
�pCV��h�ŜS�Z�T��4�NӴ,�� �8=-�%ߜ��4�p�a��~��R눥L芈�=J��j}��ʺ��,�(�x����
�]��l�)L��� I8eG#r�dC��;�/C���l���rm�ɽ��͆��e�6�M��fP�4�r��)�!�\\sڹ�?{��!cN��h�֗>�� ��o>��m�dO=&<ɻ�P��xΔ=�͌CC?�M��W[ϟ�v<���S14�����\\C�Z
��g��ݡq:�ǔ�C�k�vc�K�;��\"Y͙t�r]��G�z����w���rӹ����ަ0������e�:��/f�*^�W�Q8WsN��9}*ۥ|��~x)�N�=6J�l����M�b��Ƿ���M45�C�k]��r�uߍ�����r
]
reponse headers in firebug:
Date Thu, 15 Apr 2010 06:21:03 GMT
Server Apache/2.2.11 (Ubuntu) PHP/5.2.6-3ubuntu4.2 with Suhosin-Patch
X-Powered-By PHP/5.2.6-3ubuntu4.2
Expires Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma no-cache
Content-Length 65535
Content-Disposition attachment; filename=evidence.pdf
Keep-Alive timeout=15, max=71
Connection Keep-Alive
Content-Type application/octet-stream
Can someone help that how to download file or I am doing something wrong with uploading process. setOrganizationProfile() and getOrganizationProfile() function are created by our team which are working fine while storing/getting data to/from database.
Thanks
Ok, I think your problem is that you're using AJAX to download file.
It's not possible to download file using AJAX (or rather - JS) in a normal way. You know, there's too big hole for exploits to allow that (I think so) - anyway there's no such possibility.
There are workarounds though. One of them is creating hidden iframe dynamically on the page and then changing its location to your download script. Then you're not using JS to download, but plain browser capabilities.
Another way is described on this page:
http://www.filamentgroup.com/lab/jquery_plugin_for_requesting_ajax_like_file_downloads/
Mybe it'll be a help for you.
You want the Content-type to be application/pdf not application/octet-stream. That will render the pdf file rather than display the 'source' of it.
Cheers