准备工作

  • composer require tecnickcom/tcpdf  安装插件
  • 下载中文字体(tcpdf某部分字体导出的是中文是乱码),放到“\tecnickcom\tcpdf\tools\”目录下
  • 在第二步骤打开cmd ,输入php tcpdf_addfont.php -i .\msyh.ttf(执行成功之后会生成对应文件)

字体下载

msyh

注意事项

  • 强烈建议把pdf输出到本地文件查看,实测apipost查看会出现乱码
  • 字体下载好之后把ttf格式解压出来放到tools,别把rar放到tools文件夹
  • 字体样式请注意是否侵权

可扩展

  • php合并PDF FPDI

  • https://blog.csdn.net/qq_31695557/article/details/122936987?spm=1001.2014.3001.5502 可参考此文章
  • FPDF   下载网址  http://www.fpdf.org/
    FPDI     下载网址  https://www.setasign.com/products/fpdi/about/

设置pdf页面数据

public function exportPDF()
{
    $path = '/static/uploads/preview/' . date('Ym') . '/';//文件存放路径
    $directory=ROOT_PATH.'public';//根目录
    $is_path       = $directory. $path;//全路径
    //检测并创建文件夹
    if ($this->exists_dir($is_path) === false) {
        return false;
    }
    $objPDF = new \TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
    // 是否显示页眉
    $objPDF->setPrintHeader(false);
    // 是否显示页脚
    $objPDF->setPrintFooter(true);
    // 设置页脚的字体
    $objPDF->setFooterFont(Array('msyh', '', '8'));
    // 设置页脚距离底部的距离
    $objPDF->SetFooterMargin('7');
    // 设置默认等宽字体
    $objPDF->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
    // 设置行高
    $objPDF->setCellHeightRatio(1.5);
    // 设置是否自动分页  距离底部多少距离时分页
    $objPDF->SetAutoPageBreak(TRUE, '10');
    $objPDF->setFontSubsetting(true);
    $objPDF->AddPage();
    // 设置字体
    $objPDF->SetFont('msyh', '', 12);
    $info = [];
    $info['grade'] = '一年级';
    $info['year'] = '2023';
    $info['season'] = '第四季度';
    $info['student'] = '50';
    $info['cmit'] = '49';
    $list = [];
    $list[0]['type'] = '单选题';
    $list[0]['title'] = '题目题干';
    $list[0]['answer'] = 'A';
    $list[0]['percent'] = '50';
    $list[0]['option_A'] = 'A选项内容';
    $list[0]['sel_A'] = '0';
    $list[0]['percent_A'] = '0';
    $list[0]['option_B'] = 'A选项内容';
    $list[0]['sel_B'] = '0';
    $list[0]['percent_B'] = '0';
    $list[0]['option_C'] = 'A选项内容';
    $list[0]['sel_C'] = '0';
    $list[0]['percent_C'] = '0';
    $list[0]['option_D'] = 'A选项内容';
    $list[0]['sel_D'] = '0';
    $list[0]['percent_D'] = '0';
    $list[0]['option_E'] = 'A选项内容';
    $list[0]['sel_E'] = '0';
    $list[0]['percent_E'] = '0';
    $list[0]['option_F'] = 'A选项内容';
    $list[0]['sel_F'] = '0';
    $list[0]['percent_F'] = '0';
    $list[0]['option_G'] = 'A选项内容';
    $list[0]['sel_G'] = '0';
    $list[0]['percent_G'] = '0';
    $list[0]['cmit_num'] = '20';

    // 调用拼接html代码方法
    $pdf_html = $this->pdfHtml($info,$list,'期末考试');
    $objPDF->writeHTMLCell(0, 0, '', '', $pdf_html, 0, 1, 0, true, '', true);
    //添加二维码
    $url = $this->site() . '/h5/' . '1.png';
    $url = 'https://lrfgkhjlksg/1.jpg';
    $num_num = $objPDF->getNumPages();//获取当前页码
    $objPDF->setPage($num_num);//二维码放置指定的页面
    $style = array(
        'border' => false,
        'padding' => 0,
        'fgcolor' => array(0, 0, 0),
        'bgcolor' => false, //array(255,255,255)
        //'module_width' => 1, // width of a single module in points
        //'module_height' => 1 // height of a single module in points
    );
    //生成二维码
    $objPDF->write2DBarcode($url, 'QRCODE,L', 16, 12, 17, 17, $style, 'N');
    // 输出  四种模式 I输出、D下载、F保存本地、S输出二进制字符串
    $objPDF->Output($is_path . 123456 . ".pdf", "F");
}
检测文件夹
public function exists_dir(string $path): bool
{
    if (file_exists($path) === false) {
        $path     = str_replace("\\", '/', $path);
        $path_arr = explode('/', $path);
        $ping     = '';
        //循环逐级检测 不存在则创建
        foreach ($path_arr as $k => $v) {
            $ping .= $v . '/';
            if (file_exists($ping) === false && !mkdir($ping, 777) && is_dir($ping)) {
                return false;
            }
        }
    }
    return true;
}

书写html

public function pdfHtml($info,$list,$title)
{
    $html = '';
    $html .= '<h2 style="text-align:center;"><b>'.$title.'</b></h2>
<table style="text-align:right">
<tr><td>班级:'.$info['grade'].'_'.$info['year'].$info['season'].'</td></tr>
<tr><td>总人数:'.$info['student'].'; 已交卷:'.$info['cmit'].'</td></tr>
<tr><td>导出时间:'.date('Y-m-d H:i:s',time()).'</td></tr>
</table>';

    foreach ($list as $k => $v) {
        $html .= '<div>
    【'.$v['type'].'】 第'.($k+1).'题:'.$v['title'].'<br><span style="color: green;">【正确答案:'.$v['answer'].'】</span><b style="color: #1E9FFF"> &nbsp; &nbsp; 正确率:'.$v['percent'].'%</b>
</div>
<table  border="1" style="text-align:center">
    <colgroup>
      <col width="40%">
      <col width="10%">
      <col width="50%">
      <col>
    </colgroup>
    <tr style="background:#f2f2f2; ">
        <th>选项</th>
        <th>选择次数 / 人</th>
        <th>比例</th>
    </tr> 
       <tr>
            <td style="text-align:left">A:'.$v['option_A'].'</td>
            <td>'.$v['sel_A'].'</td>
            <td>'.$v['percent_A'].'%</td>
        </tr>
        <tr>
            <td style="text-align:left">B:'.$v['option_B'].'</td>
            <td>'.$v['sel_B'].'</td>
            <td>'.$v['percent_B'].'% </td>
        </tr>
        <tr>
            <td style="text-align:left">C:'.$v['option_C'].'</td>
            <td>'.$v['sel_C'].'</td>
            <td> '.$v['percent_C'].'% </td>
        </tr>
        <tr>
            <td style="text-align:left">D:'.$v['option_D'].'</td>
            <td>'.$v['sel_D'].'</td>
            <td> '.$v['percent_D'].'% </td>
        </tr>
        <tr>
            <td style="text-align:left">E:'.$v['option_E'].'</td>
            <td>'.$v['sel_E'].'</td>
            <td> '.$v['percent_E'].'% </td>
        </tr>
        <tr>
            <td style="text-align:left">F:'.$v['option_F'].'</td>
            <td>'.$v['sel_F'].'</td>
            <td> '.$v['percent_F'].'% </td>
        </tr>
        <tr>
            <td style="text-align:left">G:'.$v['option_G'].'</td>
            <td>'.$v['sel_G'].'</td>
            <td> '.$v['percent_G'].'% </td>
        </tr>
    <tr>
        <th>作答人数:'.$v['cmit_num'].' 人次</th>
        <th></th>
        <th></th>
    </tr> 
</table><br/>';
    }
    return $html;
}

扩展功能-添加二维码

public function qrCodePdf(array $arr): void
{
    //生成二维码  文档 https://tcpdf.org/examples/example_027/
    if (!empty($arr['on_off']) && $arr['on_off'] === 1) {
      
        //二维码链接
        $url = $this->site() . '/h5_contract_url/' . $arr['uniq_key'];
        $arr['pdf']->setPage($arr['set_page']);//二维码放置指定的页面

        $style = array(
            'border' => false,
            'padding' => 0,
            'fgcolor' => array(0, 0, 0),
            'bgcolor' => false, //array(255,255,255)
            //'module_width' => 1, // width of a single module in points
            //'module_height' => 1 // height of a single module in points
        );
        //生成二维码
        $arr['pdf']->write2DBarcode($url, 'QRCODE,L', 16, 12, 17, 17, $style, 'N');
        return $arr;
    }
}
public function site(): string
{
    return $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['SERVER_NAME'];
}