0

Relatórios PDF com PHP (CodeIgniter), Jasper Reports e Oracle (ou MySql ou PostgreSql) .

criado por Osmando Oliveira em 30/04/2013 11:07am
5. Integrando o PHP (CodeIgniter) com JasperServer

O JasperServer possui web services que permitem às aplicações enviarem e receberem dados do servidor em formato XML, e um desses web services utiliza o protocolo SOAP (Simple Object Access Protocol) para a troca dos dados. O PHP5 possui um cliente SOAP nativo, que pode ser usado para enviar e receber dados do JasperServer, fazendo com que o relatório seja executado no servidor e o resultado (saída em PDF, por exemplo) seja enviado de volta para o script, que pode salvá-lo em arquivo ou exibí-lo na tela. O manual do JasperServer explica como deve ser o formato do arquivo XML para a troca de informações.

Depois de algumas pesquisas, encontrei no site http://stackoverflow.com um script que cria o arquivo XML, inicia o cliente SOAP do PHP, faz a consulta ao servidor e recebe o resultado, ou seja, faz todo o trabalho, necessitando apenas que sejam passados alguns parâmetros (não consegui mais encontrar o usuário que enviou o script, para citar a fonte). Irei abordar aqui como integrar esse script (biblioteca) ao Framework CodeIgniter, mas poderá facilmente ser adaptado para outras situações.

Na pasta "system\application\libraries" da sua aplicação do CodeIgniter, crie uma pasta chamada "jasper"; nesta pasta, crie um novo arquivo PHP com o nome de "jasper" e cole nele o código abaixo:

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * Classe Jasper
 *
 * Esta classe permite acessar o Jasper Server, via SOAP, utilizando xml.
 *
 * @package		CodeIgniter
 * @subpackage	Libraries
 * @category	Libraries
 * @author	
 
 */

class Jasper {
   
    //Properties
    private $wsdlURL;
    private $username;
    private $password;
    private $_soapClient;
    private $_reportPath;
    private $_reportName;
    private $_outputFormat;
    private $_parameterArray;
    
    public function credenciais($wsdlURL, $username, $password) {
                
        $this->wsdlURL  = $wsdlURL;
        $this->username = $username;
        $this->password = $password;
        
        try {
            $this->_soapClient = new soapClient($this->wsdlURL, array('login' => $this->username,'password' => $this->password,'trace' => 1,));
        }
        catch (Exception $e) {
            throw $e;
        }
    }
   
    //Methods
    public function printReport($reportPath, $reportName, $outputFormat = "PDF", $parameterArray = "") {
        $this->_reportPath = $reportPath;
        $this->_reportName = $reportName;
        $this->_outputFormat = $outputFormat;
        $this->_parameterArray = $parameterArray;
       
        $requestXML = "<request operationName=\"runReport\">";
        $requestXML .= "<argument name=\"RUN_OUTPUT_FORMAT\">$outputFormat</argument>";
        $requestXML .= "<resourceDescriptor name=\"\" wsType=\"reportUnit\" uriString=\"$reportPath$reportName\" isNew=\"false\">";
        $requestXML .=     "<label></label>";
        foreach ($parameterArray as $key=>$value) {
            $requestXML .= "<parameter name=\"$key\"><![CDATA[$value]]></parameter>";
        }
        $requestXML .= "</resourceDescriptor></request>";
        $params = array("request" => $requestXML );
       
        $reportOutput = "";
        try {
            $response = $this->_soapClient->runReport($requestXML);
            $reportOutput = $this->parseResponseWithReportData(
                $this->_soapClient->__getLastResponseHeaders(),
                $this->_soapClient->__getLastResponse(),
                $outputFormat
            );
        }//end of try
        catch (SoapFault $e) {
            if ($e->faultstring == 'looks like we got no XML document') {
                $reportOutput = $this->parseResponseWithReportData(
                    $this->_soapClient->__getLastResponseHeaders(),
                    $this->_soapClient->__getLastResponse(),
                    $outputFormat
                );
            }//end of if
            else {
                throw new Exception("Erro ao criar o relatorio: " . $e->faultstring);
            }//end of else
        }//end of catch
        return $reportOutput;
    }//end of function

    private function parseResponseWithReportData($responseHeaders, $response, $outputFormat) {
        preg_match('/boundary="(.*?)"/', $responseHeaders, $matches);
        $boundary = $matches[1];
        $parts = explode($boundary, $response);
        $reportOutput = "";
        switch ($outputFormat) {
            case 'HTML':
                foreach($parts as $part) {
                      if (strpos($part, "Content-Type: image/png") !== false) {
                          $start = strpos($part, "<") + 1;
                          $length = (strpos($part, ">") - $start);
                          $filename = substr($part, $start, $length) . '.png';
                          $file = fopen("$this->_imageFolder$filename","wb");
                          $contentStart = strpos($part, "PNG") - 1;
                          $contentLength = (strpos($part, "--") - $contentStart) + 1;
                          $contents = substr($part, $contentStart, $contentLength);
                          fwrite($file, $contents);
                          fclose($file);
                      }
                      if (strpos($part, "Content-Type: image/gif") !== false) {
                          $start = strpos($part, "<") + 1;
                          $length = (strpos($part, ">") - $start);
                          $filename = substr($part, $start, $length) . '.gif';
                          $file = fopen("$this->_imageFolder$filename","wb");
                          $contentStart = strpos($part, "GIF");
                          $contentLength = (strpos($part, "--") - $contentStart) + 1;
                          $contents = substr($part, $contentStart, $contentLength);
                          fwrite($file, $contents);
                          fclose($file);
                      }
                    if (strpos($part, "Content-Type: text/html") !== false) {
                        $contentStart = strpos($part, '<html>');
                        $contentLength = (strpos($part, '</html>') - $contentStart) + 7;
                        $reportOutput = substr($part, $contentStart, $contentLength);
                      }
                }//end of for each
                break;
            case 'PDF':
                foreach($parts as $part) {
                    if (strpos($part, "Content-Type: application/pdf") !== false) {
                        $reportOutput = substr($part, strpos($part, '%PDF-'));
                        break;
                      }
                } //end of foreach
                break;
            case 'CSV':
                foreach($parts as $part) {
                    if (strpos($part, "Content-Type: application/vnd.ms-excel") !== false) {
                        $contentStart = strpos($part, 'Content-Id: <report>') + 24;
                        $reportOutput = substr($part, $contentStart);
                        break;
                    }
                }
        }
        return $reportOutput;
    }//end of functoin
}//end of class

?>

Salve o arquivo.


Eu optei por carregar a biblioteca no autoload, mas isso fica a critério de cada um. Também optei em criar um model, chamado "m_jasper", para fazer a conexão com o JasperServer, conforme o código abaixo:

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class M_Jasper extends Model {

    function __construct() {
        parent::Model();
    }


function gerarRelatorioPdf($pastaDoRelatorio, $nomeDoRelatorio, $parametros, $caminhoDoArquivo){

 $cliente = new Jasper();
 $cliente->credenciais('http://localhost:8090/jasperserver/services/repository?wsdl', 'usuario', 'usuario');
 $resultado = $cliente->printReport($pastaDoRelatorio, $nomeDoRelatorio, 'PDF', $parametros);
 if ($resultado){
    file_put_contents($caminhoDoArquivo, $resultado);
    
    unset($resultado);
    return true;
}
 
 else{
     unset($resultado);
     return false;
 }
 
}

}
?>

o primeiro "usuario" que aparece no script acima é o login de um usuário criado no JasperServer, sem privilégios administrativos, e o segundo "usuario" é a sua senha. Adapte conforme suas configurações.


Para utilizar a biblioteca, proceda da seguinte forma:

se a biblioteca "jasper" não estiver no autoload, carregue-a

$this->load->library('jasper');

carregue o model "m_jasper", que também pode ser carregado no autoload

$this->load->model('m_jasper');


eu optei em gerar o arquivo PDF, como se pode ver no script acima em

file_put_contents($caminhoDoArquivo, $resultado);

então, teremos que indicar o caminho do arquivo conforme a linha seguinte

$caminhoDoArquivo = 'pastaQualquer/nomeDoRelatorio.pdf';

"$caminhoDoArquivo" é uma string com o caminho completo do arquivo que será gerado. Dica: "pastaQualquer" tem que ser uma pasta que a sua aplicação no CodeIgniter tenha acesso com privilégios de leitura e escrita.


indique os parâmetros que serão passados ao relatório, se houver.

$parametros = array("PARAMETRO1" => VALOR, "PARAMETRO2" => VALOR, ... "PARAMETROn" => VALOR);

"$parametros" é um array com o formato mostrado acima, e pode haver tantos parâmetros quantos forem necessários. Se não houver, atribua vazio ("") à "$parametros".


execute a consulta ao servidor com o comando abaixo:

$pdf = $this->m_jasper->gerarRelatorioPdf('/pastaDorelatorio/', 'IdDoRelatorio', $parametros, $caminhoDoArquivo);

"/pastaDorelatorio/" é pasta que você criou no JasperServer, e "IdDoRelatorio", como o nome sugere, é o ID (e não o nome) que foi dado ao relatório.


ao final, você poderá ter algo como:

if ($pdf){
               
	comandos se verdadeiro
}
              
else{
                
	comandos se falso
                
}


Chegamos ao final do artigo. Espero poder ajudar àqueles que, assim como eu, têm dificuldades em gerar relatórios usando PHP, que é uma linguagem versátil e poderosa, mas deixa a desejar nesse quesito.

Um abraço e boa sorte a todos.

Comentários:

Mostrando 1 - 5 de 5 comentários
Silvio Lacerda,

Você está passando este número por extenso como parâmetro para o jasper server? Caso positivo, tente usar a função do PHP utf8_encode ($parametros = array("PARAMETRO1" => utf8_encode($variavel)), por exemplo).
Se não resolver, informe mais detalhes sobre o seu problema, para que eu possa tentar resolvê-lo.
Sim, a clase phpjasper tem alguns bugs, mas, como ela atendeu às minhas necessidades, não me empenhei em tentar resolvê-los.

Osmando.
29/10/2014 10:25am (~9 anos atrás)

Fiz um relatório no ireport 5 conseguir escrever um número por extenso (ex: 2,30) -Dois reais e trinta centavos. Tudo ok!

Mas, quando abro através de um link via php usando a classe phpjasper o relatório não abre. Sei que é problema no campo que escreve por extenso. Como resolver.

Sei que a classe phpjasper tem um monte de problemas. Conseguir contornar alguns. Mas, a escrita por extenso essa eu peço ajuda e desde já agradeço!
29/10/2014 10:09am (~9 anos atrás)

Antonio,

Você está usando Oracle? Qual o charset? (as casas decimais estão separadas com ponto ou com vírgula?)
Que tipo de dado há nesse campo, no banco de dados?
25/06/2014 9:22pm (~9 anos atrás)

Antonio disse:
Os campos de valores (double) de meu relatório saem no formato "americano" , ex.: 1,234.56 e não 1.234,56, apesar de eu configurar corretamente a propriedade "Pattern" do referido campo: #,##0.00

O que pode ser?
24/06/2014 10:19pm (~9 anos atrás)

Fabricio disse:
Parabéns Osmando...essa solução mostra a versatilidade de ser trabalhar com o PHP. Claro que existem diversas soluções possíveis, mas trabalhar com o iReport nos dá a confiabilidade de uma ferramenta gráfica já consagrada, com a flexibilidade do PHP.

Um abraço
02/09/2013 9:17am (~10 anos atrás)

Novo Comentário:

(Você pode usar tags como <b>, <i> ou <code>. URLs serão convertidas para links automaticamente.)