back to top

PHP: leggere il contenuto di file PDF, DOC e DOCX

In determinati contesti può essere utile interagire con file PDF o DOC atteraverso codice PHP. L’interazione con questi file, infatti, può essere molto meno semplice di quello che si può pensare! Sia i PDF che i file DOC (il formato di Microsoft Word), infatti, sono formati piuttosto complessi che richiedono l’intermediazione di un parser affinché possa esserne compreso, estrapolato e/o manipolato il contenuto.

In questo articolo vedremo alcune tecniche per estrarre il contenuto dai file PDF, DOC e DOCX mediante uno script PHP. Una simile attività risulta utile, ad esempio, se si ha la necessità di indicizzare una serie di file di questo tipo consentendone la ricerca attraverso un motore di ricerca interno ad un sito web.

Si pensi, ad esempio, al sito di una scuola o ad un archivio di documenti: in ambiti come questi riuscire ad "interpretare" il contenuto dei file potrebbe rivelarsi determinante al fine di offrire agli utenti idonee funzionalità di ricerca.

In situazioni come questa, quindi, potrebbe essere davvero molto interessante realizzare un spider PHP in grado di estrarre il contenuto (testuale) dai file documentali per poterli indicizzare correttamente, ad esempio archiviandone il contenuto all’interno di un database.

Si noti che in questo articolo non vedremo come realizzare il motore di ricerca di cui abbiamo fatto menzione, ma ci limiteremo ad approfondire le tecniche attraverso le quali è possibile convertire un file PDF o Word in testo mediante PHP.

Estrarre il contenuto da un file PDF

Per poter effettuare questa operazione è necessario installare nel sistema un’apposita libreria che funga, appunto, da parser. Nello specifico potremo far ricorso a XPDF Reader, un rico toolkit che include al suo interno diversi componenti tra cui pdftotext, un componente in grado di convertire un file PDF in plain text.

Una volta installato il pacchetto potremo eseguire il seguente codice PHP:

// path del file PDF
$pdfpath = '/home/documenti/miofile.pdf';

// estraggo il contenuto
$text = shell_exec('/usr/local/bin/pdftotext ' . escapeshellarg($pdfpath) . ' -');

La nostra variabile $text conterrà il testo estratto dal PDF elaborato.

Estrarre il contenuto da file DOC

Anche in questo caso è necessario scaricare un pacchetto. Si tratta di Antiword, un reader gratuito per i file generati da MS Word. Una volta installato potremo procedere similmente a quanto visto per i file PDF:

// path del file DOC
$docpath = '/home/documenti/miofile.doc';

// estraggo il contenuto
$text = shell_exec('/usr/local/bin/antiword ' . escapeshellarg($docpath));

Si noti che la libreria in questione, essendo decisamente vecchiotta, funziona unicamente coi file ".doc" e non con quelli ".docx" generati dalle versioni più recenti dell’editor di testo della suite per l’ufficio di casa Microsoft.

Estrarre il contenuto da file DOCX

Nel caso dei file con estensione ".docx" sarà necessario operare attraverso l’ausilio di un altro tool. Nello specifico sarà possibile fare ricorso a docx2text, un tool da linea di comando scritto in Perl che svolge, appunto, la conversione di un file DOCX in testo semplice.

// path del file DOCX
$docxpath = '/home/documenti/miofile.docx';

// estraggo il contenuto
$text = shell_exec('/usr/local/bin/docx2txt.pl ' . escapeshellarg($docxpath));

Convertire in testo qualsiasi file Microsoft Office

Vi segnalo, infine, una interessante classe in puro PHP attraverso la quale convertire in testo il contento di qualsiasi file generato da MS Office: doc, docx, xlsx e pptx. La classe deve, ovviamente, essere inclusa all’interno del nostro progetto.

Di seguito il contenuto della classe per la conversione di file Microsoft Office in testo:

class DocxConversion {
  private $filename;

  public function __construct($filePath) {
    $this->filename = $filePath;
  }

  private function read_doc() {
    $fileHandle = fopen($this->filename, "r");
    $line = @fread($fileHandle, filesize($this->filename));
    $lines = explode(chr(0x0D), $line);
    $outtext = "";
    foreach($lines as $thisline) {
      $pos = strpos($thisline, chr(0x00));
      if (($pos !== FALSE) || (strlen($thisline) == 0)) {} else {
        $outtext. = $thisline.
        " ";
      }
    }
    $outtext = preg_replace("/[^a-zA-Z0-9\s\,\.\-\n\r\t@\/\_\(\)]/", "", $outtext);
    return $outtext;
  }

  private function read_docx() {
    $striped_content = '';
    $content = '';
    $zip = zip_open($this->filename);
    if (!$zip || is_numeric($zip)) return false;
    while ($zip_entry = zip_read($zip)) {
      if (zip_entry_open($zip, $zip_entry) == FALSE) continue;
      if (zip_entry_name($zip_entry) != "word/document.xml") continue;
      $content. = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
      zip_entry_close($zip_entry);
    }
    zip_close($zip);
    $content = str_replace('</w:r></w:p></w:tc><w:tc>', " ", $content);
    $content = str_replace('</w:r></w:p>', "\r\n", $content);
    $striped_content = strip_tags($content);
    return $striped_content;
  }

  private function xlsx_to_text($input_file) {
    $xml_filename = "xl/sharedStrings.xml"; //content file name
    $zip_handle = new ZipArchive;
    $output_text = "";
    if (true === $zip_handle->open($input_file)) {
      if (($xml_index = $zip_handle->locateName($xml_filename)) !== false) {
        $xml_datas = $zip_handle->getFromIndex($xml_index);
        $xml_handle = DOMDocument::loadXML($xml_datas, LIBXML_NOENT | LIBXML_XINCLUDE | LIBXML_NOERROR | LIBXML_NOWARNING);
        $output_text = strip_tags($xml_handle->saveXML());
      } else {
        $output_text. = "";
      }
      $zip_handle->close();
    } else {
      $output_text. = "";
    }
    return $output_text;
  }

  private function pptx_to_text($input_file) {
    $zip_handle = new ZipArchive;
    $output_text = "";
    if (true === $zip_handle->open($input_file)) {
      $slide_number = 1; //loop through slide files
      while (($xml_index = $zip_handle->locateName("ppt/slides/slide".$slide_number.
          ".xml")) !== false) {
        $xml_datas = $zip_handle->getFromIndex($xml_index);
        $xml_handle = DOMDocument::loadXML($xml_datas, LIBXML_NOENT | LIBXML_XINCLUDE | LIBXML_NOERROR | LIBXML_NOWARNING);
        $output_text. = strip_tags($xml_handle->saveXML());
        $slide_number++;
      }
      if ($slide_number == 1) {
        $output_text. = "";
      }
      $zip_handle->close();
    } else {
      $output_text. = "";
    }
    return $output_text;
  }

  public function convertToText() {
    if (isset($this->filename) && !file_exists($this->filename)) {
      return "File Not exists";
    }
    $fileArray = pathinfo($this->filename);
    $file_ext = $fileArray['extension'];
    if ($file_ext == "doc" || $file_ext == "docx" || $file_ext == "xlsx" || $file_ext == "pptx") {
      if ($file_ext == "doc") {
        return $this->read_doc();
      }
      elseif($file_ext == "docx") {
        return $this->read_docx();
      }
      elseif($file_ext == "xlsx") {
        return $this->xlsx_to_text();
      }
      elseif($file_ext == "pptx") {
        return $this->pptx_to_text();
      }
    } else {
      return "Invalid File Type";
    }
  }
}

Una volta inclusa la classe potrà essere utilizzata in questo modo:

$docObj = new DocxConversion("/home/documenti/miofile.docx");
$text = $docObj->convertToText();

Nell’esempio abbiamo passato in argomento un file ".docx" ma nulla vieta di utilizzare la classe, come detto, con altre tipologie di file della famiglia Microsoft Office.

Pubblicitร 
Massimiliano Bossi
Massimiliano Bossi
Stregato dalla rete sin dai tempi delle BBS e dei modem a 2.400 baud, ho avuto la fortuna di poter trasformare la mia passione in un lavoro (nonostante una Laurea in Giurisprudenza). Adoro scrivere codice e mi occupo quotidianamente di comunicazione, design e nuovi media digitali. Orgogliosamente "nerd" sono il fondatore di MRW.it (per il quale ho scritto centinaia di articoli) e di una nota Web-Agency (dove seguo in prima persona progetti digitali per numerosi clienti sia in Italia che all'estero).

Leggi anche...

Cannot modify header information – headers already sent: come risolvere l’errore PHP

L'errore di PHP cannot modify header information - headers...

Ricavare l’estensione di un file con PHP

Quando si lavora con i file in un'applicazione web,...

GD Library: creazione, manipolazione e ridimensionamento immagini con PHP

Le librerie GD (o GD Library), sono componenti fondamentali...

PHP: impostare il fuso orario italiano

Le tue pagine PHP non mostrano l’orario corretto? Probabilmente...

5 script PHP per gestire BBCode

A volte può aversi l'esigenza di dover offrire agli...
Pubblicitร