En dag på nätet

Läsa dokument (.doc, .docx, .odt, .pdf & .rtf) med php

Jag hamnade nyss i en situation där jag behövde extrahera text från dokument. Syftet var att senare kunna låta Sphinx indexera datat. Målbilden var att klara av .odt, .docx, .doc, .pdf och .rtf. Både .odf och .docx är relativt enkla då de båda är zip-filer med xml-innehåll. Vet man bara var man hittar själva innehållet är det enkelt att med hjälp av phps xml-funktioner plocka ut rådatan. Jag fick lite hjälp av följande sida.

Äldre Word-filer i .doc-format löste jag genom att installera paketet antiword (apt-get install antiword på Ubuntu 10.04 Server). Därefter stötte jag på patrull. Tydligen måste Antiword ha en viss path-variabel satt för att inte sparka bakut. Följande löste problemet.

putenv("ANTIWORDHOME=/usr/share/antiword");
echo shell_exec("/usr/bin/antiword /katalog/filnamn.doc");

Pdf-filer löste jag genom pdftotext som är en del av paketet xpdf. pdftotext vill ha två argument varav det andra är den fil man vill skriva till. Ett bindestreck gör att resultatet skickas till stdout.

echo shell_exec("/usr/bin/pdftotext /katalog/filnamn.pdf -");

Det som jag trodde skulle vara enklast men som visade sig lite lurigt var rtf-filer. Jag trodde att jag skulle kunna göra på samma sätt som ovan efter att ha hittat GNU-projektet UnRTF. Vad jag gissar var felet, för jag vet inte säkert, är att unrtf av någon anledning skriver till stderr även vid “framgång”. Detta resulterade i ett elakt 500 internal server error på min Cherokee-server. När jag nästan hade gett upp så hittade jag proc_open i php-manualen. Rent intuitivt kändes det som det kunde vara något att prova. Utan att kunna förklara varför så fungerade nedan utan problem.

$desc = array(
  0 => array("pipe", "r"),

  1 => array("pipe", "w"),
  2 => array("pipe", "w")
);

$proc = proc_open("/usr/bin/unrtf --html /katalog/filnamn.rtf", $desc, $pipes);

echo stream_get_contents($pipes[1]);
$return_value = proc_close($proc);

Att proc_close skulle associeras till en variabel var något som jag också hittade i php-manualen utan att riktigt förstå varför. Eftersom UnRTF enligt egen utsago skulle vara bäst på att skapa html av det extraherade resultatet lät jag den göra det och körde sedan strip_tags och html_entity_decode på resultatet.

Hoppas att detta kan vara till nytta för någon och mig själv i framtiden om jag skulle glömma av det.

Shipping is a feature. A really important feature. Your product must have it.
… if you think you’re smarter than the badblocks program, you almost certainly aren’t.

från man badblocks. Får mig att tänka på alla som tror att de kan “lura” Google.

Jag är en aktiv förespråkare av “det spelar ingen roll vilket håll vi kör åt bara vi kör åt samma håll”. I länken ovan tycker jag Seth ger uttryck för detta på ett lite annat sätt.

You need solid values that are shared within the company. I usually say the best way to work with social media in large corporations is to work with internal communication, education and monitoring.

Det här är riktigt roliga nyheter. Google slutar censurera i Kina. Som stort Google-fanboy och tillika aktieägare blir jag ännu gladare. Kommer ändå att tänka på en föreläsning jag nyss lyssnat till med Niklas Egels Zandén om CSR-arbete. Vem har sagt att våra (läs västs) krav på en bättre värld är “rätt”? Personligen så tycker jag att mänskliga rättigheter och yttrandefrihet är bra saker.

Idag anlände ett paket från Hong Kong innehållandes en Seiko SKX031. Efter att ha, innan köpet, spenderat oskäligt mycket tid på olika klockforum så förstod jag att originalarmbandet inte var mycket att hänga i granen. Det var bara att beställa ett solitt “Super Oyster” från Yobokies. Så här ser det ut.

Idag anlände ett paket från Hong Kong innehållandes en Seiko SKX031. Efter att ha, innan köpet, spenderat oskäligt mycket tid på olika klockforum så förstod jag att originalarmbandet inte var mycket att hänga i granen. Det var bara att beställa ett solitt “Super Oyster” från Yobokies. Så här ser det ut.