-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathPDFMerger.php
259 lines (230 loc) · 7.2 KB
/
PDFMerger.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
<?php
/**
* PDFMerger created by Jarrod Nettles December 2009
* https://pdfmerger.codeplex.com/
* https://github.com/rguedes/PDFMerger
* https://github.com/myokyawhtun/PDFMerger
*
* v1.0.3+
*
* Class for easily merging PDFs (or specific pages of PDFs) together into one. Output to a file, browser, download, or return as a string.
* Unfortunately, this class does not preserve many of the enhancements your original PDF might contain. It treats
* your PDF page as an image and then concatenates them all together.
*
* Note that your PDFs are merged in the order that you provide them using the addPDF function, same as the pages.
* If you put pages 12-14 before 1-5 then 12-15 will be placed first in the output.
*
*
* Uses FPDI 1.6.1 from Setasign
* Uses FPDF 1.8.1 by Olivier Plathey with FPDF_TPL extension 1.1.3 by Setasign
*
* Both of these packages are free and open source software, bundled with this class for ease of use.
* They are not modified in any way. PDFMerger has all the limitations of the FPDI package - essentially, it cannot import dynamic content
* such as form fields, links or page annotations (anything not a part of the page content stream).
*
* Sample usage
*
<?php
include 'PDFMerger.php';
$pdf = new PDFMerger;
$pdf->addPDF('samplepdfs/one.pdf', '1, 3, 4')
->addPDF('samplepdfs/two.pdf', '1-2')
->addPDF('samplepdfs/three.pdf', 'all')
->merge('file', 'samplepdfs/TEST2.pdf');
// REPLACE 'file' WITH 'browser', 'download', 'string', or 'file' for output options
// You do not need to give a file path for browser, string, or download - just the name.
?>
*/
class PDFMerger
{
private $_files; //['form.pdf'] ["1,2,4, 5-19, 22-"]
private $_fpdi;
public $_curpages; // Number of pages in last added file
/**
* Merge PDFs.
* @return void
*/
public
function __construct()
{
if (!class_exists("FPDF"))
{
require_once ('fpdf/fpdf.php');
}
if (!class_exists("FPDI"))
{
require_once ('fpdi/fpdi.php');
}
}
/**
* Add a PDF for inclusion in the merge with a valid file path. Pages should be formatted: 1,3,6, 12-16.
* @param $filepath
* @param $pages
* @return void
* @throws exception
*/
public
function addPDF($filepath, $pages = 'all')
{
if (file_exists($filepath))
{
if (strtolower($pages) != 'all')
{
$fpdi1 = new FPDI;
$count = $fpdi1->setSourceFile($filepath);
$this->_curpages = $count;
$pages = $this->_rewritepages($pages, $count);
unset($fpdi1);
}
$this->_files[] = array(
$filepath,
$pages
);
}
else
{
throw new exception("Could not locate PDF on '$filepath'");
}
return $this;
}
/**
* Merges your provided PDFs and outputs to specified location.
* @param $outputmode
* @param $outputname
* @return PDF
* @throws exception
*/
public
function merge($outputmode = 'browser', $outputpath = 'newfile.pdf')
{
if (!isset($this->_files) || !is_array($this->_files)):
throw new exception("No PDFs to merge.");
endif;
$fpdi = new FPDI;
// merger operations
foreach($this->_files as $fkey => $file)
{
$filename = $file[0];
$filepages = $file[1];
$count = $fpdi->setSourceFile($filename);
$this->_files[$fkey][2] = $count;
// add the pages
if ($filepages == 'all')
{
for ($i = 1; $i <= $count; $i++)
{
$template = $fpdi->importPage($i);
$size = $fpdi->getTemplateSize($template);
$orientation = ($size['h'] > $size['w']) ? 'P' : 'L';
$fpdi->AddPage($orientation, array(
$size['w'],
$size['h']
));
$fpdi->useTemplate($template);
}
}
else
{
foreach($filepages as $page)
{
if (!$template = $fpdi->importPage($page)):
throw new exception("Could not load page '$page' in PDF '$filename'. Check that the page exists.");
endif;
$size = $fpdi->getTemplateSize($template);
$orientation = ($size['h'] > $size['w']) ? 'P' : 'L';
$fpdi->AddPage($orientation, array(
$size['w'],
$size['h']
));
$fpdi->useTemplate($template);
}
}
}
// output operations
$mode = $this->_switchmode($outputmode);
if ($mode == 'S')
{
return $fpdi->Output($outputpath, 'S');
}
else
{
if ($fpdi->Output($outputpath, $mode) == '')
{
return true;
}
else
{
throw new exception("Error outputting PDF to '$outputmode'.");
return false;
}
}
}
/**
* FPDI uses single characters for specifying the output location.
* Change our more descriptive string into proper format.
* @param $mode
* @return Character
* executed at fpdf::Output()
*/
private
function _switchmode($mode)
{
switch (strtolower($mode))
{
case 'download':
return 'D'; // Download
break;
case 'browser':
return 'I'; // Inline In Browser
break;
case 'file':
return 'F'; // Save As Local File
break;
case 'string':
return 'S'; // As String
break;
default:
return 'I';
break;
}
}
/**
* Takes our provided pages in the form of 1,3,4,16-50,70- and creates an array of all pages
* @param $pages
* @param $numpages is total number of pages in file
* @return array
* @throws exception
*/
private
function _rewritepages($pages, $numpages = 0)
{
$pages = str_replace(' ', '', $pages);
$part = explode(',', $pages);
// parse hyphens
foreach($part as $i)
{
$ind = explode('-', $i);
if (count($ind) == 2)
{
$x = $ind[0]; //start page
$y = $ind[1]; //end page
if (strlen(trim($y)) == 0) $y = $numpages;
if ($x > $y):
throw new exception("Starting page, '$x' is greater than ending page '$y'.");
return false;
endif;
// add middle pages
while ($x <= $y):
$newpages[] = (int)$x;
$x++;
endwhile;
}
else
{
$newpages[] = (int)$ind[0];
}
}
return $newpages;
}
}