[PHP] uncompress pdf file uit MSSQL db

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • w00d
  • Registratie: Juni 2004
  • Laatst online: 07:34
Wij zijn bezig met het koppelen van onze CRM database aan onze internet site, hierbij willen we derde de mogelijkheid bieden om documenten (pdf) te downloaden.

Nu worden de documenten gecomprimeerd opgeslagen in de database, hoe ze het comprimeren weet ik niet. Aangezien ik ook niet het datamodel ken van de database hebben we de software leverancier de opdracht gegeven om ons een stuk code te geven waarmee we de documenten eruit kunnen halen. Zij hebben mij dus een stuk php code gegeven waarin de nodige query's zitten en ook een stukje code om de documenten te openen.

Het openen werkt echter niet, het gaat mis op de decompressie van de data. Nu ligt het natuurlijk voor de hand om met het probleem terug te gaan naar de leverancier, iets wat ik ook al gedaan heb. Echter merk ik uit de reactie die ik krijg dat zij geen expert zijn op php gebied en de code ook maar simpel weg van php.net halen.

Aangezien ik niet ga zitten wachten tot hun met een oplossing komen ben ik zelf ook aan het uitzoeken waar het probleem nu zit, echter kom ik er ook niet uit...

De volgende code werd door hun aangeleverd om documenten te openen (relevant deel ervan uiteraard)
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
header('Pragma: private');
header('Cache-control: private, must-revalidate');
header("Content-Transfer-Encoding: binary");
header('Content-type: application/pdf;');
echo $data;
exit;

function uncompressdata($data)
{
    $sZMno0 = '49';
    $sZMno1 = '5a';
    $sZMno2 = '4d';
    $sZMno3 = '53';
        
    If ((bin2hex($data[0]) == $sZMno0) && (bin2hex($data[1]) == $sZMno1) && (bin2hex($data[2]) == $sZMno2) && (bin2hex($data[3]) == $sZMno3))
    {        
        $result = substr($data, 8);
        
        $uncompressed = gzuncompress($result);
        return $uncompressed;
    }
    else
    {
        return $data;
    }
}


op deze code krijg ik de volgende foutmelding wanneer adobe reader opent: bestand begint niet met %PDF-.
Als ik de gedecomprimeerde data gewoon naar de browser output krijg ik de volgende foutmelding te zien:

Warning: gzuncompress() [function.gzuncompress <http://domain/folder/function.gzuncompress> ]:
data error in .... line

Een melding waar helaas niet veel informatie over te vinden is. Enkel in de php manual staat in de comments een mogelijke oplossing, welke ook door de leverancier is aangedragen. Namelijk de volgende functie gebruiken om hem de decomprimeren:

PHP:
1
2
3
4
5
function gzuncompress_crc32($data) {
         $f = tempnam('/tmp', 'gz_fix');
         file_put_contents($f, "\x1f\x8b\x08\x00\x00\x00\x00\x00" . $data);
         return file_get_contents('compress.zlib://' . $f);
}


Ook dit heeft geen succes, krijg niet eens een foutmelding te zien.

Zlib staat wel aan bij onze webhost, versie 1.2.3 op php versie 5.2.13

Maarja hoe nu verder, op de foutmelding is niet veel informatie te vinden, de gecomprimeerde code krijg ik keurig in me browser, maarja daar wordt je ook niet echt wijzer van.

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
w00d schreef op maandag 19 april 2010 @ 11:27:
Nu worden de documenten gecomprimeerd opgeslagen in de database, hoe ze het comprimeren weet ik niet.
Dan is dat toch het punt waar je moet gaan beginnen. Als je niet weet hoe het gecomprimeerd is, ga je het ook niet kunnen decomprimeren. Dat blijkt ook uit de foutmelding die je krijgt.
Warning: gzuncompress() [function.gzuncompress <http://domain/folder/function.gzuncompress> ]:
data error in .... line
Aangezien ik ook niet het datamodel ken van de database hebben we de software leverancier de opdracht gegeven om ons een stuk code te geven waarmee we de documenten eruit kunnen halen. Zij hebben mij dus een stuk php code gegeven waarin de nodige query's zitten en ook een stukje code om de documenten te openen.
Het datamodel is blijkbaar niet het probleem, want je weet welke velden je uit moet lezen.
Het openen werkt echter niet, het gaat mis op de decompressie van de data. Nu ligt het natuurlijk voor de hand om met het probleem terug te gaan naar de leverancier, iets wat ik ook al gedaan heb. Echter merk ik uit de reactie die ik krijg dat zij geen expert zijn op php gebied en de code ook maar simpel weg van php.net halen.
Als ze geen PHP experts hebben, dan is het dus zaak dat ze specificeren hoe het systeem in elkaar zit, en dan kan je daar zelf PHP code voor schrijven.
Maarja hoe nu verder, op de foutmelding is niet veel informatie te vinden, de gecomprimeerde code krijg ik keurig in me browser, maarja daar wordt je ook niet echt wijzer van.
Uit je hele verhaal blijkt dus dat er niet goed gespecificeerd is hoe de data gecomprimeerd is. Dan kun je wel random van alles gaan proberen. Maar het probleem is toch echt dat je die specificaties nodig hebt.

PS:
Overigens vind ik de code
PHP:
1
If ((bin2hex($data[0]) == $sZMno0) && (bin2hex($data[1]) == $sZMno1) && (bin2hex($data[2]) == $sZMno2) && (bin2hex($data[3]) == $sZMno3))

Nogal vreemd. Je gaat binaire data eerst omzetten naar een string zodat je met een string kunt vergelijken? Je kunt natuurlijk ook gewoon de daadwerkelijke data vergelijken
PHP:
1
if( $data[0] == 0x49 .... )

[ Voor 9% gewijzigd door Woy op 19-04-2010 11:57 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • user109731
  • Registratie: Maart 2004
  • Niet online
Ik zou beginnen met het dumpen van de eerste 20 bytes van de gecomprimeerde data. En dan kijken waar de GZIP magic byte staat, als die uberhaupt voorkomt. Dan weet je iig zeker of echt gzip gebruikt is.

Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Heb je getest met gunzip of die het wel kan decompressen? gzinflate?

Verder: Waarom zou je uberhaupt gzuncompress doen, aangezien de meeste browsers gewoon gzip ondersteunen en je dus ook gewoon iets kan sturen als:
PHP:
1
2
3
        header('Content-Encoding: gzip');
        echo "\x1f\x8b\x08\x00\x00\x00\x00\x00";
        echo $gzdata;

Waarbij gzip soms x-gzip moet zijn (zie accept-encoding) en dit alleen werkt als de browser gzip ondersteund. :p

Doet regel 15 nu gewoon testen op substr($data,0,4)==="IZMS" ? Ik ken geen encoding die IZMS als signature heeft.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • w00d
  • Registratie: Juni 2004
  • Laatst online: 07:34
Woy schreef op maandag 19 april 2010 @ 11:54:
[...]

Dan is dat toch het punt waar je moet gaan beginnen. Als je niet weet hoe het gecomprimeerd is, ga je het ook niet kunnen decomprimeren. Dat blijkt ook uit de foutmelding die je krijgt.

Uit je hele verhaal blijkt dus dat er niet goed gespecificeerd is hoe de data gecomprimeerd is. Dan kun je wel random van alles gaan proberen. Maar het probleem is toch echt dat je die specificaties nodig hebt.
Goed punt
Het datamodel is blijkbaar niet het probleem, want je weet welke velden je uit moet lezen.


Als ze geen PHP experts hebben, dan is het dus zaak dat ze specificeren hoe het systeem in elkaar zit, en dan kan je daar zelf PHP code voor schrijven.
Daarom hebben we ook aan de leverancier gevraagd om ons de code te leveren om de documenten te openen, van hun heb ik de query's gehad en de code om documenten te openen ( laatste werkt dus niet)
PS:
Overigens vind ik de code
PHP:
1
If ((bin2hex($data[0]) == $sZMno0) && (bin2hex($data[1]) == $sZMno1) && (bin2hex($data[2]) == $sZMno2) && (bin2hex($data[3]) == $sZMno3))

Nogal vreemd. Je gaat binaire data eerst omzetten naar een string zodat je met een string kunt vergelijken? Je kunt natuurlijk ook gewoon de daadwerkelijke data vergelijken
PHP:
1
if( $data\[0] == 0x49 .... )
Ik kon het ook al niet thuis brengen, maarja ging er vanuit dat hun wel wisten wat ze aan het doen waren.

Maar ik zal de aangedragen tips is uitzoeken / proberen.

[ Voor 13% gewijzigd door w00d op 19-04-2010 12:29 ]


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
w00d schreef op maandag 19 april 2010 @ 12:28:
[...]
Daarom hebben we ook aan de leverancier gevraagd om ons de code te leveren om de documenten te openen, van hun heb ik de query's gehad en de code om documenten te openen ( laatste werkt dus niet)
Ja maar je kunt dan IMHO beter om goede documentatie vragen, dan om code. De code kun je dan op een willekeurig platform zelf maken.
Ik kon het ook al niet thuis brengen, maarja ging er vanuit dat hun wel wisten wat ze aan het doen waren.
Ik neem aan dat jullie wel gewoon PHP kennis in huis hebben? Dan moet je dit soort dingen toch gewoon kunnen plaatsen? Maar nogmaals, dit zijn implementatie kwesties, en dus in eerste instantie nog niet belangrijk. Het is belangrijk om eerst een goede definitie van het dataformaat te krijgen. Anders kun je gaan implementeren wat je wil, maar dan zal er toch niet veel nuttigs uit komen.
pedorus schreef op maandag 19 april 2010 @ 12:20:
Doet regel 15 nu gewoon testen op substr($data,0,4)==="IZMS" ? Ik ken geen encoding die IZMS als signature heeft.
Nee hij vergelijkt de string '49' met bin2hex( data[0] ), wat dus feitenlijk een controle van data[0] == 0x49 is.

[ Voor 15% gewijzigd door Woy op 19-04-2010 12:42 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Nope.. ;)
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$data="IZMSdasas";
if (substr($data,0,4)==="IZMS")
    echo "tr";

$sZMno0 = '49';
$sZMno1 = '5a';
$sZMno2 = '4d';
$sZMno3 = '53';

If ((bin2hex($data[0]) == $sZMno0) && (bin2hex($data[1]) == $sZMno1) &&
    (bin2hex($data[2]) == $sZMno2) && (bin2hex($data[3]) == $sZMno3))
    echo "ue";

if ($data[0] == 0x49)
    echo "false";

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ah ik had niet naar de daadwerkelijke codes gekeken en dat is idd 'IZMS'

Maar bin2hex( 0x49 ) levert toch gewoon '49' op of is dat een gekke aanname? Wat levert bin2hex( 'I' ) dan op?

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Woy schreef op maandag 19 april 2010 @ 13:45:
Maar bin2hex( 0x49 ) levert toch gewoon '49' op of is dat een gekke aanname? Wat levert bin2hex( 'I' ) dan op?
Nee '3733' omdat php dat als '73' ziet, en dus geldt ook "\x49"!=0x49, omdat bij zo'n vergelijking 0x49 niet naar een char gecast wordt. Dus "49"==0x49, maar "I"!=0x49 en "I"==0x0. (Jaja, PHP :p)

[ Voor 7% gewijzigd door pedorus op 19-04-2010 15:16 . Reden: php ]

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
pedorus schreef op maandag 19 april 2010 @ 14:13:
[...]

Nee '3733' omdat php dat als '49' ziet, en dus geldt ook "\x49"!=0x49, omdat bij zo'n vergelijking 0x49 niet naar een char gecast wordt. Dus "49"==0x49, maar "I"!=0x49 en "I"==0x0. (Jaja, PHP :p)
Ik ging er dan ook van uit dat $data een array van bytes was en niet een array van chars. Maar zoals je misschien al zult merken ben ik niet echt thuis in het type system van PHP ;)

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 03:28
Heeft MSSQL niet iets zoals PostgreSQL's TOAST? Dit zorgt er - automatisch en transparant voor de gebruiker - voor dat grote kolommen automatisch worden gecomprimeerd zodat je zelf daar niet moeilijk voor moet gaan doen...

Acties:
  • 0 Henk 'm!

  • w00d
  • Registratie: Juni 2004
  • Laatst online: 07:34
Zo ben weer een stukje wijzer geworden. Weet nu inmiddels hoe de data wordt gecomprimeerd, eerste 4 bytes is de magic key, en de volgende 4 bytes geeft de lengte van de uncompressed data aan.

Met gzinflate kon ik de headers van het bestand gewoon lezen, zo kon ik zien dat het inderdaad een pdf file is etc, maar toch lukte het met niet om er een echt pdf document van te maken.

Vervolgens bleef er nog maar 1 ding over, krijgen we wel de volledige string van de db? Dit heb ik vergeleken met de SQL db en inderdaad verschilde de lengte. Oorzaak is de mssql.textlimit en de mssql.textsize. Dus inmiddels contact opgenomen met de webhost welke gaat nadenken of ze dit willen aanpassen.

In ieder geval bedankt voor de tips!
Pagina: 1