Convertendo documentos (ODT, DOC to PDF) no PHP com Unoconv / LibreOffice

O problema

Converter arquivos .doc, .odt, .docx para .pdf, ou entre si (.docx para .odt, por exemplo) com o PHP.

A solução

Para solucionar o problema instalaremos o Unoconv, ferramentas de linha de comando do LibreOffice e construiremos uma classe em PHP.

! Este é um artigo antigo (2013). É possível que o conteúdo esteja desatualizado.

Instalando o unoconv

Unoconv é uma ferramenta em Python que utiliza as bibliotecas do LibreOffice (pyuno).

Instalando LibreOffice linha de comando

No servidor, não é necessário instalar todo o LibreOffice, apenas a linha de comando e conversores que estão no core.

Para Ubuntu/Debian:

apt-get install openjdk-6-jdk libreoffice-core libreoffice-common libreoffice-writer python-uno

! Importante

Ao instalar o libreoffice-writer tem-se suporte à conversão de documentos de TEXTO. Para converter outros formatos (planilhas, apresentações, imagens, etc), instale o pacote correspondente ao aplicativo do LibreOffice.

Para imagens, considere ferramentas mais leves e sedimentadas como ImageMagick;

Para converter PDF para Texto, considere o PDF to Text, encontrado no pacote Poppler-Utils

Instalando o Unoconv

Como root

cd /tmp
git clone https://github.com/dagwieers/unoconv
cd unoconv/
make install
cd ../
rm -rf unoconv/
unoconv --listener &

Isto inicia o LibreOffice/OpenOffice como um serviço rodando sobre uma porta local, conforme checamos com um ps aux | grep soffice.

Observações:

  • Para operações em massa este modo é mais interessante pois reaproveita a instância aberta do LibreOffice/OpenOffice.

  • O unoconv existe no repositório Debian, mas numa versão antiga. É um script em python que aproveita a biblioteca pyuno disponibilizada pela LibreOffice/OpenOffice

Para ver os formatos suportados

unoconv --show

Criando um Deamon

Para deamonizer o unoconv (mais prático no servidor), crie o arquivo /etc/init.d/unoconvd com o conteúdo abaixo:

( Fonte )

#!/bin/sh
### BEGIN INIT INFO
# Provides: unoconvd
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 2 3 5
# Default-Stop:
# Description: unoconvd - Converting documents to PDF by unoconv
### END INIT INFO
case "$1" in
    start)
        /usr/bin/unoconv --listener &
        ;;
    stop)
        killall soffice.bin
        ;;
    restart)
        killall soffice.bin
        sleep 1
        /usr/bin/unoconv --listener &
        ;;
esac

Ajuste permissões, coloque para carregamento no boot e rode o daemon:

chmod 755 /etc/init.d/unoconvd
update-rc.d  unoconvd defaults
service unoconvd start

Uso básico

Iniciando manualmente ou com o daemon é possível utilizar como segue:

unoconv --format pdf --output /OUTPUT_DIR/ file.odt

Isto irá converter o arquivo file.odt para file.pdf no diretório de saída informado.

Classe PHP

Um wrapper simples em PHP pode ser escrito como abaixo:

<?php

namespace Unoconv;

/**
 * Unoconv class wrapper
 *
 * @author Rafael Goulart <rafaelgou@gmail.com>
 * @see http://tech.rgou.net/
 */
class Unoconv {

    /**
     * Basic converter method
     *
     * @param string $originFilePath Origin File Path
     * @param string $toFormat       Format to export To
     * @param string $outputDirPath  Output directory path
     */
    public static function convert($originFilePath, $outputDirPath, $toFormat)
    {
        $command = 'unoconv --format %s --output %s %s';
        $command = sprintf($command, $toFormat, $outputDirPath, $originFilePath);
        system($command, $output);

        return $output;
    }

    /**
     * Convert to PDF
     *
     * @param string $originFilePath Origin File Path
     * @param string $outputDirPath  Output directory path
     */
    public static function convertToPdf($originFilePath, $outputDirPath)
    {
        return self::convert($originFilePath, $outputDirPath, 'pdf');
    }

    /**
     * Convert to TXT
     *
     * @param string $originFilePath Origin File Path
     * @param string $outputDirPath  Output directory path
     */
    public static function convertToTxt($originFilePath, $outputDirPath)
    {
        return self::convert($originFilePath, $outputDirPath, 'txt');
    }

}

Exemplo de uso:

<?php
/**
 * Sample use of Unoconv class
 *
 */
require 'Unoconv.php';

use Unoconv\Unoconv;

// Converting to PDF
$originFilePath = 'test.odt';
$outputDirPath  = './';
Unoconv::convertToPdf($originFilePath, $outputDirPath);

// Converting to DOCX
$originFilePath = 'test.odt';
$outputDirPath  = './';
Unoconv::convert($originFilePath, $outputDirPath, 'docx');