Hướng dẫn phpword library - thư viện phpword

PHPOffice là một thư viện PHP khá mạnh để thực hiện các công việc liên quan đến các file văn bản và trang tính. Nó bao gồm 2 công cụ: PHPWord để thao tác với file văn bản và PHPExcel để thao tác với trang tính. Với PHPWord ta có thể dễ dàng tạo ra một file văn bản mới với các thành phần và định dạng như mong muốn, hoặc ta cũng có thể tạo ra một file văn bản từ một template đã có sẵn. PHPWord cung cấp các phương thức để người dùng dễ dàng tạo một file văn bản với các thành phần cơ bản như text, paragraph, header, footer, table,...

Sau đây là hướng dẫn tích hợp thư viện PHPWord vào CodeIgniter:

Bước 1: Download PHPWord từ github:

https://github.com/PHPOffice/PHPWord

Bước 2: Giải nén PHPWord (chỉ giải nén PHPWord.php and PHPWord folder) và đưa vào thư mục application/third_party của CodeIgniter

Chỉ copy 2 thư mục vào application/third_party

Bước 3: tạo 1 thư viện mới trong application/libraries của CodeIgniter. Ví dụ đặt tên là Word.php với mã nguồn như sau:
<?php
if (!defined('BASEPATH')) exit('No direct script access allowed'); 
require_once APPPATH."/third_party/PHPWord.php"; 
 
class Word extends PHPWord { 
    public function __construct() { 
        parent::__construct(); 
    } 
}
Bước 4: gọi và sử dụng thư viện Word từ Controller:

Gọi thư viện và tạo ra section mới (Bắt buộc)

$this->load->library('word');
//our docx will have 'lanscape' paper orientation
$section = $this->word->createSection(['orientation' => 'landscape']);

Thêm một số định dạng và đoạn văn bản.

// Add text elements
$section->addText('Hello World!');
$section->addTextBreak(1);
  
$section->addText('I am inline styled.', ['name' => 'Verdana', 'color' => '006699']);
$section->addTextBreak(1);
  
$this->word->addFontStyle('rStyle', ['bold' => true, 'italic' => true, 'size' => 16]);
$this->word->addParagraphStyle('pStyle', ['align' => 'center', 'spaceAfter' => 100]);
$section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle');
$section->addText('I have only a paragraph style definition.', null, 'pStyle');

Thêm một số ảnh. Chú ý không sử dụng base_url or site_url, PHPWord chỉ sử dụng đường dẫn tuyêt đối đến máy chủ của bạn. Có nghĩa rằng bạn không thể thêm ảnh mà không phải từ máy chủ của bạn.

// Add image elements
$section->addImage(FCPATH.'/image/_mars.jpg');
$section->addTextBreak(1);
$section->addImage(FCPATH.'/image/_earth.JPG', ['width' => 210, 'height' => 210, 'align' => 'center']);
$section->addTextBreak(1);
$section->addImage(FCPATH.'/image/_mars.jpg', ['width' => 100, 'height' => 100, 'align' => 'right']);

Tạo bảng table và đưa thêm 1 số định dạng style

// Define table style arrays
$styleTable = ['borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80];
$styleFirstRow = ['borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF'];
// Define cell style arrays
$styleCell = ['valign' => 'center'];
$styleCellBTLR = ['valign' => 'center', 'textDirection' => PHPWord_Style_Cell::TEXT_DIR_BTLR];
// Define font style for first row
$fontStyle = ['bold' => true, 'align' => 'center'];
// Add table style
$this->word->addTableStyle('myOwnTableStyle', $styleTable, $styleFirstRow);
// Add table
$table = $section->addTable('myOwnTableStyle');
// Add row
$table->addRow(900);
// Add cells
$table->addCell(2000, $styleCell)->addText('Row 1', $fontStyle);
$table->addCell(2000, $styleCell)->addText('Row 2', $fontStyle);
$table->addCell(2000, $styleCell)->addText('Row 3', $fontStyle);
$table->addCell(2000, $styleCell)->addText('Row 4', $fontStyle);
$table->addCell(500, $styleCellBTLR)->addText('Row 5', $fontStyle);
// Add more rows / cells
for ($i = 1; $i <= 2; $i++) {
    $table->addRow();
    $table->addCell(2000)->addText("Cell $i");
    $table->addCell(2000)->addText("Cell $i");
    $table->addCell(2000)->addText("Cell $i");
    $table->addCell(2000)->addText("Cell $i");
    $text = $i % 2 == 0 ? 'X' : '';
    $table->addCell(500)->addText($text);
}

Cuối cùng đặt tên văn bản với đuôi .docx và lưu file lại.

$filename='just_some_random_name.docx'; //save our document as this file name
header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document'); //mime type
header('Content-Disposition: attachment;filename="'.$filename.'"'); //tell browser what's the file name
header('Cache-Control: max-age=0'); //no cache
 
$objWriter = PHPWord_IOFactory::createWriter($this->word, 'Word2007');
$objWriter->save('php://output');

Để tạo một tài liệu Word thì hiện tại không có nhiều thư viện PHP để làm tốt công việc này. Trong bài viết này sẽ giới thiệu về thư viện PhpWord để xuất ra các định dạng Word. PHPWord ta có thể dễ dàng tạo ra một file văn bản mới với các thành phần và định dạng như mong muốn, hoặc ta cũng có thể tạo ra một file văn bản từ một template đã có sẵn. PHPWord cung cấp các phương thức để người dùng dễ dàng tạo một file văn bản với các thành phần cơ bản như text, paragraph, header, footer, table

Hướng dẫn phpword library - thư viện phpword

1. Các tính năng

  • Đặt tiêu đề, chủ đề và người tạo
  • Tùy biến kích thước và đánh số trang
  • Tạo header và footer cho mỗi trang văn bản
  • Đặt loại phông chữ mặc định, kích thước phông chữ
  • Sử dụng phông UTF-8 và East Asia
  • Tùy chỉnh kiểu phông chữ như in đậm, in nghiêng, khoảng cách ...
  • Chèn các đoạn văn bản đơn giản hoặc phức tạp
  • Chèn tiêu đề, mục lục
  • Ngắt văn bản hoặc ngắt trang
  • ...

2. Cài đặt

Sử dụng composer

{
    "require": {
       "phpoffice/phpword": "v0.17.*"
    }
}

# run:  composer install 

Sau khi cài đặt xong thì ta có thể sử dụng bằng ví dụ tạo file word sau

<?php

namespace App\Services;
 
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\IOFactory;

class PhpWordService
{
    public function createFileWord()
    {
        //Khởi tạo đối tượng phpWord
        $phpWord = new PhpWord();

        //Thêm một tài liệu Word
        $section = $phpWord->addSection();

        //Thêm nội dung tài liệu cũng như các định dạng cơ bản của tài liệu
        $section->addText(
            'Nội dung',
            array(
                'name' => 'Arial',
                'size' => 14
            )
        );

        //Khởi tạo đối tượng writer
        $writer = IOFactory::createWriter($phpWord, 'Word2007');

        //Tạo tập tin Word
        $writer->save('path/to/save/filename.docx');
    }
}

Tạo file từ một mẫu cho trước

Với PhpWord ta có thể tạo một file từ một mẫu cho trước bằng cách đặt các ${key_search} ở các vị trí trong văn bản mẫu, các vị trí này sẽ được thay thế bằng bất cứ giá trị nào mà ta muốn điền.

Để tải một file word mẫu ta dùng

$templateProcessor = new TemplateProcessor('Template.docx');

setValue

Trong file template ta tạo các ${firstname} và ${lastname} vào các vị trí cần điền các nội dung tương ứng

// Add text elements
$section->addText('Hello World!');
$section->addTextBreak(1);
  
$section->addText('I am inline styled.', ['name' => 'Verdana', 'color' => '006699']);
$section->addTextBreak(1);
  
$this->word->addFontStyle('rStyle', ['bold' => true, 'italic' => true, 'size' => 16]);
$this->word->addParagraphStyle('pStyle', ['align' => 'center', 'spaceAfter' => 100]);
$section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle');
$section->addText('I have only a paragraph style definition.', null, 'pStyle');
7

khi này ta chỉ cần thêm bất cứ nội dung cần thiết bằng cách sử dụng hàm

// Add text elements
$section->addText('Hello World!');
$section->addTextBreak(1);
  
$section->addText('I am inline styled.', ['name' => 'Verdana', 'color' => '006699']);
$section->addTextBreak(1);
  
$this->word->addFontStyle('rStyle', ['bold' => true, 'italic' => true, 'size' => 16]);
$this->word->addParagraphStyle('pStyle', ['align' => 'center', 'spaceAfter' => 100]);
$section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle');
$section->addText('I have only a paragraph style definition.', null, 'pStyle');
8

$templateProcessor->setValue('firstname', 'John');
$templateProcessor->setValue('lastname', 'Doe');

kết quả thu được sẽ là Hello John Doe!Hello John Doe!

setValues

Ngoài cách sử dụng nhiều hàm

// Add text elements
$section->addText('Hello World!');
$section->addTextBreak(1);
  
$section->addText('I am inline styled.', ['name' => 'Verdana', 'color' => '006699']);
$section->addTextBreak(1);
  
$this->word->addFontStyle('rStyle', ['bold' => true, 'italic' => true, 'size' => 16]);
$this->word->addParagraphStyle('pStyle', ['align' => 'center', 'spaceAfter' => 100]);
$section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle');
$section->addText('I have only a paragraph style definition.', null, 'pStyle');
8 thì ta có thể truyền 1 mảng nhiều phần tử vào hàm
// Add image elements
$section->addImage(FCPATH.'/image/_mars.jpg');
$section->addTextBreak(1);
$section->addImage(FCPATH.'/image/_earth.JPG', ['width' => 210, 'height' => 210, 'align' => 'center']);
$section->addTextBreak(1);
$section->addImage(FCPATH.'/image/_mars.jpg', ['width' => 100, 'height' => 100, 'align' => 'right']);
0

$this->load->library('word');
//our docx will have 'lanscape' paper orientation
$section = $this->word->createSection(['orientation' => 'landscape']);
0

setImageValue

Ta có thể chèn hình ảnh vào văn bản mẫu bằng nhiều cách như sau

  • // Add image elements
    $section->addImage(FCPATH.'/image/_mars.jpg');
    $section->addTextBreak(1);
    $section->addImage(FCPATH.'/image/_earth.JPG', ['width' => 210, 'height' => 210, 'align' => 'center']);
    $section->addTextBreak(1);
    $section->addImage(FCPATH.'/image/_mars.jpg', ['width' => 100, 'height' => 100, 'align' => 'right']);
    
    1
  • // Add image elements
    $section->addImage(FCPATH.'/image/_mars.jpg');
    $section->addTextBreak(1);
    $section->addImage(FCPATH.'/image/_earth.JPG', ['width' => 210, 'height' => 210, 'align' => 'center']);
    $section->addTextBreak(1);
    $section->addImage(FCPATH.'/image/_mars.jpg', ['width' => 100, 'height' => 100, 'align' => 'right']);
    
    2
  • // Add image elements
    $section->addImage(FCPATH.'/image/_mars.jpg');
    $section->addTextBreak(1);
    $section->addImage(FCPATH.'/image/_earth.JPG', ['width' => 210, 'height' => 210, 'align' => 'center']);
    $section->addTextBreak(1);
    $section->addImage(FCPATH.'/image/_mars.jpg', ['width' => 100, 'height' => 100, 'align' => 'right']);
    
    3
  • // Add image elements
    $section->addImage(FCPATH.'/image/_mars.jpg');
    $section->addTextBreak(1);
    $section->addImage(FCPATH.'/image/_earth.JPG', ['width' => 210, 'height' => 210, 'align' => 'center']);
    $section->addTextBreak(1);
    $section->addImage(FCPATH.'/image/_mars.jpg', ['width' => 100, 'height' => 100, 'align' => 'right']);
    
    4
  • // Add image elements
    $section->addImage(FCPATH.'/image/_mars.jpg');
    $section->addTextBreak(1);
    $section->addImage(FCPATH.'/image/_earth.JPG', ['width' => 210, 'height' => 210, 'align' => 'center']);
    $section->addTextBreak(1);
    $section->addImage(FCPATH.'/image/_mars.jpg', ['width' => 100, 'height' => 100, 'align' => 'right']);
    
    5

Ví dụ

$this->load->library('word');
//our docx will have 'lanscape' paper orientation
$section = $this->word->createSection(['orientation' => 'landscape']);
1
$this->load->library('word');
//our docx will have 'lanscape' paper orientation
$section = $this->word->createSection(['orientation' => 'landscape']);
2

cloneBlock

$this->load->library('word');
//our docx will have 'lanscape' paper orientation
$section = $this->word->createSection(['orientation' => 'landscape']);
3

Nội dung ở giữa ${block_name} và ${/block_name} sẽ được lặp lại 3 lần khi ta sử dụng:

$this->load->library('word');
//our docx will have 'lanscape' paper orientation
$section = $this->word->createSection(['orientation' => 'landscape']);
4

Kết quả trả về sẽ là

$this->load->library('word');
//our docx will have 'lanscape' paper orientation
$section = $this->word->createSection(['orientation' => 'landscape']);
5

ta cũng có thể truyền một mảng nhiều phần tử:

$this->load->library('word');
//our docx will have 'lanscape' paper orientation
$section = $this->word->createSection(['orientation' => 'landscape']);
6

kết quả

$this->load->library('word');
//our docx will have 'lanscape' paper orientation
$section = $this->word->createSection(['orientation' => 'landscape']);
7

replaceBlock

ta dùng hàm này để sửa 1 nội dung nào đó trong file mẫu

$this->load->library('word');
//our docx will have 'lanscape' paper orientation
$section = $this->word->createSection(['orientation' => 'landscape']);
8
$this->load->library('word');
//our docx will have 'lanscape' paper orientation
$section = $this->word->createSection(['orientation' => 'landscape']);
9

deleteBlock

Xóa một khối nội dung trong văn bản mẫu

// Add text elements
$section->addText('Hello World!');
$section->addTextBreak(1);
  
$section->addText('I am inline styled.', ['name' => 'Verdana', 'color' => '006699']);
$section->addTextBreak(1);
  
$this->word->addFontStyle('rStyle', ['bold' => true, 'italic' => true, 'size' => 16]);
$this->word->addParagraphStyle('pStyle', ['align' => 'center', 'spaceAfter' => 100]);
$section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle');
$section->addText('I have only a paragraph style definition.', null, 'pStyle');
0

cloneRow

Hàm này khá tiện khi trong văn bản mẫu có những nội dung dạng bảng:

// Add text elements
$section->addText('Hello World!');
$section->addTextBreak(1);
  
$section->addText('I am inline styled.', ['name' => 'Verdana', 'color' => '006699']);
$section->addTextBreak(1);
  
$this->word->addFontStyle('rStyle', ['bold' => true, 'italic' => true, 'size' => 16]);
$this->word->addParagraphStyle('pStyle', ['align' => 'center', 'spaceAfter' => 100]);
$section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle');
$section->addText('I have only a paragraph style definition.', null, 'pStyle');
1
// Add text elements
$section->addText('Hello World!');
$section->addTextBreak(1);
  
$section->addText('I am inline styled.', ['name' => 'Verdana', 'color' => '006699']);
$section->addTextBreak(1);
  
$this->word->addFontStyle('rStyle', ['bold' => true, 'italic' => true, 'size' => 16]);
$this->word->addParagraphStyle('pStyle', ['align' => 'center', 'spaceAfter' => 100]);
$section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle');
$section->addText('I have only a paragraph style definition.', null, 'pStyle');
2

Sẽ cho kết quả

// Add text elements
$section->addText('Hello World!');
$section->addTextBreak(1);
  
$section->addText('I am inline styled.', ['name' => 'Verdana', 'color' => '006699']);
$section->addTextBreak(1);
  
$this->word->addFontStyle('rStyle', ['bold' => true, 'italic' => true, 'size' => 16]);
$this->word->addParagraphStyle('pStyle', ['align' => 'center', 'spaceAfter' => 100]);
$section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle');
$section->addText('I have only a paragraph style definition.', null, 'pStyle');
3

cloneRowAndSetValues

cũng như hàm cloneRow tuy nhiên hàm cloneRowAndSetValues có vẻ hữu dụng hơn trong nhiều trường hợp dữ liệu truyền vào là dạng mảng:cloneRow tuy nhiên hàm cloneRowAndSetValues có vẻ hữu dụng hơn trong nhiều trường hợp dữ liệu truyền vào là dạng mảng:

// Add text elements
$section->addText('Hello World!');
$section->addTextBreak(1);
  
$section->addText('I am inline styled.', ['name' => 'Verdana', 'color' => '006699']);
$section->addTextBreak(1);
  
$this->word->addFontStyle('rStyle', ['bold' => true, 'italic' => true, 'size' => 16]);
$this->word->addParagraphStyle('pStyle', ['align' => 'center', 'spaceAfter' => 100]);
$section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle');
$section->addText('I have only a paragraph style definition.', null, 'pStyle');
1
// Add text elements
$section->addText('Hello World!');
$section->addTextBreak(1);
  
$section->addText('I am inline styled.', ['name' => 'Verdana', 'color' => '006699']);
$section->addTextBreak(1);
  
$this->word->addFontStyle('rStyle', ['bold' => true, 'italic' => true, 'size' => 16]);
$this->word->addParagraphStyle('pStyle', ['align' => 'center', 'spaceAfter' => 100]);
$section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle');
$section->addText('I have only a paragraph style definition.', null, 'pStyle');
5

Kết quả sẽ là

// Add text elements
$section->addText('Hello World!');
$section->addTextBreak(1);
  
$section->addText('I am inline styled.', ['name' => 'Verdana', 'color' => '006699']);
$section->addTextBreak(1);
  
$this->word->addFontStyle('rStyle', ['bold' => true, 'italic' => true, 'size' => 16]);
$this->word->addParagraphStyle('pStyle', ['align' => 'center', 'spaceAfter' => 100]);
$section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle');
$section->addText('I have only a paragraph style definition.', null, 'pStyle');
6

Lưu ý: Trong quá trình làm việc với file word có thể là do vô tình hoặc cố ý ta phải xuống dòng ở 1 số nội dung nào đó. Thì ta dùng

// Add image elements
$section->addImage(FCPATH.'/image/_mars.jpg');
$section->addTextBreak(1);
$section->addImage(FCPATH.'/image/_earth.JPG', ['width' => 210, 'height' => 210, 'align' => 'center']);
$section->addTextBreak(1);
$section->addImage(FCPATH.'/image/_mars.jpg', ['width' => 100, 'height' => 100, 'align' => 'right']);
6 không nên dùng
// Add image elements
$section->addImage(FCPATH.'/image/_mars.jpg');
$section->addTextBreak(1);
$section->addImage(FCPATH.'/image/_earth.JPG', ['width' => 210, 'height' => 210, 'align' => 'center']);
$section->addTextBreak(1);
$section->addImage(FCPATH.'/image/_mars.jpg', ['width' => 100, 'height' => 100, 'align' => 'right']);
7,
// Add image elements
$section->addImage(FCPATH.'/image/_mars.jpg');
$section->addTextBreak(1);
$section->addImage(FCPATH.'/image/_earth.JPG', ['width' => 210, 'height' => 210, 'align' => 'center']);
$section->addTextBreak(1);
$section->addImage(FCPATH.'/image/_mars.jpg', ['width' => 100, 'height' => 100, 'align' => 'right']);
8

Kết Luận

Ở bài viết này đã giới thiệu những khái niệm cũng như tính năng của thư viên PHPWord. Còn cách dùng thì tập chung vào phần sử dung PHPWord để tạo file từ một file mẫu có sẵn. Chúc thành công!

Tài liệu tham khảo

PHPWord