【问题标题】:FPDF WriteHTML() multiple table render showing only first one correctlyFPDF WriteHTML() 多表渲染仅正确显示第一个
【发布时间】:2016-08-07 11:38:37
【问题描述】:

我正在使用FPDF 来呈现 html 内容中的表格。 所以当我想渲染表格时,我得到了这个link 来渲染表格。问题是我在 html 中一个接一个地有两个表,我无法将其分开,因为内容来自WYSIWYG 编辑器。这里的第一张桌子工作正常。但对于第二张桌子,它根本不起作用。我检查了所有标记,一切看起来都不错。

html_table.php 是这样的

    <?php
//Based on HTML2PDF by Clément Lavoillotte


require('fpdf/fpdf.php');
require('htmlparser.inc.php');

class PDF_HTML_Table extends FPDF
{
var $B;
var $I;
var $U;
var $HREF;

function PDF($orientation='P', $unit='mm', $format='A4')
{
    //Call parent constructor
    $this->FPDF($orientation,$unit,$format);
    //Initialization
    $this->B=0;
    $this->I=0;
    $this->U=0;
    $this->HREF='';
}

function WriteHTML2($html)
{
    //HTML parser
    $html=str_replace("\n",' ',$html);
    $a=preg_split('/<(.*)>/U',$html,-1,PREG_SPLIT_DELIM_CAPTURE);
    foreach($a as $i=>$e)
    {
        if($i%2==0)
        {
            //Text
            if($this->HREF)
                $this->PutLink($this->HREF,$e);
            else
                $this->Write(5,$e);
        }
        else
        {
            //Tag
            if($e[0]=='/')
                $this->CloseTag(strtoupper(substr($e,1)));
            else
            {
                //Extract attributes
                $a2=explode(' ',$e);
                $tag=strtoupper(array_shift($a2));
                $attr=array();
                foreach($a2 as $v)
                {
                    if(preg_match('/([^=]*)=["\']?([^"\']*)/',$v,$a3))
                        $attr[strtoupper($a3[1])]=$a3[2];
                }
                $this->OpenTag($tag,$attr);
            }
        }
    }
}

function OpenTag($tag, $attr)
{
    //Opening tag
    if($tag=='B' || $tag=='I' || $tag=='U')
        $this->SetStyle($tag,true);
    if($tag=='A')
        $this->HREF=$attr['HREF'];
    if($tag=='BR')
        $this->Ln(5);
    if($tag=='P')
        $this->Ln(10);
}

function CloseTag($tag)
{
    //Closing tag
    if($tag=='B' || $tag=='I' || $tag=='U')
        $this->SetStyle($tag,false);
    if($tag=='A')
        $this->HREF='';
    if($tag=='P')
        $this->Ln(10);
}

function SetStyle($tag, $enable)
{
    //Modify style and select corresponding font
    $this->$tag+=($enable ? 1 : -1);
    $style='';
    foreach(array('B','I','U') as $s)
        if($this->$s>0)
            $style.=$s;
    $this->SetFont('',$style);
}

function PutLink($URL, $txt)
{
    //Put a hyperlink
    $this->SetTextColor(0,0,255);
    $this->SetStyle('U',true);
    $this->Write(5,$txt,$URL);
    $this->SetStyle('U',false);
    $this->SetTextColor(0);
}

function WriteTable($data, $w)
{
    $this->SetLineWidth(.3);
    $this->SetFillColor(255,255,255);
    $this->SetTextColor(0);
    $this->SetFont('');
    foreach($data as $row)
    {
        $nb=0;
        for($i=0;$i<count($row);$i++)
            $nb=max($nb,$this->NbLines($w[$i],trim($row[$i])));
        $h=5*$nb;
        $this->CheckPageBreak($h);
        for($i=0;$i<count($row);$i++)
        {
            $x=$this->GetX();
            $y=$this->GetY();
            $this->Rect($x,$y,$w[$i],$h);
            $this->MultiCell($w[$i],5,trim($row[$i]),0,'C');
            //Put the position to the right of the cell
            $this->SetXY($x+$w[$i],$y);                    
        }
        $this->Ln($h);

    }
}

function NbLines($w, $txt)
{
    //Computes the number of lines a MultiCell of width w will take
    $cw=&$this->CurrentFont['cw'];
    if($w==0)
        $w=$this->w-$this->rMargin-$this->x;
    $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
    $s=str_replace("\r",'',$txt);
    $nb=strlen($s);
    if($nb>0 && $s[$nb-1]=="\n")
        $nb--;
    $sep=-1;
    $i=0;
    $j=0;
    $l=0;
    $nl=1;
    while($i<$nb)
    {
        $c=$s[$i];
        if($c=="\n")
        {
            $i++;
            $sep=-1;
            $j=$i;
            $l=0;
            $nl++;
            continue;
        }
        if($c==' ')
            $sep=$i;
        $l+=$cw[$c];
        if($l>$wmax)
        {
            if($sep==-1)
            {
                if($i==$j)
                    $i++;
            }
            else
                $i=$sep+1;
            $sep=-1;
            $j=$i;
            $l=0;
            $nl++;
        }
        else
            $i++;
    }
    return $nl;
}

function CheckPageBreak($h)
{
    //If the height h would cause an overflow, add a new page immediately
    if($this->GetY()+$h>$this->PageBreakTrigger)
        $this->AddPage($this->CurOrientation);
}

function ReplaceHTML($html)
{
    $html = str_replace( '<li>', "\n<br> - " , $html );
    $html = str_replace( '<LI>', "\n - " , $html );
    $html = str_replace( '</ul>', "\n\n" , $html );
    $html = str_replace( '<strong>', "<b>" , $html );
    $html = str_replace( '</strong>', "</b>" , $html );
    $html = str_replace( '&#160;', "\n" , $html );
    $html = str_replace( '&nbsp;', " " , $html );
    $html = str_replace( '&quot;', "\"" , $html ); 
    $html = str_replace( '&#39;', "'" , $html );
    return $html;
}

function ParseTable($Table)
{
    $_var='';
    $htmlText = $Table;
    $parser = new HtmlParser ($htmlText);
    while ($parser->parse())
    {
        if(strtolower($parser->iNodeName)=='table')
        {
            if($parser->iNodeType == NODE_TYPE_ENDELEMENT)
                $_var .='/::';
            else
                $_var .='::';
        }

        if(strtolower($parser->iNodeName)=='tr')
        {
            if($parser->iNodeType == NODE_TYPE_ENDELEMENT)
                $_var .='!-:'; //opening row
            else
                $_var .=':-!'; //closing row
        }
        if(strtolower($parser->iNodeName)=='td' && $parser->iNodeType == NODE_TYPE_ENDELEMENT)
        {
            $_var .='#,#';
        }
        if ($parser->iNodeName=='Text' && isset($parser->iNodeValue))
        {
            $_var .= $parser->iNodeValue;
        }
    }
    $elems = explode(':-!',str_replace('/','',str_replace('::','',str_replace('!-:','',$_var)))); //opening row
    foreach($elems as $key=>$value)
    {
        if(trim($value)!='')
        {
            $elems2 = explode('#,#',$value);
            array_pop($elems2);
            $data[] = $elems2;
        }
    }
    return $data;
}

function WriteHTML($html)
{
    $html = $this->ReplaceHTML($html);
    //Search for a table
    $start = strpos(strtolower($html),'<table');
    $end = strpos(strtolower($html),'</table');
    if($start!==false && $end!==false)
    {
        $this->WriteHTML2(substr($html,0,$start).'<BR>');

        $tableVar = substr($html,$start,$end-$start);
        $tableData = $this->ParseTable($tableVar);
        for($i=1;$i<=count($tableData[0]);$i++)
        {
            if($this->CurOrientation=='L')
                $w[] = abs(120/(count($tableData[0])-1))+24;
            else
                $w[] = abs(120/(count($tableData[0])-1))+5;
        }
        $this->WriteTable($tableData,$w);

        $this->WriteHTML2(substr($html,$end+8,strlen($html)-1).'<BR>');
    }
    else
    {
        $this->WriteHTML2($html);
    }
}

}

而index.php是这样的

<?php
require('html_table.php');

$pdf = new PDF_HTML_Table();
$pdf->AddPage();
$pdf->SetFont('Arial','',12);

$html='<table border="1">
<tr>
<td width="200" height="30">cell 1</td><td width="200" height="30" bgcolor="#D0D0FF">cell 2</td>
</tr>
<tr>
<td width="200" height="30">cell 3</td><td width="200" height="30">cell 4</td>
</tr>
</table>
<br>
<br>
<table border="1">
<tr>
<td width="200" height="30">cell 5</td><td width="200" height="30" bgcolor="#D0D0FF">cell 6</td>
</tr>
<tr>
<td width="200" height="30">cell 7</td><td width="200" height="30">cell 8</td>
</tr>
</table>
';

$pdf->WriteHTML($html);
$pdf->Output();
?>

谁能告诉我如何解决这个问题?任何帮助和建议都将是非常可观的。谢谢

【问题讨论】:

    标签: php pdf-generation fpdf


    【解决方案1】:

    前几天我遇到了这个确切的问题,并想出了以下解决方案:

    1. 在您的 FPDF 类中,添加函数 findAll()。这将用于查找要转换的 HTML 中的所有 &lt;table&lt;/table 实例:

      function findAll($needle, $haystack) 
      {
        // initialize the return value array
        $rv = array();
      
        // set up a temp variable to make things simple
        $temp = 0;
      
        // successively find each instance of needle in haystack
        while($temp < strlen($haystack)) 
        {
          $temp = strpos($haystack,$needle, $temp);
      
          if($temp !== false) 
          {
            $rv[] = $temp;
            $temp++;
          } 
          else
          {
            // nothing to find
            return $rv;
          }
        }
      
        return $rv;
      }  
      
    2. 修改您的 WriteHTML() 函数为 a) 使用 findAll() 查找所有表实例,并 b) 替换每个实例(保持任何非表格式不变)。这种修改实质上是将您的 HTML “分块”为“表格”和“非表格”片段,并相应地格式化 HTML:

        function WriteHTML($html)
        {
          $w = array();
      
          // search for a table
          $starts = $this->findAll('<table',strtolower($html));
          $ends = $this->findAll('</table',strtolower($html));
      
          if(count($starts) > 0 && count($ends) > 0)
          {
            $positions[0] = 'doc-start';
      
            foreach($starts as $key => $start)
            {
              $end = $ends[$key];
              $positions[$start] = 'table-start';
              $positions[$end] = 'table-end';
            }
      
            $endPos = strlen($html)-1;
            $positions[$endPos] = 'doc-end';
      
            $lastKnownPos = 0;
      
            for($q=1;$q<=$endPos;$q++)
            {
              if(isset($positions[$q]))
              {
                $curPos = $positions[$q];
      
                if($curPos == 'table-start')
                {
                  $this->WriteHTML2(substr($html,$lastKnownPos,$q-$lastKnownPos).'<BR>'); 
                  $lastKnownPos = $q;
                }
                else if($curPos == 'table-end')
                {
                  $tableVar = substr($html,$lastKnownPos,$q-$lastKnownPos+8);
                  $tableData = $this->ParseTable($tableVar);
      
                  for($i=0;$i<count($tableData[0]);$i++)
                  {
                    if($this->CurOrientation=='L')
                    {
                      $w[$i] = abs(277/(count($tableData[0])));
                    }
                    else
                    {
                      $w[$i] = abs(190/(count($tableData[0])));
                    }
                  }
                  $this->WriteTable($tableData,$w);
                  $lastKnownPos = $q+8;
                }
                else if($curPos == 'doc-end')
                {
                  $this->WriteHTML2(substr($html,$lastKnownPos,$q-$lastKnownPos).'<BR>'); 
                  $lastKnownPos = $q;              
                }
              }
            }
          } 
          else
          {
            // if there is no table, just write the HTML as normal
            $this->WriteHTML2($html);
          }
        }
      

    【讨论】:

      【解决方案2】:

      如果您使用 HTML 代码为使用 FPDF 库生成的 PDF 文档构建表格,请查看 FPDF easyTable 项目https://github.com/fpdf-easytable/fpdf-easytable

      $table=new easyTable($pdf, 3, 'border:1;');
      
      // first row
      $table->easyCell('Text 1', 'valign:T'); 
      $table->easyCell('Text 2', 'bgcolor:#b3ccff;');
      $table->easyCell('Text 3');
      $table->printRow();
      
      //second row
      $table->rowStyle('min-height:20; align:{C}'); 
      $table->easyCell('Text 4', 'colspan:3');
      $table->printRow();
      
      $table->endTable(4);
      

      【讨论】:

        猜你喜欢
        • 2013-03-06
        • 2021-10-04
        • 2015-10-06
        • 2013-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-18
        相关资源
        最近更新 更多