资讯专栏INFORMATION COLUMN

PHP制作word简历

Donne / 2197人阅读

摘要:模板替换的方式制作简历在许多招聘网站都有一个简历下载的功能,如何用实现呢在里面就有一个非常简单的生成一个文档,向文档中插入一些文字。安装创建控制器及方法用于测试,并建立路由。

PHP操作word有一个非常好用的轮子,就是phpword,该轮子可以在github上查找到(PHPOffice/PHPWord)。上面有较为详细的例子和代码,其中里面的源码包含有一些常用的操作例子,包括设置页眉、页脚、页码、字体样式、表格、插入图片等常用的操作。这里介绍的是如何使用该轮子来制作一个简历。

模板替换的方式制作简历

在许多招聘网站都有一个简历下载的功能,如何用php实现呢?在PHPOffice/PHPWord里面就有一个非常简单的生成一个word文档,向文档中插入一些文字。这里我使用的方式比较取巧,这个轮子的说明文档中有template processing,我理解为模板替换,也就是跟laravel的blade模板一个概念。接下来就不多废话,直接说如何操作,这里提一句使用的是laravel框架。

1.安装PHPOffice/PHPWord

composer require phpoffice/phpword

2.创建控制器DocController及test方法用于测试,并建立路由。

php artisan make:controller DocController

3.建立word模板,这里说明一下,该轮子替换的是word文档中格式为${value}格式的字符串,这里我简易的搭建一个模板如下图1所示:

从图中可以看到有一些基本的信息,这些可以从数据库中捞取数据。不过这次是直接使用替换的方式,像工作经历和教育经历这种多行表格的模式这里也只需要取一行作为模板即可。

4.具体代码

//load template docx
        $templateProcessor = new TemplateProcessor("./sample.docx");

        //基础信息填写替换
        $templateProcessor->setValue("update_at", date("Y-m-d H:i:s"));
        $templateProcessor->setValue("number", "123456");
        $templateProcessor->setValue("Name", "张三");
        $templateProcessor->setValue("sex", "男");
        $templateProcessor->setValue("birth", "1996年10月");
        $templateProcessor->setValue("age", "22");
        $templateProcessor->setValue("shortcut", "待业/aaa");
        $templateProcessor->setValue("liveArea", "福建省莆田市涵江区");
        $templateProcessor->setValue("domicile", "福建省莆田市涵江区");
        $templateProcessor->setValue("address", "");
        $templateProcessor->setValue("hopetodo", "IT");
        $templateProcessor->setValue("hopeworkin", "互联网");
        $templateProcessor->setValue("hopes", "7000+");
        $templateProcessor->setValue("worklocation", "福建省莆田市");
        $templateProcessor->setValue("phone", "123456789");
        $templateProcessor->setValue("mail", "456789@qq.com");
        $templateProcessor->setValue("qqnum", "456789");
        $templateProcessor->setValue("selfjudge", "哇哈哈哈哈哈哈哈");

        //工作经历表格替换
        $templateProcessor->cloneRow("experience_time", 2);//该表通过克隆行的方式,形成两行
        $templateProcessor->setValue("experience_time#1", "2010-09~2014-06");//每行参数是用value#X(X表示行号,从1开始)
        $templateProcessor->setValue("job#1", "ABC company CTO");
        $templateProcessor->setValue("experience_time#2", "2014-09~至今");
        $templateProcessor->setValue("job#2", "JBC company CTO");

        //教育经历
        $templateProcessor->cloneRow("time", 2);
        $templateProcessor->setValue("time#1", "2010-09~2014-06");
        $templateProcessor->setValue("school#1", "ABC");
        $templateProcessor->setValue("major#1", "Computer science");
        $templateProcessor->setValue("time#2", "2014-09~至今");
        $templateProcessor->setValue("school#2", "JBC");
        $templateProcessor->setValue("major#2", "Computer science");

        //语言能力
        $templateProcessor->cloneRow("lang",2);
        $templateProcessor->setValue("lang#1", "汉语|精通");
        $templateProcessor->setValue("lang#2", "英语|精通");

        //技能
        $templateProcessor->cloneRow("skill",3);
        $templateProcessor->setValue("skill#1", "JAVA|精通");
        $templateProcessor->setValue("skill#2", "Python|精通");
        $templateProcessor->setValue("skill#3", "PHP|精通");

        // Saving the document
        $templateProcessor->saveAs("my.docx");

这样就可以通过建立word模板的方式产生一个简历了。以上内容没有提到如何将图片替换进去,如果你查看文档的话会发现这个包的模板替换并没有说怎么替换图片,因为好像压根这种方式就没有提供,晕死。不过github的issue中有人提出了这个问题并且也有人给出了解决方案。下面我就来说说如何实现将图片替换进去的功能。

替换图片

假设你的简历模板中有个表格单元格中要插入一张图片,如下:

我要将public/img下的against the current.jpg图片替换进去,而源代码没有将图片替换进word的功能,所以只能自己编写了。

1.修改composer.json,将TemplateDocx类自动加载进来:

"autoload": {
        "classmap": [
            "database/seeds",
            "database/factories",
            "app/Core/TemplateDocx.php"
        ],
        "psr-4": {
            "App": "app/"
        }
    },

运行下列代码:

composer dump-autoload

2.实现TemplateDocx类:

该类的内容我直接放在我的gist上了,连接TemplateDocx.php

由于code是放在gist上,国内访问不了所以我直接把code贴出来,如下:

_countRels = 100; //start id for relationship between image and document.xml
        $this->_rels = "";
        $this->_types = "";
    }
    /**
     * Saves the result document.
     *
     * @throws PhpOfficePhpWordExceptionException
     *
     * @return string
     */
    public function save()
    {
        foreach ($this->tempDocumentHeaders as $index => $xml) {
            $this->zipClass->addFromString($this->getHeaderName($index), $xml);
        }
        $this->zipClass->addFromString($this->getMainPartName(), $this->tempDocumentMainPart);
        /*****************重写原有的save方法中添加的内容******************/
        if ($this->_rels != "") {
            $this->zipClass->addFromString("word/_rels/document.xml.rels", $this->_rels);
        }
        if ($this->_types != "") {
            $this->zipClass->addFromString("[Content_Types].xml", $this->_types);
        }
        /*********************我是分割线******************************/
        foreach ($this->tempDocumentFooters as $index => $xml) {
            $this->zipClass->addFromString($this->getFooterName($index), $xml);
        }
        // Close zip file
        if (false === $this->zipClass->close()) {
            throw new Exception("Could not close zip file.");
        }
        return $this->tempDocumentFilename;
    }
    /**
     * 实现将图片替换进word稳定的方法
     * @param $strKey
     * @param $img
     */
    public function setImg($strKey, $img){
        $strKey = "${".$strKey."}";
        $relationTmpl = "";
        $imgTmpl = "";
        $toAdd = $toAddImg = $toAddType = "";
        $aSearch = array("RID", "IMG");
        $aSearchType = array("IMG", "EXT");
        $countrels=$this->_countRels++;
        //I"m work for jpg files, if you are working with other images types -> Write conditions here
        $imgExt = "jpg";
        $imgName = "img" . $countrels . "." . $imgExt;
        $this->zipClass->deleteName("word/media/" . $imgName);
        $this->zipClass->addFile($img["src"], "word/media/" . $imgName);
        $typeTmpl = "";
        $rid = "rId" . $countrels;
        $countrels++;
        list($w,$h) = getimagesize($img["src"]);
        if(isset($img["swh"])) //Image proportionally larger side
        {
            if($w<=$h)
            {
                $ht=(int)$img["swh"];
                $ot=$w/$h;
                $wh=(int)$img["swh"]*$ot;
                $wh=round($wh);
            }
            if($w>=$h)
            {
                $wh=(int)$img["swh"];
                $ot=$h/$w;
                $ht=(int)$img["swh"]*$ot;
                $ht=round($ht);
            }
            $w=$wh;
            $h=$ht;
        }
        if(isset($img["size"]))
        {
            $w = $img["size"][0];
            $h = $img["size"][1];
        }
        $toAddImg .= str_replace(array("RID", "WID", "HEI"), array($rid, $w, $h), $imgTmpl) ;
        if(isset($img["dataImg"]))
        {
            $toAddImg.="".$this->limpiarString($img["dataImg"])."";
        }
        $aReplace = array($imgName, $imgExt);
        $toAddType .= str_replace($aSearchType, $aReplace, $typeTmpl) ;
        $aReplace = array($rid, $imgName);
        $toAdd .= str_replace($aSearch, $aReplace, $relationTmpl);
        $this->tempDocumentMainPart=str_replace("" . $strKey . "", $toAddImg, $this->tempDocumentMainPart);
        //print $this->tempDocumentMainPart;
        if($this->_rels=="")
        {
            $this->_rels=$this->zipClass->getFromName("word/_rels/document.xml.rels");
            $this->_types=$this->zipClass->getFromName("[Content_Types].xml");
        }
        $this->_types       = str_replace("", $toAddType, $this->_types) . "";
        $this->_rels        = str_replace("", $toAdd, $this->_rels) . "";
    }
}

3.使用方法:

$templateProcessor = new TemplateDocx("./sample.docx");
        $imgPath = "./img/against the current.jpg";

        $templateProcessor->setImg("img", array(
            "src"  => $imgPath, //图片路径
            "size" => array( 150, 150 ) //图片大小,单位px
        ));
        $templateProcessor->setValue("name", "Sun");

        $templateProcessor->cloneRow("key", 2);//该表通过克隆行的方式,形成两行
        $templateProcessor->setValue("key#1", "2010-09~2014-06");//每行参数是用value#X(X表示行号,从1开始)
        $templateProcessor->setValue("val#1", "ABC company CTO");
        $templateProcessor->setValue("key#2", "2014-09~至今");
        $templateProcessor->setValue("val#2", "JBC company CTO");
//        $templateProcessor->setValue("img", "Sun");

        $templateProcessor->saveAs("my.docx");

4.运行结果

至此就可以产生简历啦,如果这篇文章对你有所帮助记得点赞哦,亲!如果有任何问题可以留言!!(* ̄︶ ̄)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/28535.html

相关文章

  • 程序员写简历时的技术词汇拼写规范备忘录!

    摘要:写在前面每年这个时候又到了求职的旺季。求职前,我们都会花很多的时间在自己的技术水平提升笔面试的准备之上,但往往却忽略了找工作第一步所需要的一个严谨且靠谱的简历。而程序员写简历,第一步就是需要注意严谨而规范地使用各种技术词汇。 ...

    h9911 评论0 收藏0
  • 我本以为你们会写简历

    摘要:然而并不是裁员的裁员没裁员的正在准备裁员的路上再加上一些人年终奖也已经骗到手了依据优良传统年后正是很多人辞职奔向更好的骗工资岗位的高峰期所以如何编简历注意是编不是写我认为编这个字十分有内涵其实编简历并不是一件很难的事情这件事情的本质就是你在 然而并不是 裁员的裁员 , 没裁员的正在准备裁员的路上 . 再加上一些人年终奖也已经骗到手了 , 依据优良传统 , 年后正是很多人辞职奔向更好的骗...

    buildupchao 评论0 收藏0
  • 如何写一份好的前端面试简历?

    摘要:简历的存在只有一个目的帮你约到面试。即使你通过其他方式获得了面试,当你入职的时候,还是要有这么一份纸质简历的,所以不要想着偷懒。在该系统上线后,前端性能从提升到,服务器由台减少到台通过量化的数字来增强可信度。 简历的本质 原文地址在写简历之前,我们必须清楚的了解一件事情,那就是简历是什么?它不是人生履历,不是项目清单,也不是技能大放送。简历的存在只有一个目的 —— 帮你约到面试。只要能...

    winterdawn 评论0 收藏0
  • 如何写一份好的前端面试简历?

    摘要:简历的存在只有一个目的帮你约到面试。即使你通过其他方式获得了面试,当你入职的时候,还是要有这么一份纸质简历的,所以不要想着偷懒。在该系统上线后,前端性能从提升到,服务器由台减少到台通过量化的数字来增强可信度。 简历的本质 原文地址在写简历之前,我们必须清楚的了解一件事情,那就是简历是什么?它不是人生履历,不是项目清单,也不是技能大放送。简历的存在只有一个目的 —— 帮你约到面试。只要能...

    joyvw 评论0 收藏0
  • 如何写一份好的前端面试简历?

    摘要:简历的存在只有一个目的帮你约到面试。即使你通过其他方式获得了面试,当你入职的时候,还是要有这么一份纸质简历的,所以不要想着偷懒。在该系统上线后,前端性能从提升到,服务器由台减少到台通过量化的数字来增强可信度。 简历的本质 原文地址在写简历之前,我们必须清楚的了解一件事情,那就是简历是什么?它不是人生履历,不是项目清单,也不是技能大放送。简历的存在只有一个目的 —— 帮你约到面试。只要能...

    wpw 评论0 收藏0

发表评论

0条评论

Donne

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<