aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--composer.json7
-rw-r--r--composer.lock49
-rw-r--r--inc/3rdparty/libraries/PHPePub/EPub.HtmlEntities.php266
-rw-r--r--inc/3rdparty/libraries/PHPePub/EPub.NCX.php782
-rw-r--r--inc/3rdparty/libraries/PHPePub/EPub.OPF.php1226
-rw-r--r--inc/3rdparty/libraries/PHPePub/EPub.php2438
-rw-r--r--inc/3rdparty/libraries/PHPePub/EPubChapterSplitter.php201
-rw-r--r--inc/3rdparty/libraries/PHPePub/Logger.php92
-rw-r--r--inc/3rdparty/libraries/PHPePub/Zip.php818
-rw-r--r--inc/3rdparty/libraries/PHPePub/lib.uuid.LICENCE.txt31
-rw-r--r--inc/3rdparty/libraries/PHPePub/lib.uuid.php314
-rwxr-xr-xinc/poche/global.inc.php11
12 files changed, 54 insertions, 6181 deletions
diff --git a/composer.json b/composer.json
index d350f1d1..7f0a75ea 100644
--- a/composer.json
+++ b/composer.json
@@ -34,6 +34,10 @@
34 { 34 {
35 "type": "vcs", 35 "type": "vcs",
36 "url": "https://github.com/wallabag/pagination" 36 "url": "https://github.com/wallabag/pagination"
37 },
38 {
39 "type": "vcs",
40 "url": "https://github.com/wallabag/PHPePub"
37 } 41 }
38 ], 42 ],
39 "require": { 43 "require": {
@@ -43,10 +47,11 @@
43 "fabpot/goutte": "2.0.*@dev", 47 "fabpot/goutte": "2.0.*@dev",
44 "ezyang/htmlpurifier": "dev-master", 48 "ezyang/htmlpurifier": "dev-master",
45 "mgargano/simplehtmldom": "dev-master", 49 "mgargano/simplehtmldom": "dev-master",
50 "robmorgan/phinx": "*",
46 "wallabag/PHP-Flash-Messages": "dev-master", 51 "wallabag/PHP-Flash-Messages": "dev-master",
47 "wallabag/kriss_php5": "dev-master", 52 "wallabag/kriss_php5": "dev-master",
48 "wallabag/pagination": "dev-master", 53 "wallabag/pagination": "dev-master",
49 "robmorgan/phinx": "*" 54 "wallabag/PHPePub": "dev-master"
50 }, 55 },
51 "require-dev": { 56 "require-dev": {
52 "phpunit/phpunit": "~3.7" 57 "phpunit/phpunit": "~3.7"
diff --git a/composer.lock b/composer.lock
index 64f86e3d..b1a864b9 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
4 "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 4 "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 "This file is @generated automatically" 5 "This file is @generated automatically"
6 ], 6 ],
7 "hash": "256d4b68ab2de1b3aa0dea820f3acdb0", 7 "hash": "376dd2761a2a44043b834a7cb5897e37",
8 "packages": [ 8 "packages": [
9 { 9 {
10 "name": "ezyang/htmlpurifier", 10 "name": "ezyang/htmlpurifier",
@@ -1596,6 +1596,50 @@
1596 "time": "2013-02-14 16:41:48" 1596 "time": "2013-02-14 16:41:48"
1597 }, 1597 },
1598 { 1598 {
1599 "name": "wallabag/PHPePub",
1600 "version": "dev-master",
1601 "source": {
1602 "type": "git",
1603 "url": "https://github.com/wallabag/PHPePub.git",
1604 "reference": "7c78733d33344308520758d7f3f7bc2cc51b3512"
1605 },
1606 "dist": {
1607 "type": "zip",
1608 "url": "https://api.github.com/repos/wallabag/PHPePub/zipball/7c78733d33344308520758d7f3f7bc2cc51b3512",
1609 "reference": "7c78733d33344308520758d7f3f7bc2cc51b3512",
1610 "shasum": ""
1611 },
1612 "require": {
1613 "php": ">=5.3.0"
1614 },
1615 "type": "library",
1616 "autoload": {
1617 "classmap": [
1618 "EPub.php",
1619 "EPub.HtmlEntities.php",
1620 "EPub.NCX.php",
1621 "EPub.OPF.php",
1622 "EPubChapterSplitter.php",
1623 "lib.uuid.php",
1624 "Logger.php",
1625 "Zip.php"
1626 ]
1627 },
1628 "authors": [
1629 {
1630 "name": "Nicolas Lœuillet",
1631 "email": "nicolas@loeuillet.org",
1632 "homepage": "http://www.cdetc.fr"
1633 }
1634 ],
1635 "description": "PHP Classes for dynamically generating EPub files.",
1636 "homepage": "https://github.com/wallabag/PHPePub",
1637 "support": {
1638 "source": "https://github.com/wallabag/PHPePub/tree/master"
1639 },
1640 "time": "2015-01-19 11:44:19"
1641 },
1642 {
1599 "name": "wallabag/kriss_php5", 1643 "name": "wallabag/kriss_php5",
1600 "version": "dev-master", 1644 "version": "dev-master",
1601 "source": { 1645 "source": {
@@ -2092,7 +2136,8 @@
2092 "mgargano/simplehtmldom": 20, 2136 "mgargano/simplehtmldom": 20,
2093 "wallabag/php-flash-messages": 20, 2137 "wallabag/php-flash-messages": 20,
2094 "wallabag/kriss_php5": 20, 2138 "wallabag/kriss_php5": 20,
2095 "wallabag/pagination": 20 2139 "wallabag/pagination": 20,
2140 "wallabag/phpepub": 20
2096 }, 2141 },
2097 "prefer-stable": false, 2142 "prefer-stable": false,
2098 "prefer-lowest": false, 2143 "prefer-lowest": false,
diff --git a/inc/3rdparty/libraries/PHPePub/EPub.HtmlEntities.php b/inc/3rdparty/libraries/PHPePub/EPub.HtmlEntities.php
deleted file mode 100644
index 376b6133..00000000
--- a/inc/3rdparty/libraries/PHPePub/EPub.HtmlEntities.php
+++ /dev/null
@@ -1,266 +0,0 @@
1<?php
2/**
3 * This should be a complete list of all HTML entities, mapped to their UTF-8 character codes.
4 *
5 * @author A. Grandt
6 * @copyright A. Grandt 2009-2013
7 * @license GNU LGPL, Attribution required for commercial implementations, requested for everything else.
8 * @version 3.00
9 */
10global $htmlEntities;
11$htmlEntities = array();
12
13$htmlEntities["&quot;"] ="\x22"; // &#34; ((double) quotation mark)
14$htmlEntities["&amp;"] ="\x26"; // &#38; (ampersand)
15$htmlEntities["&apos;"] ="\x27"; // &#39; (apostrophe = apostrophe-quote)
16$htmlEntities["&lt;"] ="\x3C"; // &#60; (less-than sign)
17$htmlEntities["&gt;"] ="\x3E"; // &#62; (greater-than sign)
18$htmlEntities["&nbsp;"] ="\xC2\xA0"; // &#160; (non-breaking space)
19$htmlEntities["&iexcl;"] ="\xC2\xA1"; // &#161; (inverted exclamation mark)
20$htmlEntities["&cent;"] ="\xC2\xA2"; // &#162; (cent)
21$htmlEntities["&pound;"] ="\xC2\xA3"; // &#163; (pound)
22$htmlEntities["&curren;"] ="\xC2\xA4"; // &#164; (currency)
23$htmlEntities["&yen;"] ="\xC2\xA5"; // &#165; (yen)
24$htmlEntities["&brvbar;"] ="\xC2\xA6"; // &#166; (broken vertical bar)
25$htmlEntities["&sect;"] ="\xC2\xA7"; // &#167; (section)
26$htmlEntities["&uml;"] ="\xC2\xA8"; // &#168; (spacing diaeresis)
27$htmlEntities["&copy;"] ="\xC2\xA9"; // &#169; (copyright)
28$htmlEntities["&ordf;"] ="\xC2\xAA"; // &#170; (feminine ordinal indicator)
29$htmlEntities["&laquo;"] ="\xC2\xAB"; // &#171; (angle quotation mark (left))
30$htmlEntities["&not;"] ="\xC2\xAC"; // &#172; (negation)
31$htmlEntities["&shy;"] ="\xC2\xAD"; // &#173; (soft hyphen)
32$htmlEntities["&reg;"] ="\xC2\xAE"; // &#174; (registered trademark)
33$htmlEntities["&macr;"] ="\xC2\xAF"; // &#175; (spacing macron)
34$htmlEntities["&deg;"] ="\xC2\xB0"; // &#176; (degree)
35$htmlEntities["&plusmn;"] ="\xC2\xB1"; // &#177; (plus-or-minus)
36$htmlEntities["&sup2;"] ="\xC2\xB2"; // &#178; (superscript 2)
37$htmlEntities["&sup3;"] ="\xC2\xB3"; // &#179; (superscript 3)
38$htmlEntities["&acute;"] ="\xC2\xB4"; // &#180; (spacing acute)
39$htmlEntities["&micro;"] ="\xC2\xB5"; // &#181; (micro)
40$htmlEntities["&para;"] ="\xC2\xB6"; // &#182; (paragraph)
41$htmlEntities["&middot;"] ="\xC2\xB7"; // &#183; (middle dot)
42$htmlEntities["&cedil;"] ="\xC2\xB8"; // &#184; (spacing cedilla)
43$htmlEntities["&sup1;"] ="\xC2\xB9"; // &#185; (superscript 1)
44$htmlEntities["&ordm;"] ="\xC2\xBA"; // &#186; (masculine ordinal indicator)
45$htmlEntities["&raquo;"] ="\xC2\xBB"; // &#187; (angle quotation mark (right))
46$htmlEntities["&frac14;"] ="\xC2\xBC"; // &#188; (fraction 1/4)
47$htmlEntities["&frac12;"] ="\xC2\xBD"; // &#189; (fraction 1/2)
48$htmlEntities["&frac34;"] ="\xC2\xBE"; // &#190; (fraction 3/4)
49$htmlEntities["&iquest;"] ="\xC2\xBF"; // &#191; (inverted question mark)
50$htmlEntities["&Agrave;"] ="\xC3\x80"; // &#192; (capital a, grave accent)
51$htmlEntities["&Aacute;"] ="\xC3\x81"; // &#193; (capital a, acute accent)
52$htmlEntities["&Acirc;"] ="\xC3\x82"; // &#194; (capital a, circumflex accent)
53$htmlEntities["&Atilde;"] ="\xC3\x83"; // &#195; (capital a, tilde)
54$htmlEntities["&Auml;"] ="\xC3\x84"; // &#196; (capital a, umlaut mark)
55$htmlEntities["&Aring;"] ="\xC3\x85"; // &#197; (capital a, ring)
56$htmlEntities["&AElig;"] ="\xC3\x86"; // &#198; (capital ae)
57$htmlEntities["&Ccedil;"] ="\xC3\x87"; // &#199; (capital c, cedilla)
58$htmlEntities["&Egrave;"] ="\xC3\x88"; // &#200; (capital e, grave accent)
59$htmlEntities["&Eacute;"] ="\xC3\x89"; // &#201; (capital e, acute accent)
60$htmlEntities["&Ecirc;"] ="\xC3\x8A"; // &#202; (capital e, circumflex accent)
61$htmlEntities["&Euml;"] ="\xC3\x8B"; // &#203; (capital e, umlaut mark)
62$htmlEntities["&Igrave;"] ="\xC3\x8C"; // &#204; (capital i, grave accent)
63$htmlEntities["&Iacute;"] ="\xC3\x8D"; // &#205; (capital i, acute accent)
64$htmlEntities["&Icirc;"] ="\xC3\x8E"; // &#206; (capital i, circumflex accent)
65$htmlEntities["&Iuml;"] ="\xC3\x8F"; // &#207; (capital i, umlaut mark)
66$htmlEntities["&ETH;"] ="\xC3\x90"; // &#208; (capital eth, Icelandic)
67$htmlEntities["&Ntilde;"] ="\xC3\x91"; // &#209; (capital n, tilde)
68$htmlEntities["&Ograve;"] ="\xC3\x92"; // &#210; (capital o, grave accent)
69$htmlEntities["&Oacute;"] ="\xC3\x93"; // &#211; (capital o, acute accent)
70$htmlEntities["&Ocirc;"] ="\xC3\x94"; // &#212; (capital o, circumflex accent)
71$htmlEntities["&Otilde;"] ="\xC3\x95"; // &#213; (capital o, tilde)
72$htmlEntities["&Ouml;"] ="\xC3\x96"; // &#214; (capital o, umlaut mark)
73$htmlEntities["&times;"] ="\xC3\x97"; // &#215; (multiplication)
74$htmlEntities["&Oslash;"] ="\xC3\x98"; // &#216; (capital o, slash)
75$htmlEntities["&Ugrave;"] ="\xC3\x99"; // &#217; (capital u, grave accent)
76$htmlEntities["&Uacute;"] ="\xC3\x9A"; // &#218; (capital u, acute accent)
77$htmlEntities["&Ucirc;"] ="\xC3\x9B"; // &#219; (capital u, circumflex accent)
78$htmlEntities["&Uuml;"] ="\xC3\x9C"; // &#220; (capital u, umlaut mark)
79$htmlEntities["&Yacute;"] ="\xC3\x9D"; // &#221; (capital y, acute accent)
80$htmlEntities["&THORN;"] ="\xC3\x9E"; // &#222; (capital THORN, Icelandic)
81$htmlEntities["&szlig;"] ="\xC3\x9F"; // &#223; (small sharp s, German)
82$htmlEntities["&agrave;"] ="\xC3\xA0"; // &#224; (small a, grave accent)
83$htmlEntities["&aacute;"] ="\xC3\xA1"; // &#225; (small a, acute accent)
84$htmlEntities["&acirc;"] ="\xC3\xA2"; // &#226; (small a, circumflex accent)
85$htmlEntities["&atilde;"] ="\xC3\xA3"; // &#227; (small a, tilde)
86$htmlEntities["&auml;"] ="\xC3\xA4"; // &#228; (small a, umlaut mark)
87$htmlEntities["&aring;"] ="\xC3\xA5"; // &#229; (small a, ring)
88$htmlEntities["&aelig;"] ="\xC3\xA6"; // &#230; (small ae)
89$htmlEntities["&ccedil;"] ="\xC3\xA7"; // &#231; (small c, cedilla)
90$htmlEntities["&egrave;"] ="\xC3\xA8"; // &#232; (small e, grave accent)
91$htmlEntities["&eacute;"] ="\xC3\xA9"; // &#233; (small e, acute accent)
92$htmlEntities["&ecirc;"] ="\xC3\xAA"; // &#234; (small e, circumflex accent)
93$htmlEntities["&euml;"] ="\xC3\xAB"; // &#235; (small e, umlaut mark)
94$htmlEntities["&igrave;"] ="\xC3\xAC"; // &#236; (small i, grave accent)
95$htmlEntities["&iacute;"] ="\xC3\xAD"; // &#237; (small i, acute accent)
96$htmlEntities["&icirc;"] ="\xC3\xAE"; // &#238; (small i, circumflex accent)
97$htmlEntities["&iuml;"] ="\xC3\xAF"; // &#239; (small i, umlaut mark)
98$htmlEntities["&eth;"] ="\xC3\xB0"; // &#240; (small eth, Icelandic)
99$htmlEntities["&ntilde;"] ="\xC3\xB1"; // &#241; (small n, tilde)
100$htmlEntities["&ograve;"] ="\xC3\xB2"; // &#242; (small o, grave accent)
101$htmlEntities["&oacute;"] ="\xC3\xB3"; // &#243; (small o, acute accent)
102$htmlEntities["&ocirc;"] ="\xC3\xB4"; // &#244; (small o, circumflex accent)
103$htmlEntities["&otilde;"] ="\xC3\xB5"; // &#245; (small o, tilde)
104$htmlEntities["&ouml;"] ="\xC3\xB6"; // &#246; (small o, umlaut mark)
105$htmlEntities["&divide;"] ="\xC3\xB7"; // &#247; (division)
106$htmlEntities["&oslash;"] ="\xC3\xB8"; // &#248; (small o, slash)
107$htmlEntities["&ugrave;"] ="\xC3\xB9"; // &#249; (small u, grave accent)
108$htmlEntities["&uacute;"] ="\xC3\xBA"; // &#250; (small u, acute accent)
109$htmlEntities["&ucirc;"] ="\xC3\xBB"; // &#251; (small u, circumflex accent)
110$htmlEntities["&uuml;"] ="\xC3\xBC"; // &#252; (small u, umlaut mark)
111$htmlEntities["&yacute;"] ="\xC3\xBD"; // &#253; (small y, acute accent)
112$htmlEntities["&thorn;"] ="\xC3\xBE"; // &#254; (small thorn, Icelandic)
113$htmlEntities["&yuml;"] ="\xC3\xBF"; // &#255; (small y, umlaut mark)
114$htmlEntities["&OElig;"] ="\xC5\x92"; // &#338; (capital ligature OE)
115$htmlEntities["&oelig;"] ="\xC5\x93"; // &#339; (small ligature oe)
116$htmlEntities["&Scaron;"] ="\xC5\xA0"; // &#352; (capital S with caron)
117$htmlEntities["&scaron;"] ="\xC5\xA1"; // &#353; (small S with caron)
118$htmlEntities["&Yuml;"] ="\xC5\xB8"; // &#376; (capital Y with diaeres)
119$htmlEntities["&fnof;"] ="\xC6\x92"; // &#402; (f with hook)
120$htmlEntities["&circ;"] ="\xCB\x86"; // &#710; (modifier letter circumflex accent)
121$htmlEntities["&tilde;"] ="\xCB\x9C"; // &#732; (small tilde)
122$htmlEntities["&Alpha;"] ="\xCE\x91"; // &#913; (Alpha)
123$htmlEntities["&Beta;"] ="\xCE\x92"; // &#914; (Beta)
124$htmlEntities["&Gamma;"] ="\xCE\x93"; // &#915; (Gamma)
125$htmlEntities["&Delta;"] ="\xCE\x94"; // &#916; (Delta)
126$htmlEntities["&Epsilon;"] ="\xCE\x95"; // &#917; (Epsilon)
127$htmlEntities["&Zeta;"] ="\xCE\x96"; // &#918; (Zeta)
128$htmlEntities["&Eta;"] ="\xCE\x97"; // &#919; (Eta)
129$htmlEntities["&Theta;"] ="\xCE\x98"; // &#920; (Theta)
130$htmlEntities["&Iota;"] ="\xCE\x99"; // &#921; (Iota)
131$htmlEntities["&Kappa;"] ="\xCE\x9A"; // &#922; (Kappa)
132$htmlEntities["&Lambda;"] ="\xCE\x9B"; // &#923; (Lambda)
133$htmlEntities["&Mu;"] ="\xCE\x9C"; // &#924; (Mu)
134$htmlEntities["&Nu;"] ="\xCE\x9D"; // &#925; (Nu)
135$htmlEntities["&Xi;"] ="\xCE\x9E"; // &#926; (Xi)
136$htmlEntities["&Omicron;"] ="\xCE\x9F"; // &#927; (Omicron)
137$htmlEntities["&Pi;"] ="\xCE\xA0"; // &#928; (Pi)
138$htmlEntities["&Rho;"] ="\xCE\xA1"; // &#929; (Rho)
139$htmlEntities["&Sigma;"] ="\xCE\xA3"; // &#931; (Sigma)
140$htmlEntities["&Tau;"] ="\xCE\xA4"; // &#932; (Tau)
141$htmlEntities["&Upsilon;"] ="\xCE\xA5"; // &#933; (Upsilon)
142$htmlEntities["&Phi;"] ="\xCE\xA6"; // &#934; (Phi)
143$htmlEntities["&Chi;"] ="\xCE\xA7"; // &#935; (Chi)
144$htmlEntities["&Psi;"] ="\xCE\xA8"; // &#936; (Psi)
145$htmlEntities["&Omega;"] ="\xCE\xA9"; // &#937; (Omega)
146$htmlEntities["&alpha;"] ="\xCE\xB1"; // &#945; (alpha)
147$htmlEntities["&beta;"] ="\xCE\xB2"; // &#946; (beta)
148$htmlEntities["&gamma;"] ="\xCE\xB3"; // &#947; (gamma)
149$htmlEntities["&delta;"] ="\xCE\xB4"; // &#948; (delta)
150$htmlEntities["&epsilon;"] ="\xCE\xB5"; // &#949; (epsilon)
151$htmlEntities["&zeta;"] ="\xCE\xB6"; // &#950; (zeta)
152$htmlEntities["&eta;"] ="\xCE\xB7"; // &#951; (eta)
153$htmlEntities["&theta;"] ="\xCE\xB8"; // &#952; (theta)
154$htmlEntities["&iota;"] ="\xCE\xB9"; // &#953; (iota)
155$htmlEntities["&kappa;"] ="\xCE\xBA"; // &#954; (kappa)
156$htmlEntities["&lambda;"] ="\xCE\xBB"; // &#955; (lambda)
157$htmlEntities["&mu;"] ="\xCE\xBC"; // &#956; (mu)
158$htmlEntities["&nu;"] ="\xCE\xBD"; // &#957; (nu)
159$htmlEntities["&xi;"] ="\xCE\xBE"; // &#958; (xi)
160$htmlEntities["&omicron;"] ="\xCE\xBF"; // &#959; (omicron)
161$htmlEntities["&pi;"] ="\xCF\x80"; // &#960; (pi)
162$htmlEntities["&rho;"] ="\xCF\x81"; // &#961; (rho)
163$htmlEntities["&sigmaf;"] ="\xCF\x82"; // &#962; (sigmaf)
164$htmlEntities["&sigma;"] ="\xCF\x83"; // &#963; (sigma)
165$htmlEntities["&tau;"] ="\xCF\x84"; // &#964; (tau)
166$htmlEntities["&upsilon;"] ="\xCF\x85"; // &#965; (upsilon)
167$htmlEntities["&phi;"] ="\xCF\x86"; // &#966; (phi)
168$htmlEntities["&chi;"] ="\xCF\x87"; // &#967; (chi)
169$htmlEntities["&psi;"] ="\xCF\x88"; // &#968; (psi)
170$htmlEntities["&omega;"] ="\xCF\x89"; // &#969; (omega)
171$htmlEntities["&thetasym;"] ="\xCF\x91"; // &#977; (theta symbol)
172$htmlEntities["&upsih;"] ="\xCF\x92"; // &#978; (upsilon symbol)
173$htmlEntities["&piv;"] ="\xCF\x96"; // &#982; (pi symbol)
174$htmlEntities["&ensp;"] ="\xE2\x80\x82"; // &#8194; (en space)
175$htmlEntities["&emsp;"] ="\xE2\x80\x83"; // &#8195; (em space)
176$htmlEntities["&thinsp;"] ="\xE2\x80\x89"; // &#8201; (thin space)
177$htmlEntities["&zwnj;"] ="‌\xE2\x80\x8C"; // &#8204; (zero width non-joiner)
178$htmlEntities["&zwj;"] ="\xE2\x80\x8D‍"; // &#8205; (zero width joiner)
179$htmlEntities["&lrm;"] ="‎\xE2\x80\x8E"; // &#8206; (left-to-right mark)
180$htmlEntities["&rlm;"] ="\xE2\x80\x8F"; // &#8207; (right-to-left mark)
181$htmlEntities["&ndash;"] ="\xE2\x80\x93"; // &#8211; (en dash)
182$htmlEntities["&mdash;"] ="\xE2\x80\x94"; // &#8212; (em dash)
183$htmlEntities["&lsquo;"] ="\xE2\x80\x98"; // &#8216; (left single quotation mark)
184$htmlEntities["&rsquo;"] ="\xE2\x80\x99"; // &#8217; (right single quotation mark)
185$htmlEntities["&sbquo;"] ="\xE2\x80\x9A"; // &#8218; (single low-9 quotation mark)
186$htmlEntities["&ldquo;"] ="\xE2\x80\x9C"; // &#8220; (left double quotation mark)
187$htmlEntities["&rdquo;"] ="\xE2\x80\x9D"; // &#8221; (right double quotation mark)
188$htmlEntities["&bdquo;"] ="\xE2\x80\x9E"; // &#8222; (double low-9 quotation mark)
189$htmlEntities["&dagger;"] ="\xE2\x80\xA0"; // &#8224; (dagger)
190$htmlEntities["&Dagger;"] ="\xE2\x80\xA1"; // &#8225; (double dagger)
191$htmlEntities["&bull;"] ="\xE2\x80\xA2"; // &#8226; (bullet)
192$htmlEntities["&hellip;"] ="\xE2\x80\xA6"; // &#8230; (horizontal ellipsis)
193$htmlEntities["&permil;"] ="\xE2\x80\xB0"; // &#8240; (per mille)
194$htmlEntities["&prime;"] ="\xE2\x80\xB2"; // &#8242; (minutes or prime)
195$htmlEntities["&Prime;"] ="\xE2\x80\xB3"; // &#8243; (seconds or Double Prime)
196$htmlEntities["&lsaquo;"] ="\xE2\x80\xB9"; // &#8249; (single left angle quotation)
197$htmlEntities["&rsaquo;"] ="\xE2\x80\xBA"; // &#8250; (single right angle quotation)
198$htmlEntities["&oline;"] ="\xE2\x80\xBE"; // &#8254; (overline)
199$htmlEntities["&frasl;"] ="\xE2\x81\x84"; // &#8260; (fraction slash)
200$htmlEntities["&euro;"] ="\xE2\x82\xAC"; // &#8364; (euro)
201$htmlEntities["&image;"] ="\xE2\x84\x91"; // &#8465; (blackletter capital I)
202$htmlEntities["&weierp;"] ="\xE2\x84\x98"; // &#8472; (script capital P)
203$htmlEntities["&real;"] ="\xE2\x84\x9C"; // &#8476; (blackletter capital R)
204$htmlEntities["&trade;"] ="\xE2\x84\xA2"; // &#8482; (trademark)
205$htmlEntities["&alefsym;"] ="\xE2\x84\xB5"; // &#8501; (alef)
206$htmlEntities["&larr;"] ="\xE2\x86\x90"; // &#8592; (left arrow)
207$htmlEntities["&uarr;"] ="\xE2\x86\x91"; // &#8593; (up arrow)
208$htmlEntities["&rarr;"] ="\xE2\x86\x92"; // &#8594; (right arrow)
209$htmlEntities["&darr;"] ="\xE2\x86\x93"; // &#8595; (down arrow)
210$htmlEntities["&harr;"] ="\xE2\x86\x94"; // &#8596; (left right arrow)
211$htmlEntities["&crarr;"] ="\xE2\x86\xB5"; // &#8629; (carriage return arrow)
212$htmlEntities["&lArr;"] ="\xE2\x87\x90"; // &#8656; (left double arrow)
213$htmlEntities["&uArr;"] ="\xE2\x87\x91"; // &#8657; (up double arrow)
214$htmlEntities["&rArr;"] ="\xE2\x87\x92"; // &#8658; (right double arrow)
215$htmlEntities["&dArr;"] ="\xE2\x87\x93"; // &#8659; (down double arrow)
216$htmlEntities["&hArr;"] ="\xE2\x87\x94"; // &#8660; (left right double arrow)
217$htmlEntities["&forall;"] ="\xE2\x88\x80"; // &#8704; (for all)
218$htmlEntities["&part;"] ="\xE2\x88\x82"; // &#8706; (partial differential)
219$htmlEntities["&exist;"] ="\xE2\x88\x83"; // &#8707; (there exists)
220$htmlEntities["&empty;"] ="\xE2\x88\x85"; // &#8709; (empty set)
221$htmlEntities["&nabla;"] ="\xE2\x88\x87"; // &#8711; (backward difference)
222$htmlEntities["&isin;"] ="\xE2\x88\x88"; // &#8712; (element of)
223$htmlEntities["&notin;"] ="\xE2\x88\x89"; // &#8713; (not an element of)
224$htmlEntities["&ni;"] ="\xE2\x88\x8B"; // &#8715; (ni = contains as member)
225$htmlEntities["&prod;"] ="\xE2\x88\x8F"; // &#8719; (n-ary product)
226$htmlEntities["&sum;"] ="\xE2\x88\x91"; // &#8721; (n-ary sumation)
227$htmlEntities["&minus;"] ="\xE2\x88\x92"; // &#8722; (minus)
228$htmlEntities["&lowast;"] ="\xE2\x88\x97"; // &#8727; (asterisk operator)
229$htmlEntities["&radic;"] ="\xE2\x88\x9A"; // &#8730; (square root)
230$htmlEntities["&prop;"] ="\xE2\x88\x9D"; // &#8733; (proportional to)
231$htmlEntities["&infin;"] ="\xE2\x88\x9E"; // &#8734; (infinity)
232$htmlEntities["&ang;"] ="\xE2\x88\xA0"; // &#8736; (angle)
233$htmlEntities["&and;"] ="\xE2\x88\xA7"; // &#8743; (logical and)
234$htmlEntities["&or;"] ="\xE2\x88\xA8"; // &#8744; (logical or)
235$htmlEntities["&cap;"] ="\xE2\x88\xA9"; // &#8745; (intersection)
236$htmlEntities["&cup;"] ="\xE2\x88\xAA"; // &#8746; (union)
237$htmlEntities["&int;"] ="\xE2\x88\xAB"; // &#8747; (integral)
238$htmlEntities["&there4;"] ="\xE2\x88\xB4"; // &#8756; (therefore)
239$htmlEntities["&sim;"] ="\xE2\x88\xBC"; // &#8764; (similar to)
240$htmlEntities["&cong;"] ="\xE2\x89\x85"; // &#8773; (congruent to)
241$htmlEntities["&asymp;"] ="\xE2\x89\x88"; // &#8776; (approximately equal)
242$htmlEntities["&ne;"] ="\xE2\x89\xA0"; // &#8800; (not equal)
243$htmlEntities["&equiv;"] ="\xE2\x89\xA1"; // &#8801; (equivalent)
244$htmlEntities["&le;"] ="\xE2\x89\xA4"; // &#8804; (less or equal)
245$htmlEntities["&ge;"] ="\xE2\x89\xA5"; // &#8805; (greater or equal)
246$htmlEntities["&sub;"] ="\xE2\x8A\x82"; // &#8834; (subset of)
247$htmlEntities["&sup;"] ="\xE2\x8A\x83"; // &#8835; (superset of)
248$htmlEntities["&nsub;"] ="\xE2\x8A\x84"; // &#8836; (not subset of)
249$htmlEntities["&sube;"] ="\xE2\x8A\x86"; // &#8838; (subset or equal)
250$htmlEntities["&supe;"] ="\xE2\x8A\x87"; // &#8839; (superset or equal)
251$htmlEntities["&oplus;"] ="\xE2\x8A\x95"; // &#8853; (circled plus)
252$htmlEntities["&otimes;"] ="\xE2\x8A\x87"; // &#8855; (circled times)
253$htmlEntities["&perp;"] ="\xE2\x8A\xA5"; // &#8869; (perpendicular)
254$htmlEntities["&sdot;"] ="\xE2\x8C\x85"; // &#8901; (dot operator)
255$htmlEntities["&lceil;"] ="\xE2\x8C\x88"; // &#8968; (left ceiling)
256$htmlEntities["&rceil;"] ="\xE2\x8C\x89"; // &#8969; (right ceiling)
257$htmlEntities["&lfloor;"] ="\xE2\x8C\x8A"; // &#8970; (left floor)
258$htmlEntities["&rfloor;"] ="\xE2\x8C\x8B"; // &#8971; (right floor)
259$htmlEntities["&lang;"] ="\xE2\x8C\xA9"; // &#9001; (left angle bracket = bra)
260$htmlEntities["&rang;"] ="\xE2\x8C\xAA"; // &#9002; (right angle bracket = ket)
261$htmlEntities["&loz;"] ="\xE2\x97\x8A"; // &#9674; (lozenge)
262$htmlEntities["&spades;"] ="\xE2\x99\xA0"; // &#9824; (spade)
263$htmlEntities["&clubs;"] ="\xE2\x99\xA3"; // &#9827; (club)
264$htmlEntities["&hearts;"] ="\xE2\x99\xA5"; // &#9829; (heart)
265$htmlEntities["&diams;"] ="\xE2\x99\xA6"; // &#9830; (diamond)
266?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/PHPePub/EPub.NCX.php b/inc/3rdparty/libraries/PHPePub/EPub.NCX.php
deleted file mode 100644
index e5da05cd..00000000
--- a/inc/3rdparty/libraries/PHPePub/EPub.NCX.php
+++ /dev/null
@@ -1,782 +0,0 @@
1<?php
2/**
3 * ePub NCX file structure
4 *
5 * @author A. Grandt <php@grandt.com>
6 * @copyright 2009-2014 A. Grandt
7 * @license GNU LGPL, Attribution required for commercial implementations, requested for everything else.
8 * @version 3.20
9 */
10class Ncx {
11 const _VERSION = 3.20;
12
13 const MIMETYPE = "application/x-dtbncx+xml";
14
15 private $bookVersion = EPub::BOOK_VERSION_EPUB2;
16
17 private $navMap = NULL;
18 private $uid = NULL;
19 private $meta = array();
20 private $docTitle = NULL;
21 private $docAuthor = NULL;
22
23 private $currentLevel = NULL;
24 private $lastLevel = NULL;
25
26 private $languageCode = "en";
27 private $writingDirection = EPub::DIRECTION_LEFT_TO_RIGHT;
28
29 public $chapterList = array();
30 public $referencesTitle = "Guide";
31 public $referencesClass = "references";
32 public $referencesId = "references";
33 public $referencesList = array();
34 public $referencesName = array();
35 public $referencesOrder = NULL;
36
37 /**
38 * Class constructor.
39 *
40 * @param string $uid
41 * @param string $docTitle
42 * @param string $docAuthor
43 * @param string $languageCode
44 * @param string $writingDirection
45 */
46 function __construct($uid = NULL, $docTitle = NULL, $docAuthor = NULL, $languageCode = "en", $writingDirection = EPub::DIRECTION_LEFT_TO_RIGHT) {
47 $this->navMap = new NavMap($writingDirection);
48 $this->currentLevel = $this->navMap;
49 $this->setUid($uid);
50 $this->setDocTitle($docTitle);
51 $this->setDocAuthor($docAuthor);
52 $this->setLanguageCode($languageCode);
53 $this->setWritingDirection($writingDirection);
54 }
55
56 /**
57 * Class destructor
58 *
59 * @return void
60 */
61 function __destruct() {
62 unset($this->bookVersion, $this->navMap, $this->uid, $this->meta);
63 unset($this->docTitle, $this->docAuthor, $this->currentLevel, $this->lastLevel);
64 unset($this->languageCode, $this->writingDirection, $this->chapterList, $this->referencesTitle);
65 unset($this->referencesClass, $this->referencesId, $this->referencesList, $this->referencesName);
66 unset($this->referencesOrder);
67 }
68
69 /**
70 *
71 * Enter description here ...
72 *
73 * @param string $bookVersion
74 */
75 function setVersion($bookVersion) {
76 $this->bookVersion = is_string($bookVersion) ? trim($bookVersion) : EPub::BOOK_VERSION_EPUB2;
77 }
78
79 /**
80 *
81 * @return bool TRUE if the book is set to type ePub 2
82 */
83 function isEPubVersion2() {
84 return $this->bookVersion === EPub::BOOK_VERSION_EPUB2;
85 }
86
87 /**
88 *
89 * Enter description here ...
90 *
91 * @param string $uid
92 */
93 function setUid($uid) {
94 $this->uid = is_string($uid) ? trim($uid) : NULL;
95 }
96
97 /**
98 *
99 * Enter description here ...
100 *
101 * @param string $docTitle
102 */
103 function setDocTitle($docTitle) {
104 $this->docTitle = is_string($docTitle) ? trim($docTitle) : NULL;
105 }
106
107 /**
108 *
109 * Enter description here ...
110 *
111 * @param string $docAuthor
112 */
113 function setDocAuthor($docAuthor) {
114 $this->docAuthor = is_string($docAuthor) ? trim($docAuthor) : NULL;
115 }
116
117 /**
118 *
119 * Enter description here ...
120 *
121 * @param string $languageCode
122 */
123 function setLanguageCode($languageCode) {
124 $this->languageCode = is_string($languageCode) ? trim($languageCode) : "en";
125 }
126
127 /**
128 *
129 * Enter description here ...
130 *
131 * @param string $writingDirection
132 */
133 function setWritingDirection($writingDirection) {
134 $this->writingDirection = is_string($writingDirection) ? trim($writingDirection) : EPub::DIRECTION_LEFT_TO_RIGHT;
135 }
136
137 /**
138 *
139 * Enter description here ...
140 *
141 * @param NavMap $navMap
142 */
143 function setNavMap($navMap) {
144 if ($navMap != NULL && is_object($navMap) && get_class($navMap) === "NavMap") {
145 $this->navMap = $navMap;
146 }
147 }
148
149 /**
150 * Add one chapter level.
151 *
152 * Subsequent chapters will be added to this level.
153 *
154 * @param string $navTitle
155 * @param string $navId
156 * @param string $navClass
157 * @param string $isNavHidden
158 * @param string $writingDirection
159 * @return NavPoint
160 */
161 function subLevel($navTitle = NULL, $navId = NULL, $navClass = NULL, $isNavHidden = FALSE, $writingDirection = NULL) {
162 $navPoint = FALSE;
163 if (isset($navTitle) && isset($navClass)) {
164 $navPoint = new NavPoint($navTitle, NULL, $navId, $navClass, $isNavHidden, $writingDirection);
165 $this->addNavPoint($navPoint);
166 }
167 if ($this->lastLevel !== NULL) {
168 $this->currentLevel = $this->lastLevel;
169 }
170 return $navPoint;
171 }
172
173 /**
174 * Step back one chapter level.
175 *
176 * Subsequent chapters will be added to this chapters parent level.
177 */
178 function backLevel() {
179 $this->lastLevel = $this->currentLevel;
180 $this->currentLevel = $this->currentLevel->getParent();
181 }
182
183 /**
184 * Step back to the root level.
185 *
186 * Subsequent chapters will be added to the rooot NavMap.
187 */
188 function rootLevel() {
189 $this->lastLevel = $this->currentLevel;
190 $this->currentLevel = $this->navMap;
191 }
192
193 /**
194 * Step back to the given level.
195 * Useful for returning to a previous level from deep within the structure.
196 * Values below 2 will have the same effect as rootLevel()
197 *
198 * @param int $newLevel
199 */
200 function setCurrentLevel($newLevel) {
201 if ($newLevel <= 1) {
202 $this->rootLevel();
203 } else {
204 while ($this->currentLevel->getLevel() > $newLevel) {
205 $this->backLevel();
206 }
207 }
208 }
209
210 /**
211 * Get current level count.
212 * The indentation of the current structure point.
213 *
214 * @return current level count;
215 */
216 function getCurrentLevel() {
217 return $this->currentLevel->getLevel();
218 }
219
220 /**
221 * Add child NavPoints to current level.
222 *
223 * @param NavPoint $navPoint
224 */
225 function addNavPoint($navPoint) {
226 $this->lastLevel = $this->currentLevel->addNavPoint($navPoint);
227 }
228
229 /**
230 *
231 * Enter description here ...
232 *
233 * @return NavMap
234 */
235 function getNavMap() {
236 return $this->navMap;
237 }
238
239 /**
240 *
241 * Enter description here ...
242 *
243 * @param string $name
244 * @param string $content
245 */
246 function addMetaEntry($name, $content) {
247 $name = is_string($name) ? trim($name) : NULL;
248 $content = is_string($content) ? trim($content) : NULL;
249
250 if ($name != NULL && $content != NULL) {
251 $this->meta[] = array($name => $content);
252 }
253 }
254
255 /**
256 *
257 * Enter description here ...
258 *
259 * @return string
260 */
261 function finalize() {
262 $nav = $this->navMap->finalize();
263
264 $ncx = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
265 if ($this->isEPubVersion2()) {
266 $ncx .= "<!DOCTYPE ncx PUBLIC \"-//NISO//DTD ncx 2005-1//EN\"\n"
267 . " \"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd\">\n";
268 }
269 $ncx .= "<ncx xmlns=\"http://www.daisy.org/z3986/2005/ncx/\" version=\"2005-1\" xml:lang=\"" . $this->languageCode . "\" dir=\"" . $this->writingDirection . "\">\n"
270 . "\t<head>\n"
271 . "\t\t<meta name=\"dtb:uid\" content=\"" . $this->uid . "\" />\n"
272 . "\t\t<meta name=\"dtb:depth\" content=\"" . $this->navMap->getNavLevels() . "\" />\n"
273 . "\t\t<meta name=\"dtb:totalPageCount\" content=\"0\" />\n"
274 . "\t\t<meta name=\"dtb:maxPageNumber\" content=\"0\" />\n";
275
276 if (sizeof($this->meta)) {
277 foreach ($this->meta as $metaEntry) {
278 list($name, $content) = each($metaEntry);
279 $ncx .= "\t\t<meta name=\"" . $name . "\" content=\"" . $content . "\" />\n";
280 }
281 }
282
283 $ncx .= "\t</head>\n\n\t<docTitle>\n\t\t<text>"
284 . $this->docTitle
285 . "</text>\n\t</docTitle>\n\n\t<docAuthor>\n\t\t<text>"
286 . $this->docAuthor
287 . "</text>\n\t</docAuthor>\n\n"
288 . $nav;
289
290 return $ncx . "</ncx>\n";
291 }
292
293 /**
294 *
295 * @param string $title
296 * @param string $cssFileName
297 * @return string
298 */
299 function finalizeEPub3($title = "Table of Contents", $cssFileName = NULL) {
300 $end = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
301 . "<html xmlns=\"http://www.w3.org/1999/xhtml\"\n"
302 . " xmlns:epub=\"http://www.idpf.org/2007/ops\"\n"
303 . " xml:lang=\"" . $this->languageCode . "\" lang=\"" . $this->languageCode . "\" dir=\"" . $this->writingDirection . "\">\n"
304 . "\t<head>\n"
305 . "\t\t<title>" . $this->docTitle . "</title>\n"
306 . "\t\t<meta http-equiv=\"default-style\" content=\"text/html; charset=utf-8\"/>\n";
307 if ($cssFileName !== NULL) {
308 $end .= "\t\t<link rel=\"stylesheet\" href=\"" . $cssFileName . "\" type=\"text/css\"/>\n";
309 }
310 $end .= "\t</head>\n"
311 . "\t<body epub:type=\"frontmatter toc\">\n"
312 . "\t\t<header>\n"
313 . "\t\t\t<h1>" . $title . "</h1>\n"
314 . "\t\t</header>\n"
315 . $this->navMap->finalizeEPub3()
316 . $this->finalizeEPub3Landmarks()
317 . "\t</body>\n"
318 . "</html>\n";
319
320 return $end;
321 }
322
323 /**
324 * Build the references for the ePub 2 toc.
325 * These are merely reference pages added to the end of the navMap though.
326 *
327 * @return string
328 */
329 function finalizeReferences() {
330 if (isset($this->referencesList) && sizeof($this->referencesList) > 0) {
331 $this->rootLevel();
332 $this->subLevel($this->referencesTitle, $this->referencesId, $this->referencesClass);
333 $refId = 1;
334 while (list($item, $descriptive) = each($this->referencesOrder)) {
335 if (array_key_exists($item, $this->referencesList)) {
336 $name = (empty($this->referencesName[$item]) ? $descriptive : $this->referencesName[$item]);
337 $navPoint = new NavPoint($name, $this->referencesList[$item], "ref-" . $refId++);
338 $this->addNavPoint($navPoint);
339 }
340 }
341 }
342 }
343
344 /**
345 * Build the landmarks for the ePub 3 toc.
346 * @return string
347 */
348 function finalizeEPub3Landmarks() {
349 $lm = "";
350 if (isset($this->referencesList) && sizeof($this->referencesList) > 0) {
351 $lm = "\t\t\t<nav epub:type=\"landmarks\">\n"
352 . "\t\t\t\t<h2"
353 . ($this->writingDirection === EPub::DIRECTION_RIGHT_TO_LEFT ? " dir=\"rtl\"" : "")
354 . ">" . $this->referencesTitle . "</h2>\n"
355 . "\t\t\t\t<ol>\n";
356
357 $li = "";
358 while (list($item, $descriptive) = each($this->referencesOrder)) {
359 if (array_key_exists($item, $this->referencesList)) {
360 $li .= "\t\t\t\t\t<li><a epub:type=\""
361 . $item
362 . "\" href=\"" . $this->referencesList[$item] . "\">"
363 . (empty($this->referencesName[$item]) ? $descriptive : $this->referencesName[$item])
364 . "</a></li>\n";
365 }
366 }
367 if (empty($li)) {
368 return "";
369 }
370
371 $lm .= $li
372 . "\t\t\t\t</ol>\n"
373 . "\t\t\t</nav>\n";
374 }
375 return $lm;
376 }
377}
378
379/**
380 * ePub NavMap class
381 */
382class NavMap {
383 const _VERSION = 3.00;
384
385 private $navPoints = array();
386 private $navLevels = 0;
387 private $writingDirection = NULL;
388
389 /**
390 * Class constructor.
391 *
392 * @return void
393 */
394 function __construct($writingDirection = NULL) {
395 $this->setWritingDirection($writingDirection);
396 }
397
398 /**
399 * Class destructor
400 *
401 * @return void
402 */
403 function __destruct() {
404 unset($this->navPoints, $this->navLevels, $this->writingDirection);
405 }
406
407 /**
408 * Set the writing direction to be used for this NavPoint.
409 *
410 * @param string $writingDirection
411 */
412 function setWritingDirection($writingDirection) {
413 $this->writingDirection = isset($writingDirection) && is_string($writingDirection) ? trim($writingDirection) : NULL;
414 }
415
416 function getWritingDirection() {
417 return $this->writingDirection;
418 }
419
420 /**
421 * Add a navPoint to the root of the NavMap.
422 *
423 * @param NavPoint $navPoint
424 * @return NavMap
425 */
426 function addNavPoint($navPoint) {
427 if ($navPoint != NULL && is_object($navPoint) && get_class($navPoint) === "NavPoint") {
428 $navPoint->setParent($this);
429 if ($navPoint->getWritingDirection() == NULL) {
430 $navPoint->setWritingDirection($this->writingDirection);
431 }
432 $this->navPoints[] = $navPoint;
433 return $navPoint;
434 }
435 return $this;
436 }
437
438 /**
439 * The final max depth for the "dtb:depth" meta attribute
440 * Only available after finalize have been called.
441 *
442 * @return number
443 */
444 function getNavLevels() {
445 return $this->navLevels+1;
446 }
447
448 function getLevel() {
449 return 1;
450 }
451
452 function getParent() {
453 return $this;
454 }
455
456 /**
457 * Finalize the navMap, the final max depth for the "dtb:depth" meta attribute can be retrieved with getNavLevels after finalization
458 *
459 */
460 function finalize() {
461 $playOrder = 0;
462 $this->navLevels = 0;
463
464 $nav = "\t<navMap>\n";
465 if (sizeof($this->navPoints) > 0) {
466 $this->navLevels++;
467 foreach ($this->navPoints as $navPoint) {
468 $retLevel = $navPoint->finalize($nav, $playOrder, 0);
469 if ($retLevel > $this->navLevels) {
470 $this->navLevels = $retLevel;
471 }
472 }
473 }
474 return $nav . "\t</navMap>\n";
475 }
476
477 /**
478 * Finalize the navMap, the final max depth for the "dtb:depth" meta attribute can be retrieved with getNavLevels after finalization
479 *
480 */
481 function finalizeEPub3() {
482 $playOrder = 0;
483 $level = 0;
484 $this->navLevels = 0;
485
486 $nav = "\t\t<nav epub:type=\"toc\" id=\"toc\">\n";
487
488 if (sizeof($this->navPoints) > 0) {
489 $this->navLevels++;
490
491 $nav .= str_repeat("\t", $level) . "\t\t\t<ol epub:type=\"list\">\n";
492 foreach ($this->navPoints as $navPoint) {
493 $retLevel = $navPoint->finalizeEPub3($nav, $playOrder, 0);
494 if ($retLevel > $this->navLevels) {
495 $this->navLevels = $retLevel;
496 }
497 }
498 $nav .= str_repeat("\t", $level) . "\t\t\t</ol>\n";
499 }
500
501 return $nav . "\t\t</nav>\n";
502 }
503}
504
505/**
506 * ePub NavPoint class
507 */
508class NavPoint {
509 const _VERSION = 3.00;
510
511 private $label = NULL;
512 private $contentSrc = NULL;
513 private $id = NULL;
514 private $navClass = NULL;
515 private $isNavHidden = FALSE;
516 private $navPoints = array();
517 private $parent = NULL;
518
519 /**
520 * Class constructor.
521 *
522 * All three attributes are mandatory, though if ID is set to null (default) the value will be generated.
523 *
524 * @param string $label
525 * @param string $contentSrc
526 * @param string $id
527 * @param string $navClass
528 * @param bool $isNavHidden
529 * @param string $writingDirection
530 */
531 function __construct($label, $contentSrc = NULL, $id = NULL, $navClass = NULL, $isNavHidden = FALSE, $writingDirection = NULL) {
532 $this->setLabel($label);
533 $this->setContentSrc($contentSrc);
534 $this->setId($id);
535 $this->setNavClass($navClass);
536 $this->setNavHidden($isNavHidden);
537 $this->setWritingDirection($writingDirection);
538 }
539
540 /**
541 * Class destructor
542 *
543 * @return void
544 */
545 function __destruct() {
546 unset($this->label, $this->contentSrc, $this->id, $this->navClass);
547 unset($this->isNavHidden, $this->navPoints, $this->parent);
548 }
549
550 /**
551 * Set the Text label for the NavPoint.
552 *
553 * The label is mandatory.
554 *
555 * @param string $label
556 */
557 function setLabel($label) {
558 $this->label = is_string($label) ? trim($label) : NULL;
559 }
560
561 /**
562 * Get the Text label for the NavPoint.
563 *
564 * @return string Label
565 */
566 function getLabel() {
567 return $this->label;
568 }
569
570 /**
571 * Set the src reference for the NavPoint.
572 *
573 * The src is mandatory for ePub 2.
574 *
575 * @param string $contentSrc
576 */
577 function setContentSrc($contentSrc) {
578 $this->contentSrc = isset($contentSrc) && is_string($contentSrc) ? trim($contentSrc) : NULL;
579 }
580
581 /**
582 * Get the src reference for the NavPoint.
583 *
584 * @return string content src url.
585 */
586 function getContentSrc() {
587 return $this->contentSrc;
588 }
589 /**
590 * Set the parent for this NavPoint.
591 *
592 * @param NavPoint or NavMap $parent
593 */
594 function setParent($parent) {
595 if ($parent != NULL && is_object($parent) &&
596 (get_class($parent) === "NavPoint" || get_class($parent) === "NavMap") ) {
597 $this->parent = $parent;
598 }
599 }
600
601 /**
602 * Get the parent to this NavPoint.
603 *
604 * @return NavPoint, or NavMap if the parent is the root.
605 */
606 function getParent() {
607 return $this->parent;
608 }
609
610 /**
611 * Get the current level. 1 = document root.
612 *
613 * @return int level
614 */
615 function getLevel() {
616 return $this->parent === NULL ? 1 : $this->parent->getLevel()+1;
617 }
618
619 /**
620 * Set the id for the NavPoint.
621 *
622 * The id must be unique, and is mandatory.
623 *
624 * @param string $id
625 */
626 function setId($id) {
627 $this->id = is_string($id) ? trim($id) : NULL;
628 }
629
630 /**
631 * Set the class to be used for this NavPoint.
632 *
633 * @param string $navClass
634 */
635 function setNavClass($navClass) {
636 $this->navClass = isset($navClass) && is_string($navClass) ? trim($navClass) : NULL;
637 }
638
639 /**
640 * Set the class to be used for this NavPoint.
641 *
642 * @param string $navClass
643 */
644 function setNavHidden($isNavHidden) {
645 $this->isNavHidden = $isNavHidden === TRUE;
646 }
647
648 /**
649 * Set the writing direction to be used for this NavPoint.
650 *
651 * @param string $writingDirection
652 */
653 function setWritingDirection($writingDirection) {
654 $this->writingDirection = isset($writingDirection) && is_string($writingDirection) ? trim($writingDirection) : NULL;
655 }
656
657 function getWritingDirection() {
658 return $this->writingDirection;
659 }
660
661 /**
662 * Add child NavPoints for multi level NavMaps.
663 *
664 * @param NavPoint $navPoint
665 */
666 function addNavPoint($navPoint) {
667 if ($navPoint != NULL && is_object($navPoint) && get_class($navPoint) === "NavPoint") {
668 $navPoint->setParent($this);
669 if ($navPoint->getWritingDirection() == NULL) {
670 $navPoint->setWritingDirection($this->writingDirection);
671 }
672 $this->navPoints[] = $navPoint;
673 return $navPoint;
674 }
675 return $this;
676 }
677
678 /**
679 *
680 * Enter description here ...
681 *
682 * @param string $nav
683 * @param int $playOrder
684 * @param int $level
685 * @return int
686 */
687 function finalize(&$nav = "", &$playOrder = 0, $level = 0) {
688 $maxLevel = $level;
689 $levelAdjust = 0;
690
691 if ($this->isNavHidden) {
692 return $maxLevel;
693 }
694
695 if (isset($this->contentSrc)) {
696 $playOrder++;
697
698 if ($this->id == NULL) {
699 $this->id = "navpoint-" . $playOrder;
700 }
701 $nav .= str_repeat("\t", $level) . "\t\t<navPoint id=\"" . $this->id . "\" playOrder=\"" . $playOrder . "\">\n"
702 . str_repeat("\t", $level) . "\t\t\t<navLabel>\n"
703 . str_repeat("\t", $level) . "\t\t\t\t<text>" . $this->label . "</text>\n"
704 . str_repeat("\t", $level) . "\t\t\t</navLabel>\n"
705 . str_repeat("\t", $level) . "\t\t\t<content src=\"" . $this->contentSrc . "\" />\n";
706 } else {
707 $levelAdjust++;
708 }
709
710 if (sizeof($this->navPoints) > 0) {
711 $maxLevel++;
712 foreach ($this->navPoints as $navPoint) {
713 $retLevel = $navPoint->finalize($nav, $playOrder, ($level+1+$levelAdjust));
714 if ($retLevel > $maxLevel) {
715 $maxLevel = $retLevel;
716 }
717 }
718 }
719
720 if (isset($this->contentSrc)) {
721 $nav .= str_repeat("\t", $level) . "\t\t</navPoint>\n";
722 }
723
724 return $maxLevel;
725 }
726
727 /**
728 *
729 * Enter description here ...
730 *
731 * @param string $nav
732 * @param int $playOrder
733 * @param int $level
734 * @return int
735 */
736 function finalizeEPub3(&$nav = "", &$playOrder = 0, $level = 0, $subLevelClass = NULL, $subLevelHidden = FALSE) {
737 $maxLevel = $level;
738
739 if ($this->id == NULL) {
740 $this->id = "navpoint-" . $playOrder;
741 }
742 $indent = str_repeat("\t", $level) . "\t\t\t\t";
743
744 $nav .= $indent . "<li id=\"" . $this->id . "\"";
745 if (isset($this->writingDirection)) {
746 $nav .= " dir=\"" . $this->writingDirection . "\"";
747 }
748 $nav .= ">\n";
749
750 if (isset($this->contentSrc)) {
751 $nav .= $indent . "\t<a href=\"" . $this->contentSrc . "\">" . $this->label . "</a>\n";
752 } else {
753 $nav .= $indent . "\t<span>" . $this->label . "</span>\n";
754 }
755
756 if (sizeof($this->navPoints) > 0) {
757 $maxLevel++;
758
759 $nav .= $indent . "\t<ol epub:type=\"list\"";
760 if (isset($subLevelClass)) {
761 $nav .= " class=\"" . $subLevelClass . "\"";
762 }
763 if ($subLevelHidden) {
764 $nav .= " hidden=\"hidden\"";
765 }
766 $nav .= ">\n";
767
768 foreach ($this->navPoints as $navPoint) {
769 $retLevel = $navPoint->finalizeEPub3($nav, $playOrder, ($level+2), $subLevelClass, $subLevelHidden);
770 if ($retLevel > $maxLevel) {
771 $maxLevel = $retLevel;
772 }
773 }
774 $nav .= $indent . "\t</ol>\n";
775 }
776
777 $nav .= $indent . "</li>\n";
778
779 return $maxLevel;
780 }
781}
782?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/PHPePub/EPub.OPF.php b/inc/3rdparty/libraries/PHPePub/EPub.OPF.php
deleted file mode 100644
index 803a2108..00000000
--- a/inc/3rdparty/libraries/PHPePub/EPub.OPF.php
+++ /dev/null
@@ -1,1226 +0,0 @@
1<?php
2/**
3 * ePub OPF file structure
4 *
5 * @author A. Grandt <php@grandt.com>
6 * @copyright 2009-2014 A. Grandt
7 * @license GNU LGPL, Attribution required for commercial implementations, requested for everything else.
8 * @version 3.20
9 */
10class Opf {
11 const _VERSION = 3.20;
12
13 /* Core Media types.
14 * These types are the only guaranteed mime types any ePub reader must understand.
15 * Any other type muse define a fall back whose fallback chain will end in one of these.
16 */
17 const TYPE_GIF = "image/gif";
18 const TYPE_JPEG = "image/jpeg";
19 const TYPE_PNG = "image/png";
20 const TYPE_SVG = "image/svg+xml";
21 const TYPE_XHTML = "application/xhtml+xml";
22 const TYPE_DTBOOK = "application/x-dtbook+xml";
23 const TYPE_CSS = "text/css";
24 const TYPE_XML = "application/xml";
25 const TYPE_OEB1_DOC = "text/x-oeb1-document"; // Deprecated
26 const TYPE_OEB1_CSS = "text/x-oeb1-css"; // Deprecated
27 const TYPE_NCX = "application/x-dtbncx+xml";
28
29 private $bookVersion = EPub::BOOK_VERSION_EPUB2;
30 private $ident = "BookId";
31
32 public $date = NULL;
33 public $metadata = NULL;
34 public $manifest = NULL;
35 public $spine = NULL;
36 public $guide = NULL;
37
38 /**
39 * Class constructor.
40 *
41 * @return void
42 */
43 function __construct($ident = "BookId", $bookVersion = EPub::BOOK_VERSION_EPUB2) {
44 $this->setIdent($ident);
45 $this->setVersion($bookVersion);
46 $this->metadata = new Metadata();
47 $this->manifest = new Manifest();
48 $this->spine = new Spine();
49 $this->guide = new Guide();
50 }
51
52 /**
53 * Class destructor
54 *
55 * @return void
56 */
57 function __destruct() {
58 unset ($this->bookVersion, $this->ident, $this->date, $this->metadata, $this->manifest, $this->spine, $this->guide);
59 }
60
61 /**
62 *
63 * Enter description here ...
64 *
65 * @param string $ident
66 */
67 function setVersion($bookVersion) {
68 $this->bookVersion = is_string($bookVersion) ? trim($bookVersion) : EPub::BOOK_VERSION_EPUB2;
69 }
70
71 function isEPubVersion2() {
72 return $this->bookVersion === EPub::BOOK_VERSION_EPUB2;
73 }
74
75 /**
76 *
77 * Enter description here ...
78 *
79 * @param string $ident
80 */
81 function setIdent($ident = "BookId") {
82 $this->ident = is_string($ident) ? trim($ident) : "BookId";
83 }
84
85 /**
86 *
87 * Enter description here ...
88 *
89 * @return string
90 */
91 function finalize() {
92 $opf = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
93 . "<package xmlns=\"http://www.idpf.org/2007/opf\" unique-identifier=\"" . $this->ident . "\" version=\"" . $this->bookVersion . "\">\n";
94
95 $opf .= $this->metadata->finalize($this->bookVersion, $this->date);
96 $opf .= $this->manifest->finalize($this->bookVersion);
97 $opf .= $this->spine->finalize();
98
99 if ($this->guide->length() > 0) {
100 $opf .= $this->guide->finalize();
101 }
102
103 return $opf . "</package>\n";
104 }
105
106 // Convenience functions:
107
108 /**
109 *
110 * Enter description here ...
111 *
112 * @param string $title
113 * @param string $language
114 * @param string $identifier
115 * @param string $identifierScheme
116 */
117 function initialize($title, $language, $identifier, $identifierScheme) {
118 $this->metadata->addDublinCore(new DublinCore("title", $title));
119 $this->metadata->addDublinCore(new DublinCore("language", $language));
120
121 $dc = new DublinCore("identifier", $identifier);
122 $dc->addAttr("id", $this->ident);
123 $dc->addOpfAttr("scheme", $identifierScheme);
124 $this->metadata->addDublinCore($dc);
125 }
126
127 /**
128 *
129 * Enter description here ...
130 *
131 * @param string $id
132 * @param string $href
133 * @param string $mediaType
134 */
135 function addItem($id, $href, $mediaType, $properties = NULL) {
136 $this->manifest->addItem(new Item($id, $href, $mediaType, $properties));
137 }
138
139 /**
140 *
141 * Enter description here ...
142 *
143 * @param string $idref
144 * @param bool $linear
145 */
146 function addItemRef($idref, $linear = TRUE) {
147 $this->spine->addItemref(new Itemref($idref, $linear));
148 }
149
150 /**
151 *
152 * Enter description here ...
153 *
154 * @param string $type
155 * @param string $title
156 * @param string $href
157 */
158 function addReference($type, $title, $href) {
159 $this->guide->addReference(new Reference($type, $title, $href));
160 }
161
162 /**
163 *
164 * Enter description here ...
165 *
166 * @param string $name
167 * @param string $value
168 */
169 function addDCMeta($name, $value) {
170 $this->metadata->addDublinCore(new DublinCore($name, $value));
171 }
172
173 /**
174 *
175 * Enter description here ...
176 *
177 * @param string $name
178 * @param string $content
179 */
180 function addMeta($name, $content) {
181 $this->metadata->addMeta($name, $content);
182 }
183
184 /**
185 *
186 * Enter description here ...
187 *
188 * @param string $name
189 * @param string $fileAs
190 * @param string $role Use the MarcCode constants
191 */
192 function addCreator($name, $fileAs = NULL, $role = NULL) {
193 $dc = new DublinCore(DublinCore::CREATOR, trim($name));
194
195 if ($fileAs !== NULL) {
196 $dc->addOpfAttr("file-as", trim($fileAs));
197 }
198
199 if ($role !== NULL) {
200 $dc->addOpfAttr("role", trim($role));
201 }
202
203 $this->metadata->addDublinCore($dc);
204 }
205
206 /**
207 *
208 * Enter description here ...
209 *
210 * @param string $name
211 * @param string $fileAs
212 * @param string $role Use the MarcCode constants
213 */
214 function addColaborator($name, $fileAs = NULL, $role = NULL) {
215 $dc = new DublinCore(DublinCore::CONTRIBUTOR, trim($name));
216
217 if ($fileAs !== NULL) {
218 $dc->addOpfAttr("file-as", trim($fileAs));
219 }
220
221 if ($role !== NULL) {
222 $dc->addOpfAttr("role", trim($role));
223 }
224
225 $this->metadata->addDublinCore($dc);
226 }
227}
228
229/**
230 * ePub OPF Metadata structures
231 */
232class Metadata {
233 const _VERSION = 3.00;
234
235 private $dc = array();
236 private $meta = array();
237
238 /**
239 * Class constructor.
240 *
241 * @return void
242 */
243 function __construct() {
244 }
245
246 /**
247 * Class destructor
248 *
249 * @return void
250 */
251 function __destruct() {
252 unset ($this->dc, $this->meta);
253 }
254
255 /**
256 *
257 * Enter description here ...
258 *
259 * @param DublinCore $dc
260 */
261 function addDublinCore($dc) {
262 if ($dc != NULL && is_object($dc) && get_class($dc) === "DublinCore") {
263 $this->dc[] = $dc;
264 }
265 }
266
267 /**
268 *
269 * Enter description here ...
270 *
271 * @param string $name
272 * @param string $content
273 */
274 function addMeta($name, $content) {
275 $name = is_string($name) ? trim($name) : NULL;
276 if (isset($name)) {
277 $content = is_string($content) ? trim($content) : NULL;
278 }
279 if (isset($content)) {
280 $this->meta[] = array ($name => $content);
281 }
282 }
283
284 /**
285 *
286 * @param string $bookVersion
287 * @param int $date
288 * @return string
289 */
290 function finalize($bookVersion = EPub::BOOK_VERSION_EPUB2, $date = NULL) {
291 $metadata = "\t<metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n";
292 if ($bookVersion === EPub::BOOK_VERSION_EPUB2) {
293 $metadata .= "\t\txmlns:opf=\"http://www.idpf.org/2007/opf\"\n\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n";
294 } else {
295 $metadata .= "\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n";
296 if (!isset($date)) {
297 $date = time();
298 }
299 $metadata .= "\t\t<meta property=\"dcterms:modified\">" . gmdate("Y-m-d\TH:i:s\Z", $date) . "</meta>\n";
300 }
301
302 foreach ($this->dc as $dc) {
303 $metadata .= $dc->finalize($bookVersion);
304 }
305
306 foreach ($this->meta as $data) {
307 list($name, $content) = each($data);
308 $metadata .= "\t\t<meta name=\"" . $name . "\" content=\"" . $content . "\" />\n";
309 }
310
311 return $metadata . "\t</metadata>\n";
312 }
313}
314
315/**
316 * ePub OPF Dublin Core (dc:) Metadata structures
317 */
318class DublinCore {
319 const _VERSION = 3.00;
320
321 const CONTRIBUTOR = "contributor";
322 const COVERAGE = "coverage";
323 const CREATOR = "creator";
324 const DATE = "date";
325 const DESCRIPTION = "description";
326 const FORMAT = "format";
327 const IDENTIFIER = "identifier";
328 const LANGUAGE = "language";
329 const PUBLISHER = "publisher";
330 const RELATION = "relation";
331 const RIGHTS = "rights";
332 const SOURCE = "source";
333 const SUBJECT = "subject";
334 const TITLE = "title";
335 const TYPE = "type";
336
337 private $dcName = NULL;
338 private $dcValue = NULL;
339 private $attr = array();
340 private $opfAttr = array();
341
342 /**
343 * Class constructor.
344 *
345 * @return void
346 */
347 function __construct($name, $value) {
348 $this->setDc($name, $value);
349 }
350
351 /**
352 * Class destructor
353 *
354 * @return void
355 */
356 function __destruct() {
357 unset ($this->dcName, $this->dcValue, $this->attr, $this->opfAttr);
358 }
359
360 /**
361 *
362 * Enter description here ...
363 *
364 * @param string $name
365 * @param string $value
366 */
367 function setDc($name, $value) {
368 $this->dcName = is_string($name) ? trim($name) : NULL;
369 if (isset($this->dcName)) {
370 $this->dcValue = isset($value) ? (string)$value : NULL;
371 }
372 if (! isset($this->dcValue)) {
373 $this->dcName = NULL;
374 }
375 }
376
377 /**
378 *
379 * Enter description here ...
380 *
381 * @param string $attrName
382 * @param string $attrValue
383 */
384 function addAttr($attrName, $attrValue) {
385 $attrName = is_string($attrName) ? trim($attrName) : NULL;
386 if (isset($attrName)) {
387 $attrValue = is_string($attrValue) ? trim($attrValue) : NULL;
388 }
389 if (isset($attrValue)) {
390 $this->attr[$attrName] = $attrValue;
391 }
392 }
393
394 /**
395 *
396 * Enter description here ...
397 *
398 * @param string $opfAttrName
399 * @param string $opfAttrValue
400 */
401 function addOpfAttr($opfAttrName, $opfAttrValue) {
402 $opfAttrName = is_string($opfAttrName) ? trim($opfAttrName) : NULL;
403 if (isset($opfAttrName)) {
404 $opfAttrValue = is_string($opfAttrValue) ? trim($opfAttrValue) : NULL;
405 }
406 if (isset($opfAttrValue)) {
407 $this->opfAttr[$opfAttrName] = $opfAttrValue;
408 }
409 }
410
411
412 /**
413 *
414 * @param string $bookVersion
415 * @return string
416 */
417 function finalize($bookVersion = EPub::BOOK_VERSION_EPUB2) {
418 $dc = "\t\t<dc:" . $this->dcName;
419
420 if (sizeof($this->attr) > 0) {
421 while (list($name, $content) = each($this->attr)) {
422 $dc .= " " . $name . "=\"" . $content . "\"";
423 }
424 }
425
426 if ($bookVersion === EPub::BOOK_VERSION_EPUB2 && sizeof($this->opfAttr) > 0) {
427 while (list($name, $content) = each($this->opfAttr)) {
428 $dc .= " opf:" . $name . "=\"" . $content . "\"";
429 }
430 }
431
432 return $dc . ">" . $this->dcValue . "</dc:" . $this->dcName . ">\n";
433 }
434}
435
436/**
437 * ePub OPF Manifest structure
438 */
439class Manifest {
440 const _VERSION = 3.00;
441
442 private $items = array();
443
444 /**
445 * Class constructor.
446 *
447 * @return void
448 */
449 function __construct() {
450 }
451
452 /**
453 * Class destructor
454 *
455 * @return void
456 */
457 function __destruct() {
458 unset ($this->items);
459 }
460
461 /**
462 *
463 * Enter description here ...
464 *
465 * @param Item $item
466 */
467 function addItem($item) {
468 if ($item != NULL && is_object($item) && get_class($item) === "Item") {
469 $this->items[] = $item;
470 }
471 }
472
473 /**
474 *
475 * @param string $bookVersion
476 * @return string
477 */
478 function finalize($bookVersion = EPub::BOOK_VERSION_EPUB2) {
479 $manifest = "\n\t<manifest>\n";
480 foreach ($this->items as $item) {
481 $manifest .= $item->finalize($bookVersion);
482 }
483 return $manifest . "\t</manifest>\n";
484 }
485}
486
487/**
488 * ePub OPF Item structure
489 */
490class Item {
491 const _VERSION = 3.00;
492
493 private $id = NULL;
494 private $href = NULL;
495 private $mediaType = NULL;
496 private $properties = NULL;
497 private $requiredNamespace = NULL;
498 private $requiredModules = NULL;
499 private $fallback = NULL;
500 private $fallbackStyle = NULL;
501
502 /**
503 * Class constructor.
504 *
505 * @return void
506 */
507 function __construct($id, $href, $mediaType, $properties = NULL) {
508 $this->setId($id);
509 $this->setHref($href);
510 $this->setMediaType($mediaType);
511 $this->setProperties($properties);
512 }
513
514 /**
515 * Class destructor
516 *
517 * @return void
518 */
519 function __destruct() {
520 unset ($this->id, $this->href, $this->mediaType);
521 unset ($this->properties, $this->requiredNamespace, $this->requiredModules, $this->fallback, $this->fallbackStyle);
522 }
523
524 /**
525 *
526 * Enter description here ...
527 *
528 * @param string $id
529 */
530 function setId($id) {
531 $this->id = is_string($id) ? trim($id) : NULL;
532 }
533
534 /**
535 *
536 * Enter description here ...
537 *
538 * @param string $href
539 */
540 function setHref($href) {
541 $this->href = is_string($href) ? trim($href) : NULL;
542 }
543
544 /**
545 *
546 * Enter description here ...
547 *
548 * @param string $mediaType
549 */
550 function setMediaType($mediaType) {
551 $this->mediaType = is_string($mediaType) ? trim($mediaType) : NULL;
552 }
553
554 /**
555 *
556 * Enter description here ...
557 *
558 * @param string $properties
559 */
560 function setProperties($properties) {
561 $this->properties = is_string($properties) ? trim($properties) : NULL;
562 }
563
564 /**
565 *
566 * Enter description here ...
567 *
568 * @param string $requiredNamespace
569 */
570 function setRequiredNamespace($requiredNamespace) {
571 $this->requiredNamespace = is_string($requiredNamespace) ? trim($requiredNamespace) : NULL;
572 }
573
574 /**
575 *
576 * Enter description here ...
577 *
578 * @param string $requiredModules
579 */
580 function setRequiredModules($requiredModules) {
581 $this->requiredModules = is_string($requiredModules) ? trim($requiredModules) : NULL;
582 }
583
584 /**
585 *
586 * Enter description here ...
587 *
588 * @param string $fallback
589 */
590 function setfallback($fallback) {
591 $this->fallback = is_string($fallback) ? trim($fallback) : NULL;
592 }
593
594 /**
595 *
596 * Enter description here ...
597 *
598 * @param string $fallbackStyle
599 */
600 function setFallbackStyle($fallbackStyle) {
601 $this->fallbackStyle = is_string($fallbackStyle) ? trim($fallbackStyle) : NULL;
602 }
603
604 /**
605 *
606 * @param string $bookVersion
607 * @return string
608 */
609 function finalize($bookVersion = EPub::BOOK_VERSION_EPUB2) {
610 $item = "\t\t<item id=\"" . $this->id . "\" href=\"" . $this->href . "\" media-type=\"" . $this->mediaType . "\" ";
611 if ($bookVersion === EPub::BOOK_VERSION_EPUB3 && isset($this->properties)) {
612 $item .= "properties=\"" . $this->properties . "\" ";
613 }
614 if (isset($this->requiredNamespace)) {
615 $item .= "\n\t\t\trequired-namespace=\"" . $this->requiredNamespace . "\" ";
616 if (isset($this->requiredModules)) {
617 $item .= "required-modules=\"" . $this->requiredModules . "\" ";
618 }
619 }
620 if (isset($this->fallback)) {
621 $item .= "\n\t\t\tfallback=\"" . $this->fallback . "\" ";
622 }
623 if (isset($this->fallbackStyle)) {
624 $item .= "\n\t\t\tfallback-style=\"" . $this->fallbackStyle . "\" ";
625 }
626 return $item . "/>\n";
627 }
628}
629
630/**
631 * ePub OPF Spine structure
632 */
633class Spine {
634 const _VERSION = 1.00;
635
636 private $itemrefs = array();
637 private $toc = NULL;
638
639 /**
640 * Class constructor.
641 *
642 * @return void
643 */
644 function __construct($toc = "ncx") {
645 $this->setToc($toc);
646 }
647
648 /**
649 * Class destructor
650 *
651 * @return void
652 */
653 function __destruct() {
654 unset ($this->itemrefs, $this->toc);
655 }
656
657 /**
658 *
659 * Enter description here ...
660 *
661 * @param string $toc
662 */
663 function setToc($toc) {
664 $this->toc = is_string($toc) ? trim($toc) : NULL;
665 }
666
667 /**
668 *
669 * Enter description here ...
670 *
671 * @param Itemref $itemref
672 */
673 function addItemref($itemref) {
674 if ($itemref != NULL
675 && is_object($itemref)
676 && get_class($itemref) === "Itemref"
677 && !isset($this->itemrefs[$itemref->getIdref()])) {
678 $this->itemrefs[$itemref->getIdref()] = $itemref;
679 }
680 }
681
682 /**
683 *
684 * Enter description here ...
685 *
686 * @return string
687 */
688 function finalize() {
689 $spine = "\n\t<spine toc=\"" . $this->toc . "\">\n";
690 foreach ($this->itemrefs as $itemref) {
691 $spine .= $itemref->finalize();
692 }
693 return $spine . "\t</spine>\n";
694 }
695}
696
697/**
698 * ePub OPF ItemRef structure
699 */
700class Itemref {
701 const _VERSION = 3.00;
702
703 private $idref = NULL;
704 private $linear = TRUE;
705
706 /**
707 * Class constructor.
708 *
709 * @return void
710 */
711 function __construct($idref, $linear = TRUE) {
712 $this->setIdref($idref);
713 $this->setLinear($linear);
714 }
715
716 /**
717 * Class destructor
718 *
719 * @return void
720 */
721 function __destruct() {
722 unset ($this->idref, $this->linear);
723 }
724
725 /**
726 *
727 * Enter description here ...
728 *
729 * @param string $idref
730 */
731 function setIdref($idref) {
732 $this->idref = is_string($idref) ? trim($idref) : NULL;
733 }
734
735 /**
736 *
737 * Enter description here ...
738 *
739 * @return string $idref
740 */
741 function getIdref() {
742 return $this->idref;
743 }
744
745 /**
746 *
747 * Enter description here ...
748 *
749 * @param bool $linear
750 */
751 function setLinear($linear = TRUE) {
752 $this->linear = $linear === TRUE;
753 }
754
755 /**
756 *
757 * Enter description here ...
758 *
759 * @return string
760 */
761 function finalize() {
762 $itemref = "\t\t<itemref idref=\"" . $this->idref . "\"";
763 if ($this->linear == FALSE) {
764 return $itemref .= " linear=\"no\" />\n";
765 }
766 return $itemref . " />\n";
767 }
768}
769
770/**
771 * ePub OPF Guide structure
772 */
773class Guide {
774 const _VERSION = 3.00;
775
776 private $references = array();
777
778 /**
779 * Class constructor.
780 *
781 * @return void
782 */
783 function __construct() {
784 }
785
786 /**
787 * Class destructor
788 *
789 * @return void
790 */
791 function __destruct() {
792 unset ($this->references);
793 }
794
795 /**
796 *
797 * Enter description here ...
798 *
799 */
800 function length() {
801 return sizeof($this->references);
802 }
803
804 /**
805 *
806 * Enter description here ...
807 *
808 * @param Reference $reference
809 */
810 function addReference($reference) {
811 if ($reference != NULL && is_object($reference) && get_class($reference) === "Reference") {
812 $this->references[] = $reference;
813 }
814 }
815
816 /**
817 *
818 * Enter description here ...
819 *
820 * @return string
821 */
822 function finalize() {
823 $ref = "";
824 if (sizeof($this->references) > 0) {
825 $ref = "\n\t<guide>\n";
826 foreach ($this->references as $reference) {
827 $ref .= $reference->finalize();
828 }
829 $ref .= "\t</guide>\n";
830 }
831 return $ref;
832 }
833}
834
835/**
836 * Reference constants
837 */
838class Reference {
839 const _VERSION = 1.00;
840
841 /* REFERENCE types are derived from the "Chicago Manual of Style"
842 */
843
844 /** Acknowledgements page */
845 const ACKNOWLEDGEMENTS = "acknowledgements";
846
847 /** Bibliography page */
848 const BIBLIOGRAPHY = "bibliography";
849
850 /** Colophon page */
851 const COLOPHON = "colophon";
852
853 /** Copyright page */
854 const COPYRIGHT_PAGE = "copyright-page";
855
856 /** Dedication */
857 const DEDICATION = "dedication";
858
859 /** Epigraph */
860 const EPIGRAPH = "epigraph";
861
862 /** Foreword */
863 const FOREWORD = "foreword";
864
865 /** Glossary page */
866 const GLOSSARY = "glossary";
867
868 /** back-of-book style index */
869 const INDEX = "index";
870
871 /** List of illustrations */
872 const LIST_OF_ILLUSTRATIONS = "loi";
873
874 /** List of tables */
875 const LIST_OF_TABLES = "lot";
876
877 /** Notes page */
878 const NOTES = "notes";
879
880 /** Preface page */
881 const PREFACE = "preface";
882
883 /** Table of contents */
884 const TABLE_OF_CONTENTS = "toc";
885
886 /** Page with possibly title, author, publisher, and other metadata */
887 const TITLE_PAGE = "titlepage";
888
889 /** First page of the book, ie. first page of the first chapter */
890 const TEXT = "text";
891
892 // ******************
893 // ePub3 constants
894 // ******************
895
896 // Document partitions
897 /** The publications cover(s), jacket information, etc. This is officially in ePub3, but works for ePub 2 as well */
898 const COVER = "cover";
899
900 /** Preliminary material to the content body, such as tables of contents, dedications, etc. */
901 const FRONTMATTER = "frontmatter";
902
903 /** The main (body) content of a document. */
904 const BODYMATTER = "bodymatter";
905
906 /** Ancillary material occurring after the document body, such as indices, appendices, etc. */
907 const BACKMATTER = "backmatter";
908
909
910 private $type = NULL;
911 private $title = NULL;
912 private $href = NULL;
913
914 /**
915 * Class constructor.
916 *
917 * @param string $type
918 * @param string $title
919 * @param string $href
920 */
921 function __construct($type, $title, $href) {
922 $this->setType($type);
923 $this->setTitle($title);
924 $this->setHref($href);
925 }
926
927 /**
928 * Class destructor
929 *
930 * @return void
931 */
932 function __destruct() {
933 unset ($this->type, $this->title, $this->href);
934 }
935
936 /**
937 *
938 * Enter description here ...
939 *
940 * @param string $type
941 */
942 function setType($type) {
943 $this->type = is_string($type) ? trim($type) : NULL;
944 }
945
946 /**
947 *
948 * Enter description here ...
949 *
950 * @param string $title
951 */
952 function setTitle($title) {
953 $this->title = is_string($title) ? trim($title) : NULL;
954 }
955
956 /**
957 *
958 * Enter description here ...
959 *
960 * @param string $href
961 */
962 function setHref($href) {
963 $this->href = is_string($href) ? trim($href) : NULL;
964 }
965
966 /**
967 *
968 * Enter description here ...
969 *
970 * @return string
971 */
972 function finalize() {
973 return "\t\t<reference type=\"" . $this->type . "\" title=\"" . $this->title . "\" href=\"" . $this->href . "\" />\n";
974 }
975}
976
977/**
978 * Common Marc codes.
979 * Ref: http://www.loc.gov/marc/relators/
980 */
981class MarcCode {
982 const _VERSION = 3.00;
983
984 /**
985 * Adapter
986 *
987 * Use for a person who
988 * 1) reworks a musical composition, usually for a different medium, or
989 * 2) rewrites novels or stories for motion pictures or other audiovisual medium.
990 */
991 const ADAPTER = "adp";
992
993 /**
994 * Annotator
995 *
996 * Use for a person who writes manuscript annotations on a printed item.
997 */
998 const ANNOTATOR = "ann";
999
1000 /**
1001 * Arranger
1002 *
1003 * Use for a person who transcribes a musical composition, usually for a different
1004 * medium from that of the original; in an arrangement the musical substance remains
1005 * essentially unchanged.
1006 */
1007 const ARRANGER = "arr";
1008
1009 /**
1010 * Artist
1011 *
1012 * Use for a person (e.g., a painter) who conceives, and perhaps also implements,
1013 * an original graphic design or work of art, if specific codes (e.g., [egr],
1014 * [etr]) are not desired. For book illustrators, prefer Illustrator [ill].
1015 */
1016 const ARTIST = "art";
1017
1018 /**
1019 * Associated name
1020 *
1021 * Use as a general relator for a name associated with or found in an item or
1022 * collection, or which cannot be determined to be that of a Former owner [fmo]
1023 * or other designated relator indicative of provenance.
1024 */
1025 const ASSOCIATED_NAME = "asn";
1026
1027 /**
1028 * Author
1029 *
1030 * Use for a person or corporate body chiefly responsible for the intellectual
1031 * or artistic content of a work. This term may also be used when more than one
1032 * person or body bears such responsibility.
1033 */
1034 const AUTHOR = "aut";
1035
1036 /**
1037 * Author in quotations or text extracts
1038 *
1039 * Use for a person whose work is largely quoted or extracted in a works to which
1040 * he or she did not contribute directly. Such quotations are found particularly
1041 * in exhibition catalogs, collections of photographs, etc.
1042 */
1043 const AUTHOR_IN_QUOTES = "aqt";
1044
1045 /**
1046 * Author of afterword, colophon, etc.
1047 *
1048 * Use for a person or corporate body responsible for an afterword, postface,
1049 * colophon, etc. but who is not the chief author of a work.
1050 */
1051 const AUTHOR_OF_AFTERWORD = "aft";
1052
1053 /**
1054 * Author of introduction, etc.
1055 *
1056 * Use for a person or corporate body responsible for an introduction, preface,
1057 * foreword, or other critical matter, but who is not the chief author.
1058 */
1059 const AUTHOR_OF_INTRO = "aui";
1060
1061 /**
1062 * Bibliographic antecedent
1063 *
1064 * Use for the author responsible for a work upon which the work represented by
1065 * the catalog record is based. This can be appropriate for adaptations, sequels,
1066 * continuations, indexes, etc.
1067 */
1068 const BIB_ANTECEDENT = "ant";
1069
1070 /**
1071 * Book producer
1072 *
1073 * Use for the person or firm responsible for the production of books and other
1074 * print media, if specific codes (e.g., [bkd], [egr], [tyd], [prt]) are not desired.
1075 */
1076 const BOOK_PRODUCER = "bkp";
1077
1078 /**
1079 * Collaborator
1080 *
1081 * Use for a person or corporate body that takes a limited part in the elaboration
1082 * of a work of another author or that brings complements (e.g., appendices, notes)
1083 * to the work of another author.
1084 */
1085 const COLABORATOR = "clb";
1086
1087 /**
1088 * Commentator
1089 *
1090 * Use for a person who provides interpretation, analysis, or a discussion of the
1091 * subject matter on a recording, motion picture, or other audiovisual medium.
1092 * Compiler [com] Use for a person who produces a work or publication by selecting
1093 * and putting together material from the works of various persons or bodies.
1094 */
1095 const COMMENTATOR = "cmm";
1096
1097 /**
1098 * Designer
1099 *
1100 * Use for a person or organization responsible for design if specific codes (e.g.,
1101 * [bkd], [tyd]) are not desired.
1102 */
1103 const DESIGNER = "dsr";
1104
1105 /**
1106 * Editor
1107 *
1108 * Use for a person who prepares for publication a work not primarily his/her own,
1109 * such as by elucidating text, adding introductory or other critical matter, or
1110 * technically directing an editorial staff.
1111 */
1112 const EDITORT = "edt";
1113
1114 /**
1115 * Illustrator
1116 *
1117 * Use for the person who conceives, and perhaps also implements, a design or
1118 * illustration, usually to accompany a written text.
1119 */
1120 const ILLUSTRATOR = "ill";
1121
1122 /**
1123 * Lyricist
1124 *
1125 * Use for the writer of the text of a song.
1126 */
1127 const LYRICIST = "lyr";
1128
1129 /**
1130 * Metadata contact
1131 *
1132 * Use for the person or organization primarily responsible for compiling and
1133 * maintaining the original description of a metadata set (e.g., geospatial
1134 * metadata set).
1135 */
1136 const METADATA_CONTACT = "mdc";
1137
1138 /**
1139 * Musician
1140 *
1141 * Use for the person who performs music or contributes to the musical content
1142 * of a work when it is not possible or desirable to identify the function more
1143 * precisely.
1144 */
1145 const MUSICIAN = "mus";
1146
1147 /**
1148 * Narrator
1149 *
1150 * Use for the speaker who relates the particulars of an act, occurrence, or
1151 * course of events.
1152 */
1153 const NARRATOR = "nrt";
1154
1155 /**
1156 * Other
1157 *
1158 * Use for relator codes from other lists which have no equivalent in the MARC
1159 * list or for terms which have not been assigned a code.
1160 */
1161 const OTHER = "oth";
1162
1163 /**
1164 * Photographer
1165 *
1166 * Use for the person or organization responsible for taking photographs, whether
1167 * they are used in their original form or as reproductions.
1168 */
1169 const PHOTOGRAPHER = "pht";
1170
1171 /**
1172 * Printer
1173 *
1174 * Use for the person or organization who prints texts, whether from type or plates.
1175 */
1176 const PRINTER = "prt";
1177
1178 /**
1179 * Redactor
1180 *
1181 * Use for a person who writes or develops the framework for an item without
1182 * being intellectually responsible for its content.
1183 */
1184 const REDACTOR = "red";
1185
1186 /**
1187 * Reviewer
1188 *
1189 * Use for a person or corporate body responsible for the review of book, motion
1190 * picture, performance, etc.
1191 */
1192 const REVIEWER = "rev";
1193
1194 /**
1195 * Sponsor
1196 *
1197 * Use for the person or agency that issued a contract, or under whose auspices
1198 * a work has been written, printed, published, etc.
1199 */
1200 const SPONSOR = "spn";
1201
1202 /**
1203 * Thesis advisor
1204 *
1205 * Use for the person under whose supervision a degree candidate develops and
1206 * presents a thesis, memoir, or text of a dissertation.
1207 */
1208 const THESIS_ADVISOR = "ths";
1209
1210 /**
1211 * Transcriber
1212 *
1213 * Use for a person who prepares a handwritten or typewritten copy from original
1214 * material, including from dictated or orally recorded material.
1215 */
1216 const TRANSCRIBER = "trc";
1217
1218 /**
1219 * Translator
1220 *
1221 * Use for a person who renders a text from one language into another, or from
1222 * an older form of a language into the modern form.
1223 */
1224 const TRANSLATOR = "trl";
1225}
1226?>
diff --git a/inc/3rdparty/libraries/PHPePub/EPub.php b/inc/3rdparty/libraries/PHPePub/EPub.php
deleted file mode 100644
index d9b990b7..00000000
--- a/inc/3rdparty/libraries/PHPePub/EPub.php
+++ /dev/null
@@ -1,2438 +0,0 @@
1<?php
2/**
3 * Create an ePub compatible book file.
4 *
5 * Please note, once finalized a book can no longer have chapters of data added or changed.
6 *
7 * License: GNU LGPL, Attribution required for commercial implementations, requested for everything else.
8 *
9 * Thanks to: Adam Schmalhofer and Kirstyn Fox for invaluable input and for "nudging" me in the right direction :)
10 *
11 * @author A. Grandt <php@grandt.com>
12 * @copyright 2009-2014 A. Grandt
13 * @license GNU LGPL 2.1
14 * @version 3.20
15 * @link http://www.phpclasses.org/package/6115
16 * @link https://github.com/Grandt/PHPePub
17 * @uses Zip.php version 1.50; http://www.phpclasses.org/browse/package/6110.html or https://github.com/Grandt/PHPZip
18 */
19class EPub {
20 const VERSION = 3.20;
21 const REQ_ZIP_VERSION = 1.60;
22
23 const IDENTIFIER_UUID = 'UUID';
24 const IDENTIFIER_URI = 'URI';
25 const IDENTIFIER_ISBN = 'ISBN';
26
27 /** Ignore all external references, and do not process the file for these */
28 const EXTERNAL_REF_IGNORE = 0;
29 /** Process the file for external references and add them to the book */
30 const EXTERNAL_REF_ADD = 1;
31 /** Process the file for external references and add them to the book, but remove images, and img tags */
32 const EXTERNAL_REF_REMOVE_IMAGES = 2;
33 /** Process the file for external references and add them to the book, but replace images, and img tags with [image] */
34 const EXTERNAL_REF_REPLACE_IMAGES = 3;
35
36 const DIRECTION_LEFT_TO_RIGHT = "ltr";
37 const DIRECTION_RIGHT_TO_LEFT = "rtl";
38
39 const BOOK_VERSION_EPUB2 = "2.0";
40 const BOOK_VERSION_EPUB3 = "3.0";
41
42 private $bookVersion = EPub::BOOK_VERSION_EPUB2;
43
44 private $debugInside = FALSE;
45
46 public $maxImageWidth = 768;
47 public $maxImageHeight = 1024;
48
49 public $splitDefaultSize = 250000;
50 /** Gifs can crash some early ADE based readers, and are disabled by default.
51 * getImage will convert these if it can, unless this is set to TRUE.
52 */
53 public $isGifImagesEnabled = FALSE;
54 public $isReferencesAddedToToc = TRUE;
55
56 private $zip;
57
58 private $title = "";
59 private $language = "en";
60 private $identifier = "";
61 private $identifierType = "";
62 private $description = "";
63 private $author = "";
64 private $authorSortKey = "";
65 private $publisherName = "";
66 private $publisherURL = "";
67 private $date = 0;
68 private $rights = "";
69 private $coverage = "";
70 private $relation = "";
71 private $sourceURL = "";
72
73 private $chapterCount = 0;
74 private $opf = NULL;
75 private $ncx = NULL;
76 private $isFinalized = FALSE;
77 private $isCoverImageSet = FALSE;
78 private $buildTOC = FALSE;
79 private $tocTitle = NULL;
80 private $tocFileName = NULL;
81 private $tocCSSClass = NULL;
82 private $tocAddReferences = FALSE;
83 private $tocCssFileName = NULL;
84
85 private $fileList = array();
86 private $writingDirection = EPub::DIRECTION_LEFT_TO_RIGHT;
87 private $languageCode = "en";
88
89 /**
90 * Used for building the TOC.
91 * If this list is overwritten it MUST contain at least "text" as an element.
92 */
93 public $referencesOrder = NULL;
94
95 private $dateformat = 'Y-m-d\TH:i:s.000000P'; // ISO 8601 long
96 private $dateformatShort = 'Y-m-d'; // short date format to placate ePubChecker.
97 private $headerDateFormat = "D, d M Y H:i:s T";
98
99 protected $isCurlInstalled;
100 protected $isGdInstalled;
101 protected $isExifInstalled;
102 protected $isFileGetContentsInstalled;
103 protected $isFileGetContentsExtInstalled;
104
105 private $bookRoot = "OEBPS/";
106 private $docRoot = NULL;
107 private $EPubMark = TRUE;
108 private $generator = "";
109
110 private $log = NULL;
111 public $isLogging = TRUE;
112
113 public $encodeHTML = FALSE;
114
115 private $mimetypes = array(
116 "js" => "application/x-javascript", "swf" => "application/x-shockwave-flash", "xht" => "application/xhtml+xml", "xhtml" => "application/xhtml+xml", "zip" => "application/zip",
117 "aif" => "audio/x-aiff", "aifc" => "audio/x-aiff", "aiff" => "audio/x-aiff", "au" => "audio/basic", "kar" => "audio/midi", "m3u" => "audio/x-mpegurl", "mid" => "audio/midi", "midi" => "audio/midi", "mp2" => "audio/mpeg", "mp3" => "audio/mpeg", "mpga" => "audio/mpeg", "oga" => "audio/ogg", "ogg" => "audio/ogg", "ra" => "audio/x-realaudio", "ram" => "audio/x-pn-realaudio", "rm" => "audio/x-pn-realaudio", "rpm" => "audio/x-pn-realaudio-plugin", "snd" => "audio/basic", "wav" => "audio/x-wav",
118 "bmp" => "image/bmp", "djv" => "image/vnd.djvu", "djvu" => "image/vnd.djvu", "gif" => "image/gif", "ief" => "image/ief", "jpe" => "image/jpeg", "jpeg" => "image/jpeg", "jpg" => "image/jpeg", "pbm" => "image/x-portable-bitmap", "pgm" => "image/x-portable-graymap", "png" => "image/png", "pnm" => "image/x-portable-anymap", "ppm" => "image/x-portable-pixmap", "ras" => "image/x-cmu-raster", "rgb" => "image/x-rgb", "tif" => "image/tif", "tiff" => "image/tiff", "wbmp" => "image/vnd.wap.wbmp", "xbm" => "image/x-xbitmap", "xpm" => "image/x-xpixmap", "xwd" => "image/x-windowdump",
119 "asc" => "text/plain", "css" => "text/css", "etx" => "text/x-setext", "htm" => "text/html", "html" => "text/html", "rtf" => "text/rtf", "rtx" => "text/richtext", "sgm" => "text/sgml", "sgml" => "text/sgml", "tsv" => "text/tab-seperated-values", "txt" => "text/plain", "wml" => "text/vnd.wap.wml", "wmls" => "text/vnd.wap.wmlscript", "xml" => "text/xml", "xsl" => "text/xml",
120 "avi" => "video/x-msvideo", "mov" => "video/quicktime", "movie" => "video/x-sgi-movie", "mp4" => "video/mp4", "mpe" => "video/mpeg", "mpeg" => "video/mpeg", "mpg" => "video/mpeg", "mxu" => "video/vnd.mpegurl", "ogv" => "video/ogg", "qt" => "video/quicktime", "webm" => "video/webm");
121
122 // These are the ONLY allowed types in that these are the ones ANY reader must support, any other MUST have the fallback attribute pointing to one of these.
123 private $coreMediaTypes = array("image/gif", "image/jpeg", "image/png", "image/svg+xml", "application/xhtml+xml", "application/x-dtbook+xml", "application/xml", "application/x-dtbncx+xml", "text/css", "text/x-oeb1-css", "text/x-oeb1-document");
124
125 private $opsContentTypes = array("application/xhtml+xml", "application/x-dtbook+xml", "application/xml", "application/x-dtbncx+xml", "text/x-oeb1-document");
126
127 private $forbiddenCharacters = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", "%");
128
129 private $htmlContentHeader = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n<title></title>\n</head>\n<body>\n";
130 private $htmlContentFooter = "</body>\n</html>\n";
131
132 /**
133 * Class constructor.
134 *
135 * @return void
136 */
137 function __construct($bookVersion = EPub::BOOK_VERSION_EPUB2, $debugInside = FALSE, $languageCode = "en", $writingDirection = EPub::DIRECTION_LEFT_TO_RIGHT) {
138 include_once("Zip.php");
139 include_once("Logger.php");
140
141 if (!$debugInside) {
142 error_reporting(E_ERROR | E_PARSE);
143 }
144
145 $this->bookVersion = $bookVersion;
146 $this->writingDirection = $writingDirection;
147 $this->languageCode = $languageCode;
148
149 $this->log = new Logger("EPub", $this->isLogging);
150
151 /* Prepare Logging. Just in case it's used. later */
152 if ($this->isLogging) {
153 $this->log->logLine("EPub class version....: " . self::VERSION);
154 $this->log->logLine("EPub req. Zip version.: " . self::REQ_ZIP_VERSION);
155 $this->log->logLine("Zip version...........: " . Zip::VERSION);
156 $this->log->dumpInstalledModules();
157 }
158
159 if (!defined("Zip::VERSION") || Zip::VERSION < self::REQ_ZIP_VERSION) {
160 die("<p>EPub version " . self::VERSION . " requires Zip.php at version " . self::REQ_ZIP_VERSION . " or higher.<br />You can obtain the latest version from <a href=\"http://www.phpclasses.org/browse/package/6110.html\">http://www.phpclasses.org/browse/package/6110.html</a>.</p>");
161 }
162
163 include_once("EPubChapterSplitter.php");
164 include_once("EPub.HtmlEntities.php");
165 include_once("EPub.NCX.php");
166 include_once("EPub.OPF.php");
167
168 $this->initialize();
169 }
170
171 /**
172 * Class destructor
173 *
174 * @return void
175 * @TODO make sure elements in the destructor match the current class elements
176 */
177 function __destruct() {
178 unset($this->bookVersion, $this->maxImageWidth, $this->maxImageHeight);
179 unset($this->splitDefaultSize, $this->isGifImagesEnabled, $this->isReferencesAddedToToc);
180 unset($this->zip, $this->title, $this->language, $this->identifier, $this->identifierType);
181 unset($this->description, $this->author, $this->authorSortKey, $this->publisherName);
182 unset($this->publisherURL, $this->date, $this->rights, $this->coverage, $this->relation);
183 unset($this->sourceURL, $this->chapterCount, $this->opf, $this->ncx, $this->isFinalized);
184 unset($this->isCoverImageSet, $this->fileList, $this->writingDirection, $this->languageCode);
185 unset($this->referencesOrder, $this->dateformat, $this->dateformatShort, $this->headerDateFormat);
186 unset($this->isCurlInstalled, $this->isGdInstalled, $this->isExifInstalled);
187 unset($this->isFileGetContentsInstalled, $this->isFileGetContentsExtInstalled, $this->bookRoot);
188 unset($this->docRoot, $this->EPubMark, $this->generator, $this->log, $this->isLogging);
189 unset($this->encodeHTML, $this->mimetypes, $this->coreMediaTypes, $this->opsContentTypes);
190 unset($this->forbiddenCharacters, $this->htmlContentHeader, $this->htmlContentFooter);
191 unset($this->buildTOC, $this->tocTitle, $this->tocCSSClass, $this->tocAddReferences);
192 unset($this->tocFileName, $this->tocCssFileName);
193 }
194
195 /**
196 * initialize defaults.
197 */
198 private function initialize() {
199 $this->referencesOrder = array(
200 Reference::COVER => "Cover Page",
201 Reference::TITLE_PAGE => "Title Page",
202 Reference::ACKNOWLEDGEMENTS => "Acknowledgements",
203 Reference::BIBLIOGRAPHY => "Bibliography",
204 Reference::COLOPHON => "Colophon",
205 Reference::COPYRIGHT_PAGE => "Copyright",
206 Reference::DEDICATION => "Dedication",
207 Reference::EPIGRAPH => "Epigraph",
208 Reference::FOREWORD => "Foreword",
209 Reference::TABLE_OF_CONTENTS => "Table of Contents",
210 Reference::NOTES => "Notes",
211 Reference::PREFACE => "Preface",
212 Reference::TEXT => "First Page",
213 Reference::LIST_OF_ILLUSTRATIONS => "List of Illustrations",
214 Reference::LIST_OF_TABLES => "List of Tables",
215 Reference::GLOSSARY => "Glossary",
216 Reference::INDEX => "Index");
217
218 $this->docRoot = filter_input(INPUT_SERVER, "DOCUMENT_ROOT") . "/";
219
220 $this->isCurlInstalled = extension_loaded('curl') && function_exists('curl_version');
221 $this->isGdInstalled = extension_loaded('gd') && function_exists('gd_info');
222 $this->isExifInstalled = extension_loaded('exif') && function_exists('exif_imagetype');
223 $this->isFileGetContentsInstalled = function_exists('file_get_contents');
224 $this->isFileGetContentsExtInstalled = $this->isFileGetContentsInstalled && ini_get('allow_url_fopen');
225
226 $this->zip = new Zip();
227 $this->zip->setExtraField(FALSE);
228 $this->zip->addFile("application/epub+zip", "mimetype");
229 $this->zip->setExtraField(TRUE);
230 $this->zip->addDirectory("META-INF");
231
232 $this->content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<container version=\"1.0\" xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\">\n\t<rootfiles>\n\t\t<rootfile full-path=\"" . $this->bookRoot . "book.opf\" media-type=\"application/oebps-package+xml\" />\n\t</rootfiles>\n</container>\n";
233
234 if (!$this->isEPubVersion2()) {
235 $this->htmlContentHeader = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
236 . "<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n"
237 . "<head>"
238 . "<meta http-equiv=\"Default-Style\" content=\"text/html; charset=utf-8\" />\n"
239 . "<title></title>\n"
240 . "</head>\n"
241 . "<body>\n";
242 }
243
244 $this->zip->addFile($this->content, "META-INF/container.xml", 0, NULL, FALSE);
245 $this->content = NULL;
246 $this->ncx = new Ncx(NULL, NULL, NULL, $this->languageCode, $this->writingDirection);
247 $this->opf = new Opf();
248 $this->ncx->setVersion($this->bookVersion);
249 $this->opf->setVersion($this->bookVersion);
250 $this->opf->addItem("ncx", "book.ncx", Ncx::MIMETYPE);
251 $this->chapterCount = 0;
252 }
253
254 /**
255 * Add dynamically generated data as a file to the book.
256 *
257 * @param string $fileName Filename to use for the file, must be unique for the book.
258 * @param string $fileId Unique identifier for the file.
259 * @param string $fileData File data
260 * @param string $mimetype file mime type
261 * @return bool $success
262 */
263 function addFile($fileName, $fileId, $fileData, $mimetype) {
264 if ($this->isFinalized || array_key_exists($fileName, $this->fileList)) {
265 return FALSE;
266 }
267
268 $fileName = $this->normalizeFileName($fileName);
269
270 $compress = (strpos($mimetype, "image/") !== 0);
271
272 $this->zip->addFile($fileData, $this->bookRoot.$fileName, 0, NULL, $compress);
273 $this->fileList[$fileName] = $fileName;
274 $this->opf->addItem($fileId, $fileName, $mimetype);
275 return TRUE;
276 }
277
278 /**
279 * Add a large file directly from the filestystem to the book.
280 *
281 * @param string $fileName Filename to use for the file, must be unique for the book.
282 * @param string $fileId Unique identifier for the file.
283 * @param string $filePath File path
284 * @param string $mimetype file mime type
285 * @return bool $success
286 */
287 function addLargeFile($fileName, $fileId, $filePath, $mimetype) {
288 if ($this->isFinalized || array_key_exists($fileName, $this->fileList)) {
289 return FALSE;
290 }
291 $fileName = $this->normalizeFileName($fileName);
292
293 if ($this->zip->addLargeFile($filePath, $this->bookRoot.$fileName)) {
294 $this->fileList[$fileName] = $fileName;
295 $this->opf->addItem($fileId, $fileName, $mimetype);
296 return TRUE;
297 }
298 return FALSE;
299 }
300
301 /**
302 * Add a CSS file to the book.
303 *
304 * @param string $fileName Filename to use for the CSS file, must be unique for the book.
305 * @param string $fileId Unique identifier for the file.
306 * @param string $fileData CSS data
307 * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? See documentation for <code>processCSSExternalReferences</code> for explanation. Default is EPub::EXTERNAL_REF_IGNORE.
308 * @param string $baseDir Default is "", meaning it is pointing to the document root. NOT used if $externalReferences is set to EPub::EXTERNAL_REF_IGNORE.
309 *
310 * @return bool $success
311 */
312 function addCSSFile($fileName, $fileId, $fileData, $externalReferences = EPub::EXTERNAL_REF_IGNORE, $baseDir = "") {
313 if ($this->isFinalized || array_key_exists($fileName, $this->fileList)) {
314 return FALSE;
315 }
316 $fileName = Zip::getRelativePath($fileName);
317 $fileName = preg_replace('#^[/\.]+#i', "", $fileName);
318
319 if ($externalReferences !== EPub::EXTERNAL_REF_IGNORE) {
320 $cssDir = pathinfo($fileName);
321 $cssDir = preg_replace('#^[/\.]+#i', "", $cssDir["dirname"] . "/");
322 if (!empty($cssDir)) {
323 $cssDir = preg_replace('#[^/]+/#i', "../", $cssDir);
324 }
325
326 $this->processCSSExternalReferences($fileData, $externalReferences, $baseDir, $cssDir);
327 }
328
329 $this->addFile($fileName, "css_" . $fileId, $fileData, "text/css");
330
331 return TRUE;
332 }
333
334 /**
335 * Add a chapter to the book, as a chapter should not exceed 250kB, you can parse an array with multiple parts as $chapterData.
336 * These will still only show up as a single chapter in the book TOC.
337 *
338 * @param string $chapterName Name of the chapter, will be use din the TOC
339 * @param string $fileName Filename to use for the chapter, must be unique for the book.
340 * @param string $chapter Chapter text in XHTML or array $chapterData valid XHTML data for the chapter. File should NOT exceed 250kB.
341 * @param bool $autoSplit Should the chapter be split if it exceeds the default split size? Default=FALSE, only used if $chapterData is a string.
342 * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? See documentation for <code>processChapterExternalReferences</code> for explanation. Default is EPub::EXTERNAL_REF_IGNORE.
343 * @param string $baseDir Default is "", meaning it is pointing to the document root. NOT used if $externalReferences is set to EPub::EXTERNAL_REF_IGNORE.
344 * @return mixed $success FALSE if the addition failed, else the new NavPoint.
345 */
346 function addChapter($chapterName, $fileName, $chapterData = NULL, $autoSplit = FALSE, $externalReferences = EPub::EXTERNAL_REF_IGNORE, $baseDir = "") {
347 if ($this->isFinalized) {
348 return FALSE;
349 }
350 $fileName = Zip::getRelativePath($fileName);
351 $fileName = preg_replace('#^[/\.]+#i', "", $fileName);
352 $fileName = $this->sanitizeFileName($fileName);
353
354 $chapter = $chapterData;
355 if ($autoSplit && is_string($chapterData) && mb_strlen($chapterData) > $this->splitDefaultSize) {
356 $splitter = new EPubChapterSplitter();
357
358 $chapterArray = $splitter->splitChapter($chapterData);
359 if (count($chapterArray) > 1) {
360 $chapter = $chapterArray;
361 }
362 }
363
364 if (!empty($chapter) && is_string($chapter)) {
365 if ($externalReferences !== EPub::EXTERNAL_REF_IGNORE) {
366 $htmlDirInfo = pathinfo($fileName);
367 $htmlDir = preg_replace('#^[/\.]+#i', "", $htmlDirInfo["dirname"] . "/");
368 $this->processChapterExternalReferences($chapter, $externalReferences, $baseDir, $htmlDir);
369 }
370
371 if ($this->encodeHTML === TRUE) {
372 $chapter = $this->encodeHtml($chapter);
373 }
374
375 $this->chapterCount++;
376 $this->addFile($fileName, "chapter" . $this->chapterCount, $chapter, "application/xhtml+xml");
377 $this->opf->addItemRef("chapter" . $this->chapterCount);
378
379 $navPoint = new NavPoint($this->decodeHtmlEntities($chapterName), $fileName, "chapter" . $this->chapterCount);
380 $this->ncx->addNavPoint($navPoint);
381 $this->ncx->chapterList[$chapterName] = $navPoint;
382 } else if (is_array($chapter)) {
383 $fileNameParts = pathinfo($fileName);
384 $extension = $fileNameParts['extension'];
385 $name = $fileNameParts['filename'];
386
387 $partCount = 0;
388 $this->chapterCount++;
389
390 $oneChapter = each($chapter);
391 while ($oneChapter) {
392 list($k, $v) = $oneChapter;
393 if ($this->encodeHTML === TRUE) {
394 $v = $this->encodeHtml($v);
395 }
396
397 if ($externalReferences !== EPub::EXTERNAL_REF_IGNORE) {
398 $this->processChapterExternalReferences($v, $externalReferences, $baseDir);
399 }
400 $partCount++;
401 $partName = $name . "_" . $partCount;
402 $this->addFile($partName . "." . $extension, $partName, $v, "application/xhtml+xml");
403 $this->opf->addItemRef($partName);
404
405 $oneChapter = each($chapter);
406 }
407 $partName = $name . "_1." . $extension;
408 $navPoint = new NavPoint($this->decodeHtmlEntities($chapterName), $partName, $partName);
409 $this->ncx->addNavPoint($navPoint);
410
411 $this->ncx->chapterList[$chapterName] = $navPoint;
412 } else if (!isset($chapterData) && strpos($fileName, "#") > 0) {
413 $this->chapterCount++;
414 //$this->opf->addItemRef("chapter" . $this->chapterCount);
415
416 $navPoint = new NavPoint($this->decodeHtmlEntities($chapterName), $fileName, "chapter" . $this->chapterCount);
417 $this->ncx->addNavPoint($navPoint);
418 $this->ncx->chapterList[$chapterName] = $navPoint;
419 } else if (!isset($chapterData) && $fileName=="TOC.xhtml") {
420 $this->chapterCount++;
421 $this->opf->addItemRef("toc");
422
423 $navPoint = new NavPoint($this->decodeHtmlEntities($chapterName), $fileName, "chapter" . $this->chapterCount);
424 $this->ncx->addNavPoint($navPoint);
425 $this->ncx->chapterList[$chapterName] = $navPoint;
426 }
427 return $navPoint;
428 }
429
430 /**
431 * Add one chapter level.
432 *
433 * Subsequent chapters will be added to this level.
434 *
435 * @param string $navTitle
436 * @param string $navId
437 * @param string $navClass
438 * @param int $isNavHidden
439 * @param string $writingDirection
440 * @return NavPoint The new NavPoint for that level.
441 */
442 function subLevel($navTitle = NULL, $navId = NULL, $navClass = NULL, $isNavHidden = FALSE, $writingDirection = NULL) {
443 return $this->ncx->subLevel($this->decodeHtmlEntities($navTitle), $navId, $navClass, $isNavHidden, $writingDirection);
444 }
445
446 /**
447 * Step back one chapter level.
448 *
449 * Subsequent chapters will be added to this chapters parent level.
450 */
451 function backLevel() {
452 $this->ncx->backLevel();
453 }
454
455 /**
456 * Step back to the root level.
457 *
458 * Subsequent chapters will be added to the rooot NavMap.
459 */
460 function rootLevel() {
461 $this->ncx->rootLevel();
462 }
463
464 /**
465 * Step back to the given level.
466 * Useful for returning to a previous level from deep within the structure.
467 * Values below 2 will have the same effect as rootLevel()
468 *
469 * @param int $newLevel
470 */
471 function setCurrentLevel($newLevel) {
472 $this->ncx->setCurrentLevel($newLevel);
473 }
474
475 /**
476 * Get current level count.
477 * The indentation of the current structure point.
478 *
479 * @return current level count;
480 */
481 function getCurrentLevel() {
482 return $this->ncx->getCurrentLevel();
483 }
484
485 /**
486 * Wrap ChapterContent with Head and Footer
487 *
488 * @param $content
489 * @return string $content
490 */
491 private function wrapChapter($content) {
492 return $this->htmlContentHeader . "\n" . $content . "\n" . $this->htmlContentFooter;
493 }
494
495 /**
496 * Reference pages is usually one or two pages for items such as Table of Contents, reference lists, Author notes or Acknowledgements.
497 * These do not show up in the regular navigation list.
498 *
499 * As they are supposed to be short.
500 *
501 * @param string $pageName Name of the chapter, will be use din the TOC
502 * @param string $fileName Filename to use for the chapter, must be unique for the book.
503 * @param string $pageData Page content in XHTML. File should NOT exceed 250kB.
504 * @param string $reference Reference key
505 * @param int $externalReferences How to handle external references. See documentation for <code>processChapterExternalReferences</code> for explanation. Default is EPub::EXTERNAL_REF_IGNORE.
506 * @param string $baseDir Default is "", meaning it is pointing to the document root. NOT used if $externalReferences is set to EPub::EXTERNAL_REF_IGNORE.
507 * @return bool $success
508 */
509 function addReferencePage($pageName, $fileName, $pageData, $reference, $externalReferences = EPub::EXTERNAL_REF_IGNORE, $baseDir = "") {
510 if ($this->isFinalized) {
511 return FALSE;
512 }
513 $fileName = Zip::getRelativePath($fileName);
514 $fileName = preg_replace('#^[/\.]+#i', "", $fileName);
515
516
517 if (!empty($pageData) && is_string($pageData)) {
518 if ($this->encodeHTML === TRUE) {
519 $pageData = $this->encodeHtml($pageData);
520 }
521
522 $this->wrapChapter($pageData);
523
524 if ($externalReferences !== EPub::EXTERNAL_REF_IGNORE) {
525 $htmlDirInfo = pathinfo($fileName);
526 $htmlDir = preg_replace('#^[/\.]+#i', "", $htmlDirInfo["dirname"] . "/");
527 $this->processChapterExternalReferences($pageData, $externalReferences, $baseDir, $htmlDir);
528 }
529
530 $this->addFile($fileName, "ref_" . $reference, $pageData, "application/xhtml+xml");
531
532 if ($reference !== Reference::TABLE_OF_CONTENTS || !isset($this->ncx->referencesList[$reference])) {
533 $this->opf->addItemRef("ref_" . $reference, FALSE);
534 $this->opf->addReference($reference, $pageName, $fileName);
535
536 $this->ncx->referencesList[$reference] = $fileName;
537 $this->ncx->referencesName[$reference] = $pageName;
538 }
539 return TRUE;
540 }
541 return TRUE;
542 }
543
544 /**
545 * Add custom metadata to the book.
546 *
547 * It is up to the builder to make sure there are no collisions. Metadata are just key value pairs.
548 *
549 * @param string $name
550 * @param string $content
551 */
552 function addCustomMetadata($name, $content) {
553 $this->opf->addMeta($name, $content);
554 }
555
556 /**
557 * Add DublinCore metadata to the book
558 *
559 * Use the DublinCore constants included in EPub, ie DublinCore::DATE
560 *
561 * @param string $dublinCore name
562 * @param string $value
563 */
564 function addDublinCoreMetadata($dublinCoreConstant, $value) {
565 if ($this->isFinalized) {
566 return;
567 }
568
569 $this->opf->addDCMeta($dublinCoreConstant, $this->decodeHtmlEntities($value));
570 }
571
572 /**
573 * Add a cover image to the book.
574 * If the $imageData is not set, the function assumes the $fileName is the path to the image file.
575 *
576 * The styling and structure of the generated XHTML is heavily inspired by the XHTML generated by Calibre.
577 *
578 * @param string $fileName Filename to use for the image, must be unique for the book.
579 * @param string $imageData Binary image data
580 * @param string $mimetype Image mimetype, such as "image/jpeg" or "image/png".
581 * @return bool $success
582 */
583 function setCoverImage($fileName, $imageData = NULL, $mimetype = NULL,$bookTitle) {
584 if ($this->isFinalized || $this->isCoverImageSet || array_key_exists("CoverPage.html", $this->fileList)) {
585 return FALSE;
586 }
587
588 if ($imageData == NULL) {
589 // assume $fileName is the valid file path.
590 if (!file_exists($fileName)) {
591 // Attempt to locate the file using the doc root.
592 $rp = realpath($this->docRoot . "/" . $fileName);
593
594 if ($rp !== FALSE) {
595 // only assign the docroot path if it actually exists there.
596 $fileName = $rp;
597 }
598 }
599 $image = $this->getImage($fileName);
600 $imageData = $image['image'];
601 $mimetype = $image['mime'];
602 $fileName = preg_replace("#\.[^\.]+$#", "." . $image['ext'], $fileName);
603 }
604
605
606 $path = pathinfo($fileName);
607 $imgPath = "images/" . $path["basename"];
608
609 if (empty($mimetype) && file_exists($fileName)) {
610 list($width, $height, $type, $attr) = getimagesize($fileName);
611 $mimetype = image_type_to_mime_type($type);
612 }
613 if (empty($mimetype)) {
614 $ext = strtolower($path['extension']);
615 if ($ext == "jpg") {
616 $ext = "jpeg";
617 }
618 $mimetype = "image/" . $ext;
619 }
620
621 $coverPage = "";
622
623 if ($this->isEPubVersion2()) {
624 $coverPage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
625 . "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n"
626 . " \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
627 . "<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\" xml:lang=\"en\">\n"
628 . "\t<head>\n"
629 . "\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n"
630 . "\t\t<title>Cover Image</title>\n"
631 . "\t\t<link type=\"text/css\" rel=\"stylesheet\" href=\"Styles/CoverPage.css\" />\n"
632 . "\t</head>\n"
633 . "\t<body>\n"
634 . "\t" . $bookTitle . "\n"
635 . "\t\t<div>\n"
636 . "\t\t\t<img src=\"" . $imgPath . "\" alt=\"Cover image\" style=\"height: 100%\"/>\n"
637 . "\t\t</div>\n"
638 . "\t</body>\n"
639 . "</html>\n";
640 } else {
641 $coverPage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
642 . "<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n"
643 . "<head>"
644 . "\t<meta http-equiv=\"Default-Style\" content=\"text/html; charset=utf-8\" />\n"
645 . "\t\t<title>Cover Image</title>\n"
646 . "\t\t<link type=\"text/css\" rel=\"stylesheet\" href=\"Styles/CoverPage.css\" />\n"
647 . "\t</head>\n"
648 . "\t<body>\n"
649 . "\t\t<section epub:type=\"cover\">\n"
650 . "\t" . $bookTitle . "\n"
651 . "\t\t\t<img src=\"" . $imgPath . "\" alt=\"Cover image\" style=\"height: 30%\"/>\n"
652 . "\t\t</section>\n"
653 . "\t</body>\n"
654 . "</html>\n";
655 }
656 $coverPageCss = "@page, body, div, img {\n"
657 . "\tpadding: 0pt;\n"
658 . "\tmargin:0pt;\n"
659 . "}\n\nbody {\n"
660 . "\ttext-align: center;\n"
661 . "}\n";
662
663 $this->addCSSFile("Styles/CoverPage.css", "CoverPageCss", $coverPageCss);
664 $this->addFile($imgPath, "CoverImage", $imageData, $mimetype);
665 $this->addReferencePage("CoverPage", "CoverPage.xhtml", $coverPage, "cover");
666 $this->isCoverImageSet = TRUE;
667 return TRUE;
668 }
669
670 /**
671 * Process external references from a HTML to the book. The chapter itself is not stored.
672 * the HTML is scanned for &lt;link..., &lt;style..., and &lt;img tags.
673 * Embedded CSS styles and links will also be processed.
674 * Script tags are not processed, as scripting should be avoided in e-books.
675 *
676 * EPub keeps track of added files, and duplicate files referenced across multiple
677 * chapters, are only added once.
678 *
679 * If the $doc is a string, it is assumed to be the content of an HTML file,
680 * else is it assumes to be a DOMDocument.
681 *
682 * Basedir is the root dir the HTML is supposed to "live" in, used to resolve
683 * relative references such as <code>&lt;img src="../images/image.png"/&gt;</code>
684 *
685 * $externalReferences determines how the function will handle external references.
686 *
687 * @param mixed &$doc (referenced)
688 * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? Default is EPub::EXTERNAL_REF_ADD.
689 * @param string $baseDir Default is "", meaning it is pointing to the document root.
690 * @param string $htmlDir The path to the parent HTML file's directory from the root of the archive.
691 *
692 * @return bool FALSE if uncuccessful (book is finalized or $externalReferences == EXTERNAL_REF_IGNORE).
693 */
694 protected function processChapterExternalReferences(&$doc, $externalReferences = EPub::EXTERNAL_REF_ADD, $baseDir = "", $htmlDir = "") {
695 if ($this->isFinalized || $externalReferences === EPub::EXTERNAL_REF_IGNORE) {
696 return FALSE;
697 }
698
699 $backPath = preg_replace('#[^/]+/#i', "../", $htmlDir);
700 $isDocAString = is_string($doc);
701 $xmlDoc = NULL;
702
703 if ($isDocAString) {
704 $xmlDoc = new DOMDocument();
705 @$xmlDoc->loadHTML($doc);
706 } else {
707 $xmlDoc = $doc;
708 }
709
710 $this->processChapterStyles($xmlDoc, $externalReferences, $baseDir, $htmlDir);
711 $this->processChapterLinks($xmlDoc, $externalReferences, $baseDir, $htmlDir, $backPath);
712 $this->processChapterImages($xmlDoc, $externalReferences, $baseDir, $htmlDir, $backPath);
713 $this->processChapterSources($xmlDoc, $externalReferences, $baseDir, $htmlDir, $backPath);
714
715 if ($isDocAString) {
716 //$html = $xmlDoc->saveXML();
717
718 $htmlNode = $xmlDoc->getElementsByTagName("html");
719 $headNode = $xmlDoc->getElementsByTagName("head");
720 $bodyNode = $xmlDoc->getElementsByTagName("body");
721
722 $htmlNS = "";
723 for ($index = 0; $index < $htmlNode->item(0)->attributes->length; $index++) {
724 $nodeName = $htmlNode->item(0)->attributes->item($index)->nodeName;
725 $nodeValue = $htmlNode->item(0)->attributes->item($index)->nodeValue;
726
727 if ($nodeName != "xmlns") {
728 $htmlNS .= " $nodeName=\"$nodeValue\"";
729 }
730 }
731
732 $xml = new DOMDocument('1.0', "utf-8");
733 $xml->lookupPrefix("http://www.w3.org/1999/xhtml");
734 $xml->preserveWhiteSpace = FALSE;
735 $xml->formatOutput = TRUE;
736
737 $xml2Doc = new DOMDocument('1.0', "utf-8");
738 $xml2Doc->lookupPrefix("http://www.w3.org/1999/xhtml");
739 $xml2Doc->loadXML("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\"$htmlNS>\n</html>\n");
740 $html = $xml2Doc->getElementsByTagName("html")->item(0);
741 $html->appendChild($xml2Doc->importNode($headNode->item(0), TRUE));
742 $html->appendChild($xml2Doc->importNode($bodyNode->item(0), TRUE));
743
744 // force pretty printing and correct formatting, should not be needed, but it is.
745 $xml->loadXML($xml2Doc->saveXML());
746 $doc = $xml->saveXML();
747
748 if (!$this->isEPubVersion2()) {
749 $doc = preg_replace('#^\s*<!DOCTYPE\ .+?>\s*#im', '', $doc);
750 }
751 }
752 return TRUE;
753 }
754
755 /**
756 * Process images referenced from an CSS file to the book.
757 *
758 * $externalReferences determins how the function will handle external references.
759 *
760 * @param string &$cssFile (referenced)
761 * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? Default is EPub::EXTERNAL_REF_ADD.
762 * @param string $baseDir Default is "", meaning it is pointing to the document root.
763 * @param string $cssDir The of the CSS file's directory from the root of the archive.
764 *
765 * @return bool FALSE if unsuccessful (book is finalized or $externalReferences == EXTERNAL_REF_IGNORE).
766 */
767 protected function processCSSExternalReferences(&$cssFile, $externalReferences = EPub::EXTERNAL_REF_ADD, $baseDir = "", $cssDir = "") {
768 if ($this->isFinalized || $externalReferences === EPub::EXTERNAL_REF_IGNORE) {
769 return FALSE;
770 }
771
772 $backPath = preg_replace('#[^/]+/#i', "../", $cssDir);
773 $imgs = null;
774 preg_match_all('#url\s*\([\'\"\s]*(.+?)[\'\"\s]*\)#im', $cssFile, $imgs, PREG_SET_ORDER);
775
776 $itemCount = count($imgs);
777 for ($idx = 0; $idx < $itemCount; $idx++) {
778 $img = $imgs[$idx];
779 if ($externalReferences === EPub::EXTERNAL_REF_REMOVE_IMAGES || $externalReferences === EPub::EXTERNAL_REF_REPLACE_IMAGES) {
780 $cssFile = str_replace($img[0], "", $cssFile);
781 } else {
782 $source = $img[1];
783
784 $pathData = pathinfo($source);
785 $internalSrc = $pathData['basename'];
786 $internalPath = "";
787 $isSourceExternal = FALSE;
788
789 if ($this->resolveImage($source, $internalPath, $internalSrc, $isSourceExternal, $baseDir, $cssDir, $backPath)) {
790 $cssFile = str_replace($img[0], "url('" . $backPath . $internalPath . "')", $cssFile);
791 } else if ($isSourceExternal) {
792 $cssFile = str_replace($img[0], "", $cssFile); // External image is missing
793 } // else do nothing, if the image is local, and missing, assume it's been generated.
794 }
795 }
796 return TRUE;
797 }
798
799 /**
800 * Process style tags in a DOMDocument. Styles will be passed as CSS files and reinserted into the document.
801 *
802 * @param DOMDocument &$xmlDoc (referenced)
803 * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? Default is EPub::EXTERNAL_REF_ADD.
804 * @param string $baseDir Default is "", meaning it is pointing to the document root.
805 * @param string $htmlDir The path to the parent HTML file's directory from the root of the archive.
806 *
807 * @return bool FALSE if uncuccessful (book is finalized or $externalReferences == EXTERNAL_REF_IGNORE).
808 */
809 protected function processChapterStyles(&$xmlDoc, $externalReferences = EPub::EXTERNAL_REF_ADD, $baseDir = "", $htmlDir = "") {
810 if ($this->isFinalized || $externalReferences === EPub::EXTERNAL_REF_IGNORE) {
811 return FALSE;
812 }
813 // process inlined CSS styles in style tags.
814 $styles = $xmlDoc->getElementsByTagName("style");
815 $styleCount = $styles->length;
816 for ($styleIdx = 0; $styleIdx < $styleCount; $styleIdx++) {
817 $style = $styles->item($styleIdx);
818
819 $styleData = preg_replace('#[/\*\s]*\<\!\[CDATA\[[\s\*/]*#im', "", $style->nodeValue);
820 $styleData = preg_replace('#[/\*\s]*\]\]\>[\s\*/]*#im', "", $styleData);
821
822 $this->processCSSExternalReferences($styleData, $externalReferences, $baseDir, $htmlDir);
823 $style->nodeValue = "\n" . trim($styleData) . "\n";
824 }
825 return TRUE;
826 }
827
828 /**
829 * Process link tags in a DOMDocument. Linked files will be loaded into the archive, and the link src will be rewritten to point to that location.
830 * Link types text/css will be passed as CSS files.
831 *
832 * @param DOMDocument &$xmlDoc (referenced)
833 * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? Default is EPub::EXTERNAL_REF_ADD.
834 * @param string $baseDir Default is "", meaning it is pointing to the document root.
835 * @param string $htmlDir The path to the parent HTML file's directory from the root of the archive.
836 * @param string $backPath The path to get back to the root of the archive from $htmlDir.
837 *
838 * @return bool FALSE if uncuccessful (book is finalized or $externalReferences == EXTERNAL_REF_IGNORE).
839 */
840 protected function processChapterLinks(&$xmlDoc, $externalReferences = EPub::EXTERNAL_REF_ADD, $baseDir = "", $htmlDir = "", $backPath = "") {
841 if ($this->isFinalized || $externalReferences === EPub::EXTERNAL_REF_IGNORE) {
842 return FALSE;
843 }
844 // process link tags.
845 $links = $xmlDoc->getElementsByTagName("link");
846 $linkCount = $links->length;
847 for ($linkIdx = 0; $linkIdx < $linkCount; $linkIdx++) {
848 $link = $links->item($linkIdx);
849 $source = $link->attributes->getNamedItem("href")->nodeValue;
850 $sourceData = NULL;
851
852 $pathData = pathinfo($source);
853 $internalSrc = $pathData['basename'];
854
855 if (preg_match('#^(http|ftp)s?://#i', $source) == 1) {
856 $urlinfo = parse_url($source);
857
858 if (strpos($urlinfo['path'], $baseDir."/") !== FALSE) {
859 $internalSrc = substr($urlinfo['path'], strpos($urlinfo['path'], $baseDir."/") + strlen($baseDir) + 1);
860 }
861
862 @$sourceData = getFileContents($source);
863 } else if (strpos($source, "/") === 0) {
864 @$sourceData = file_get_contents($this->docRoot . $source);
865 } else {
866 @$sourceData = file_get_contents($this->docRoot . $baseDir . "/" . $source);
867 }
868
869 if (!empty($sourceData)) {
870 if (!array_key_exists($internalSrc, $this->fileList)) {
871 $mime = $link->attributes->getNamedItem("type")->nodeValue;
872 if (empty($mime)) {
873 $mime = "text/plain";
874 }
875 if ($mime == "text/css") {
876 $this->processCSSExternalReferences($sourceData, $externalReferences, $baseDir, $htmlDir);
877 $this->addCSSFile($internalSrc, $internalSrc, $sourceData, EPub::EXTERNAL_REF_IGNORE, $baseDir);
878 $link->setAttribute("href", $backPath . $internalSrc);
879 } else {
880 $this->addFile($internalSrc, $internalSrc, $sourceData, $mime);
881 }
882 $this->fileList[$internalSrc] = $source;
883 } else {
884 $link->setAttribute("href", $backPath . $internalSrc);
885 }
886 } // else do nothing, if the link is local, and missing, assume it's been generated.
887 }
888 return TRUE;
889 }
890
891 /**
892 * Process img tags in a DOMDocument.
893 * $externalReferences will determine what will happen to these images, and the img src will be rewritten accordingly.
894 *
895 * @param DOMDocument &$xmlDoc (referenced)
896 * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? Default is EPub::EXTERNAL_REF_ADD.
897 * @param string $baseDir Default is "", meaning it is pointing to the document root.
898 * @param string $htmlDir The path to the parent HTML file's directory from the root of the archive.
899 * @param string $backPath The path to get back to the root of the archive from $htmlDir.
900 *
901 * @return bool FALSE if uncuccessful (book is finalized or $externalReferences == EXTERNAL_REF_IGNORE).
902 */
903 protected function processChapterImages(&$xmlDoc, $externalReferences = EPub::EXTERNAL_REF_ADD, $baseDir = "", $htmlDir = "", $backPath = "") {
904 if ($this->isFinalized || $externalReferences === EPub::EXTERNAL_REF_IGNORE) {
905 return FALSE;
906 }
907 // process img tags.
908 $postProcDomElememts = array();
909 $images = $xmlDoc->getElementsByTagName("img");
910 $itemCount = $images->length;
911
912 for ($idx = 0; $idx < $itemCount; $idx++) {
913 $img = $images->item($idx);
914
915 if ($externalReferences === EPub::EXTERNAL_REF_REMOVE_IMAGES) {
916 $postProcDomElememts[] = $img;
917 } else if ($externalReferences === EPub::EXTERNAL_REF_REPLACE_IMAGES) {
918 $altNode = $img->attributes->getNamedItem("alt");
919 $alt = "image";
920 if ($altNode !== NULL && strlen($altNode->nodeValue) > 0) {
921 $alt = $altNode->nodeValue;
922 }
923 $postProcDomElememts[] = array($img, $this->createDomFragment($xmlDoc, "<em>[" . $alt . "]</em>"));
924 } else {
925 $source = $img->attributes->getNamedItem("src")->nodeValue;
926
927 $parsedSource = parse_url($source);
928 $internalSrc = $this->sanitizeFileName(urldecode(pathinfo($parsedSource['path'], PATHINFO_BASENAME)));
929 $internalPath = "";
930 $isSourceExternal = FALSE;
931
932 if ($this->resolveImage($source, $internalPath, $internalSrc, $isSourceExternal, $baseDir, $htmlDir, $backPath)) {
933 $img->setAttribute("src", $backPath . $internalPath);
934 } else if ($isSourceExternal) {
935 $postProcDomElememts[] = $img; // External image is missing
936 } // else do nothing, if the image is local, and missing, assume it's been generated.
937 }
938 }
939
940 foreach ($postProcDomElememts as $target) {
941 if (is_array($target)) {
942 $target[0]->parentNode->replaceChild($target[1], $target[0]);
943 } else {
944 $target->parentNode->removeChild($target);
945 }
946 }
947 return TRUE;
948 }
949
950 /**
951 * Process source tags in a DOMDocument.
952 * $externalReferences will determine what will happen to these images, and the img src will be rewritten accordingly.
953 *
954 * @param DOMDocument &$xmlDoc (referenced)
955 * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? Default is EPub::EXTERNAL_REF_ADD.
956 * @param string $baseDir Default is "", meaning it is pointing to the document root.
957 * @param string $htmlDir The path to the parent HTML file's directory from the root of the archive.
958 * @param string $backPath The path to get back to the root of the archive from $htmlDir.
959 *
960 * @return bool FALSE if uncuccessful (book is finalized or $externalReferences == EXTERNAL_REF_IGNORE).
961 */
962 protected function processChapterSources(&$xmlDoc, $externalReferences = EPub::EXTERNAL_REF_ADD, $baseDir = "", $htmlDir = "", $backPath = "") {
963 if ($this->isFinalized || $externalReferences === EPub::EXTERNAL_REF_IGNORE) {
964 return FALSE;
965 }
966
967 if ($this->bookVersion !== EPub::BOOK_VERSION_EPUB3) {
968 // ePub 2 does not support multimedia formats, and they must be removed.
969 $externalReferences = EPub::EXTERNAL_REF_REMOVE_IMAGES;
970 }
971
972 $postProcDomElememts = array();
973 $images = $xmlDoc->getElementsByTagName("source");
974 $itemCount = $images->length;
975 for ($idx = 0; $idx < $itemCount; $idx++) {
976 $img = $images->item($idx);
977 if ($externalReferences === EPub::EXTERNAL_REF_REMOVE_IMAGES) {
978 $postProcDomElememts[] = $img;
979 } else if ($externalReferences === EPub::EXTERNAL_REF_REPLACE_IMAGES) {
980 $altNode = $img->attributes->getNamedItem("alt");
981 $alt = "image";
982 if ($altNode !== NULL && strlen($altNode->nodeValue) > 0) {
983 $alt = $altNode->nodeValue;
984 }
985 $postProcDomElememts[] = array($img, $this->createDomFragment($xmlDoc, "[" . $alt . "]"));
986 } else {
987 $source = $img->attributes->getNamedItem("src")->nodeValue;
988
989 $parsedSource = parse_url($source);
990 $internalSrc = $this->sanitizeFileName(urldecode(pathinfo($parsedSource['path'], PATHINFO_BASENAME)));
991 $internalPath = "";
992 $isSourceExternal = FALSE;
993
994 if ($this->resolveMedia($source, $internalPath, $internalSrc, $isSourceExternal, $baseDir, $htmlDir, $backPath)) {
995 $img->setAttribute("src", $backPath . $internalPath);
996 } else if ($isSourceExternal) {
997 $postProcDomElememts[] = $img; // External image is missing
998 } // else do nothing, if the image is local, and missing, assume it's been generated.
999 }
1000 }
1001 }
1002
1003 /**
1004 * Resolve an image src and determine it's target location and add it to the book.
1005 *
1006 * @param string $source Image Source link.
1007 * @param string &$internalPath (referenced) Return value, will be set to the target path and name in the book.
1008 * @param string &$internalSrc (referenced) Return value, will be set to the target name in the book.
1009 * @param string &$isSourceExternal (referenced) Return value, will be set to TRUE if the image originated from a full URL.
1010 * @param string $baseDir Default is "", meaning it is pointing to the document root.
1011 * @param string $htmlDir The path to the parent HTML file's directory from the root of the archive.
1012 * @param string $backPath The path to get back to the root of the archive from $htmlDir.
1013 */
1014 protected function resolveImage($source, &$internalPath, &$internalSrc, &$isSourceExternal, $baseDir = "", $htmlDir = "", $backPath = "") {
1015 if ($this->isFinalized) {
1016 return FALSE;
1017 }
1018 $imageData = NULL;
1019
1020 if (preg_match('#^(http|ftp)s?://#i', $source) == 1) {
1021 $urlinfo = parse_url($source);
1022 $urlPath = pathinfo($urlinfo['path']);
1023
1024 if (strpos($urlinfo['path'], $baseDir."/") !== FALSE) {
1025 $internalSrc = $this->sanitizeFileName(urldecode(substr($urlinfo['path'], strpos($urlinfo['path'], $baseDir."/") + strlen($baseDir) + 1)));
1026 }
1027 $internalPath = $urlinfo["scheme"] . "/" . $urlinfo["host"] . "/" . pathinfo($urlinfo["path"], PATHINFO_DIRNAME);
1028 $isSourceExternal = TRUE;
1029 $imageData = $this->getImage($source);
1030 } else if (strpos($source, "/") === 0) {
1031 $internalPath = pathinfo($source, PATHINFO_DIRNAME);
1032
1033 $path = $source;
1034 if (!file_exists($path)) {
1035 $path = $this->docRoot . $path;
1036 }
1037
1038 $imageData = $this->getImage($path);
1039 } else {
1040 $internalPath = $htmlDir . "/" . preg_replace('#^[/\.]+#', '', pathinfo($source, PATHINFO_DIRNAME));
1041
1042 $path = $baseDir . "/" . $source;
1043 if (!file_exists($path)) {
1044 $path = $this->docRoot . $path;
1045 }
1046
1047 $imageData = $this->getImage($path);
1048 }
1049 if ($imageData !== FALSE) {
1050 $iSrcInfo = pathinfo($internalSrc);
1051 if (!empty($imageData['ext']) && $imageData['ext'] != $iSrcInfo['extension']) {
1052 $internalSrc = $iSrcInfo['filename'] . "." . $imageData['ext'];
1053 }
1054 $internalPath = Zip::getRelativePath("images/" . $internalPath . "/" . $internalSrc);
1055 if (!array_key_exists($internalPath, $this->fileList)) {
1056 $this->addFile($internalPath, "i_" . $internalSrc, $imageData['image'], $imageData['mime']);
1057 $this->fileList[$internalPath] = $source;
1058 }
1059 return TRUE;
1060 }
1061 return FALSE;
1062 }
1063
1064 /**
1065 * Resolve a media src and determine it's target location and add it to the book.
1066 *
1067 * @param string $source Source link.
1068 * @param string $internalPath (referenced) Return value, will be set to the target path and name in the book.
1069 * @param string $internalSrc (referenced) Return value, will be set to the target name in the book.
1070 * @param string $isSourceExternal (referenced) Return value, will be set to TRUE if the image originated from a full URL.
1071 * @param string $baseDir Default is "", meaning it is pointing to the document root.
1072 * @param string $htmlDir The path to the parent HTML file's directory from the root of the archive.
1073 * @param string $backPath The path to get back to the root of the archive from $htmlDir.
1074 */
1075 protected function resolveMedia($source, &$internalPath, &$internalSrc, &$isSourceExternal, $baseDir = "", $htmlDir = "", $backPath = "") {
1076 if ($this->isFinalized) {
1077 return FALSE;
1078 }
1079 $mediaPath = NULL;
1080 $tmpFile;
1081
1082 if (preg_match('#^(http|ftp)s?://#i', $source) == 1) {
1083 $urlinfo = parse_url($source);
1084
1085 if (strpos($urlinfo['path'], $baseDir."/") !== FALSE) {
1086 $internalSrc = substr($urlinfo['path'], strpos($urlinfo['path'], $baseDir."/") + strlen($baseDir) + 1);
1087 }
1088 $internalPath = $urlinfo["scheme"] . "/" . $urlinfo["host"] . "/" . pathinfo($urlinfo["path"], PATHINFO_DIRNAME);
1089 $isSourceExternal = TRUE;
1090 $mediaPath = $this->getFileContents($source, true);
1091 $tmpFile = $mediaPath;
1092 } else if (strpos($source, "/") === 0) {
1093 $internalPath = pathinfo($source, PATHINFO_DIRNAME);
1094
1095 $mediaPath = $source;
1096 if (!file_exists($mediaPath)) {
1097 $mediaPath = $this->docRoot . $mediaPath;
1098 }
1099 } else {
1100 $internalPath = $htmlDir . "/" . preg_replace('#^[/\.]+#', '', pathinfo($source, PATHINFO_DIRNAME));
1101
1102 $mediaPath = $baseDir . "/" . $source;
1103 if (!file_exists($mediaPath)) {
1104 $mediaPath = $this->docRoot . $mediaPath;
1105 }
1106 }
1107
1108 if ($mediaPath !== FALSE) {
1109 $mime = $this->getMime($source);
1110 $internalPath = Zip::getRelativePath("media/" . $internalPath . "/" . $internalSrc);
1111
1112 if (!array_key_exists($internalPath, $this->fileList) &&
1113 $this->addLargeFile($internalPath, "m_" . $internalSrc, $mediaPath, $mime)) {
1114 $this->fileList[$internalPath] = $source;
1115 }
1116 if (isset($tmpFile)) {
1117 unlink($tmpFile);
1118 }
1119 return TRUE;
1120 }
1121 return FALSE;
1122 }
1123
1124 /**
1125 * Get Book Chapter count.
1126 *
1127 * @access public
1128 * @return number of chapters
1129 */
1130 function getChapterCount() {
1131 return $this->chapterCount;
1132 }
1133
1134 /**
1135 * Book title, mandatory.
1136 *
1137 * Used for the dc:title metadata parameter in the OPF file as well as the DocTitle attribute in the NCX file.
1138 *
1139 * @param string $title
1140 * @access public
1141 * @return bool $success
1142 */
1143 function setTitle($title) {
1144 if ($this->isFinalized) {
1145 return FALSE;
1146 }
1147 $this->title = $title;
1148 return TRUE;
1149 }
1150
1151 /**
1152 * Get Book title.
1153 *
1154 * @access public
1155 * @return $title
1156 */
1157 function getTitle() {
1158 return $this->title;
1159 }
1160
1161 /**
1162 * Book language, mandatory
1163 *
1164 * Use the RFC3066 Language codes, such as "en", "da", "fr" etc.
1165 * Defaults to "en".
1166 *
1167 * Used for the dc:language metadata parameter in the OPF file.
1168 *
1169 * @param string $language
1170 * @access public
1171 * @return bool $success
1172 */
1173 function setLanguage($language) {
1174 if ($this->isFinalized || mb_strlen($language) != 2) {
1175 return FALSE;
1176 }
1177 $this->language = $language;
1178 return TRUE;
1179 }
1180
1181 /**
1182 * Get Book language.
1183 *
1184 * @access public
1185 * @return $language
1186 */
1187 function getLanguage() {
1188 return $this->language;
1189 }
1190
1191 /**
1192 * Unique book identifier, mandatory.
1193 * Use the URI, or ISBN if available.
1194 *
1195 * An unambiguous reference to the resource within a given context.
1196 *
1197 * Recommended best practice is to identify the resource by means of a
1198 * string conforming to a formal identification system.
1199 *
1200 * Used for the dc:identifier metadata parameter in the OPF file, as well
1201 * as dtb:uid in the NCX file.
1202 *
1203 * Identifier type should only be:
1204 * EPub::IDENTIFIER_URI
1205 * EPub::IDENTIFIER_ISBN
1206 * EPub::IDENTIFIER_UUID
1207 *
1208 * @param string $identifier
1209 * @param string $identifierType
1210 * @access public
1211 * @return bool $success
1212 */
1213 function setIdentifier($identifier, $identifierType) {
1214 if ($this->isFinalized || ($identifierType !== EPub::IDENTIFIER_URI && $identifierType !== EPub::IDENTIFIER_ISBN && $identifierType !== EPub::IDENTIFIER_UUID)) {
1215 return FALSE;
1216 }
1217 $this->identifier = $identifier;
1218 $this->identifierType = $identifierType;
1219 return TRUE;
1220 }
1221
1222 /**
1223 * Get Book identifier.
1224 *
1225 * @access public
1226 * @return $identifier
1227 */
1228 function getIdentifier() {
1229 return $this->identifier;
1230 }
1231
1232 /**
1233 * Get Book identifierType.
1234 *
1235 * @access public
1236 * @return $identifierType
1237 */
1238 function getIdentifierType() {
1239 return $this->identifierType;
1240 }
1241
1242 /**
1243 * Book description, optional.
1244 *
1245 * An account of the resource.
1246 *
1247 * Description may include but is not limited to: an abstract, a table of
1248 * contents, a graphical representation, or a free-text account of the
1249 * resource.
1250 *
1251 * Used for the dc:source metadata parameter in the OPF file
1252 *
1253 * @param string $description
1254 * @access public
1255 * @return bool $success
1256 */
1257 function setDescription($description) {
1258 if ($this->isFinalized) {
1259 return FALSE;
1260 }
1261 $this->description = $description;
1262 return TRUE;
1263 }
1264
1265 /**
1266 * Get Book description.
1267 *
1268 * @access public
1269 * @return $description
1270 */
1271 function getDescription() {
1272 return $this->description;
1273 }
1274
1275 /**
1276 * Book author or creator, optional.
1277 * The $authorSortKey is basically how the name is to be sorted, usually
1278 * it's "Lastname, First names" where the $author is the straight
1279 * "Firstnames Lastname"
1280 *
1281 * An entity primarily responsible for making the resource.
1282 *
1283 * Examples of a Creator include a person, an organization, or a service.
1284 * Typically, the name of a Creator should be used to indicate the entity.
1285 *
1286 * Used for the dc:creator metadata parameter in the OPF file and the
1287 * docAuthor attribure in the NCX file.
1288 * The sort key is used for the opf:file-as attribute in dc:creator.
1289 *
1290 * @param string $author
1291 * @param string $authorSortKey
1292 * @access public
1293 * @return bool $success
1294 */
1295 function setAuthor($author, $authorSortKey) {
1296 if ($this->isFinalized) {
1297 return FALSE;
1298 }
1299 $this->author = $author;
1300 $this->authorSortKey = $authorSortKey;
1301 return TRUE;
1302 }
1303
1304 /**
1305 * Get Book author.
1306 *
1307 * @access public
1308 * @return $author
1309 */
1310 function getAuthor() {
1311 return $this->author;
1312 }
1313
1314 /**
1315 * Publisher Information, optional.
1316 *
1317 * An entity responsible for making the resource available.
1318 *
1319 * Examples of a Publisher include a person, an organization, or a service.
1320 * Typically, the name of a Publisher should be used to indicate the entity.
1321 *
1322 * Used for the dc:publisher and dc:relation metadata parameters in the OPF file.
1323 *
1324 * @param string $publisherName
1325 * @param string $publisherURL
1326 * @access public
1327 * @return bool $success
1328 */
1329 function setPublisher($publisherName, $publisherURL) {
1330 if ($this->isFinalized) {
1331 return FALSE;
1332 }
1333 $this->publisherName = $publisherName;
1334 $this->publisherURL = $publisherURL;
1335 return TRUE;
1336 }
1337
1338 /**
1339 * Get Book publisherName.
1340 *
1341 * @access public
1342 * @return $publisherName
1343 */
1344 function getPublisherName() {
1345 return $this->publisherName;
1346 }
1347
1348 /**
1349 * Get Book publisherURL.
1350 *
1351 * @access public
1352 * @return $publisherURL
1353 */
1354 function getPublisherURL() {
1355 return $this->publisherURL;
1356 }
1357
1358 /**
1359 * Release date, optional. If left blank, the time of the finalization will
1360 * be used.
1361 *
1362 * A point or period of time associated with an event in the lifecycle of
1363 * the resource.
1364 *
1365 * Date may be used to express temporal information at any level of
1366 * granularity. Recommended best practice is to use an encoding scheme,
1367 * such as the W3CDTF profile of ISO 8601 [W3CDTF].
1368 *
1369 * Used for the dc:date metadata parameter in the OPF file
1370 *
1371 * @param long $timestamp
1372 * @access public
1373 * @return bool $success
1374 */
1375 function setDate($timestamp) {
1376 if ($this->isFinalized) {
1377 return FALSE;
1378 }
1379 $this->date = $timestamp;
1380 $this->opf->date = $timestamp;
1381 return TRUE;
1382 }
1383
1384 /**
1385 * Get Book date.
1386 *
1387 * @access public
1388 * @return $date
1389 */
1390 function getDate() {
1391 return $this->date;
1392 }
1393
1394 /**
1395 * Book (copy)rights, optional.
1396 *
1397 * Information about rights held in and over the resource.
1398 *
1399 * Typically, rights information includes a statement about various
1400 * property rights associated with the resource, including intellectual
1401 * property rights.
1402 *
1403 * Used for the dc:rights metadata parameter in the OPF file
1404 *
1405 * @param string $rightsText
1406 * @access public
1407 * @return bool $success
1408 */
1409 function setRights($rightsText) {
1410 if ($this->isFinalized) {
1411 return FALSE;
1412 }
1413 $this->rights = $rightsText;
1414 return TRUE;
1415 }
1416
1417 /**
1418 * Get Book rights.
1419 *
1420 * @access public
1421 * @return $rights
1422 */
1423 function getRights() {
1424 return $this->rights;
1425 }
1426
1427 /**
1428 * Add book Subject.
1429 *
1430 * The topic of the resource.
1431 *
1432 * Typically, the subject will be represented using keywords, key phrases,
1433 * or classification codes. Recommended best practice is to use a
1434 * controlled vocabulary. To describe the spatial or temporal topic of the
1435 * resource, use the Coverage element.
1436 *
1437 * @param string $subject
1438 */
1439 function setSubject($subject) {
1440 if ($this->isFinalized) {
1441 return;
1442 }
1443 $this->opf->addDCMeta(DublinCore::SUBJECT, $this->decodeHtmlEntities($subject));
1444 }
1445
1446 /**
1447 * Book source URL, optional.
1448 *
1449 * A related resource from which the described resource is derived.
1450 *
1451 * The described resource may be derived from the related resource in whole
1452 * or in part. Recommended best practice is to identify the related
1453 * resource by means of a string conforming to a formal identification system.
1454 *
1455 * Used for the dc:source metadata parameter in the OPF file
1456 *
1457 * @param string $sourceURL
1458 * @access public
1459 * @return bool $success
1460 */
1461 function setSourceURL($sourceURL) {
1462 if ($this->isFinalized) {
1463 return FALSE;
1464 }
1465 $this->sourceURL = $sourceURL;
1466 return TRUE;
1467 }
1468
1469 /**
1470 * Get Book sourceURL.
1471 *
1472 * @access public
1473 * @return $sourceURL
1474 */
1475 function getSourceURL() {
1476 return $this->sourceURL;
1477 }
1478
1479 /**
1480 * Coverage, optional.
1481 *
1482 * The spatial or temporal topic of the resource, the spatial applicability
1483 * of the resource, or the jurisdiction under which the resource is relevant.
1484 *
1485 * Spatial topic and spatial applicability may be a named place or a location
1486 * specified by its geographic coordinates. Temporal topic may be a named
1487 * period, date, or date range. A jurisdiction may be a named administrative
1488 * entity or a geographic place to which the resource applies. Recommended
1489 * best practice is to use a controlled vocabulary such as the Thesaurus of
1490 * Geographic Names [TGN]. Where appropriate, named places or time periods
1491 * can be used in preference to numeric identifiers such as sets of
1492 * coordinates or date ranges.
1493 *
1494 * Used for the dc:coverage metadata parameter in the OPF file
1495 *
1496 * Same as ->addDublinCoreMetadata(DublinCore::COVERAGE, $coverage);
1497 *
1498 * @param string $coverage
1499 * @access public
1500 * @return bool $success
1501 */
1502 function setCoverage($coverage) {
1503 if ($this->isFinalized) {
1504 return FALSE;
1505 }
1506 $this->coverage = $coverage;
1507 return TRUE;
1508 }
1509
1510 /**
1511 * Get Book coverage.
1512 *
1513 * @access public
1514 * @return $coverage
1515 */
1516 function getCoverage() {
1517 return $this->coverage;
1518 }
1519
1520 /**
1521 * Set book Relation.
1522 *
1523 * A related resource.
1524 *
1525 * Recommended best practice is to identify the related resource by means
1526 * of a string conforming to a formal identification system.
1527 *
1528 * @param string $relation
1529 */
1530 function setRelation($relation) {
1531 if ($this->isFinalized) {
1532 return;
1533 }
1534 $this->relation = $relation;
1535 }
1536
1537 /**
1538 * Get the book relation.
1539 *
1540 * @return string The relation.
1541 */
1542 function getRelation() {
1543 return $this->relation;
1544 }
1545
1546 /**
1547 * Set book Generator.
1548 *
1549 * The generator is a meta tag added to the ncx file, it is not visible
1550 * from within the book, but is a kind of electronic watermark.
1551 *
1552 * @param string $generator
1553 */
1554 function setGenerator($generator) {
1555 if ($this->isFinalized) {
1556 return;
1557 }
1558 $this->generator = $generator;
1559 }
1560
1561 /**
1562 * Get the book relation.
1563 *
1564 * @return string The generator identity string.
1565 */
1566 function getGenerator() {
1567 return $this->generator;
1568 }
1569
1570 /**
1571 * Set ePub date formate to the short yyyy-mm-dd form, for compliance with
1572 * a bug in EpubCheck, prior to its version 1.1.
1573 *
1574 * The latest version of ePubCheck can be obtained here:
1575 * http://code.google.com/p/epubcheck/
1576 *
1577 * @access public
1578 * @return bool $success
1579 */
1580 function setShortDateFormat() {
1581 if ($this->isFinalized) {
1582 return FALSE;
1583 }
1584 $this->dateformat = $this->dateformatShort;
1585 return TRUE;
1586 }
1587
1588 /**
1589 * @Deprecated
1590 */
1591 function setIgnoreEmptyBuffer($ignoreEmptyBuffer = TRUE) {
1592 die ("Function was deprecated, functionality is no longer needed.");
1593 }
1594
1595 /**
1596 * Set the references title for the ePub 3 landmarks section
1597 *
1598 * @param string $referencesTitle
1599 * @param string $referencesId
1600 * @param string $referencesClass
1601 * @return bool
1602 */
1603 function setReferencesTitle($referencesTitle = "Guide", $referencesId = "", $referencesClass = "references") {
1604 if ($this->isFinalized) {
1605 return FALSE;
1606 }
1607 $this->ncx->referencesTitle = is_string($referencesTitle) ? trim($referencesTitle) : "Guide";
1608 $this->ncx->referencesId = is_string($referencesId) ? trim($referencesId) : "references";
1609 $this->ncx->referencesClass = is_string($referencesClass) ? trim($referencesClass) : "references";
1610 return TRUE;
1611 }
1612
1613 /**
1614 * Set the references title for the ePub 3 landmarks section
1615 *
1616 * @param bool $referencesTitle
1617 */
1618 function setisReferencesAddedToToc($isReferencesAddedToToc = TRUE) {
1619 if ($this->isFinalized) {
1620 return FALSE;
1621 }
1622 $this->isReferencesAddedToToc = $isReferencesAddedToToc === TRUE;
1623 return TRUE;
1624 }
1625
1626 /**
1627 * Get Book status.
1628 *
1629 * @access public
1630 * @return bool
1631 */
1632 function isFinalized() {
1633 return $this->isFinalized;
1634 }
1635
1636 /**
1637 * Build the Table of Contents. This is not strictly necessary, as most eReaders will build it from the navigation structure in the .ncx file.
1638 *
1639 * @param string $cssFileName Include a link to this css file in the TOC html.
1640 * @param string $tocCSSClass The TOC is a <div>, if you need special formatting, you can add a css class for that div. Default is "toc".
1641 * @param string $title Title of the Table of contents. Default is "Table of Contents". Use this for ie. languages other than English.
1642 * @param bool $addReferences include reference pages in the TOC, using the $referencesOrder array to determine the order of the pages in the TOC. Default is TRUE.
1643 * @param bool $addToIndex Add the TOC to the NCX index at the current leve/position. Default is FALSE
1644 * @param string $tocFileName Change teh default name of the TOC file. The default is "TOC.xhtml"
1645 */
1646 function buildTOC($cssFileName = NULL, $tocCSSClass = "toc", $title = "Table of Contents", $addReferences = TRUE, $addToIndex = FALSE, $tocFileName = "TOC.xhtml") {
1647 if ($this->isFinalized) {
1648 return FALSE;
1649 }
1650 $this->buildTOC = TRUE;
1651 $this->tocTitle = $title;
1652 $this->tocFileName = $this->normalizeFileName($tocFileName);
1653 if (!empty($cssFileName)) {
1654 $this->tocCSSFileName = $this->normalizeFileName($cssFileName);
1655 }
1656 $this->tocCSSClass = $tocCSSClass;
1657 $this->tocAddReferences = $addReferences;
1658
1659 $this->opf->addItemRef("ref_" . Reference::TABLE_OF_CONTENTS, FALSE);
1660 $this->opf->addReference(Reference::TABLE_OF_CONTENTS, $title, $this->tocFileName);
1661
1662 if ($addToIndex) {
1663 $navPoint = new NavPoint($this->decodeHtmlEntities($title), $this->tocFileName, "ref_" . Reference::TABLE_OF_CONTENTS);
1664 $this->ncx->addNavPoint($navPoint);
1665 } else {
1666 $this->ncx->referencesList[Reference::TABLE_OF_CONTENTS] = $this->tocFileName;
1667 $this->ncx->referencesName[Reference::TABLE_OF_CONTENTS] = $title;
1668 }
1669 }
1670
1671 private function finalizeTOC() {
1672 if (!$this->buildTOC) {
1673 return FALSE;
1674 }
1675
1676 if (empty($this->tocTitle)) {
1677 $this->tocTitle = "Table of Contents";
1678 }
1679
1680 $tocData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
1681
1682 if ($this->isEPubVersion2()) {
1683 $tocData .= "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n"
1684 . " \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
1685 . "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
1686 . "<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
1687 } else {
1688 $tocData .= "<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n"
1689 . "<head>\n<meta http-equiv=\"Default-Style\" content=\"text/html; charset=utf-8\" />\n";
1690 }
1691
1692 if (!empty($this->tocCssFileName)) {
1693 $tocData .= "<link rel=\"stylesheet\" type=\"text/css\" href=\"" . $this->tocCssFileName . "\" />\n";
1694 }
1695
1696 $tocData .= "<title>" . $this->tocTitle . "</title>\n"
1697 . "</head>\n"
1698 . "<body>\n"
1699 . "<h3>" . $this->tocTitle . "</h3>\n<div";
1700
1701 if (!empty($this->tocCSSClass)) {
1702 $tocData .= " class=\"" . $this->tocCSSClass . "\"";
1703 }
1704 $tocData .= ">\n";
1705
1706 while (list($item, $descriptive) = each($this->referencesOrder)) {
1707 if ($item === "text") {
1708 while (list($chapterName, $navPoint) = each($this->ncx->chapterList)) {
1709 $fileName = $navPoint->getContentSrc();
1710 $level = $navPoint->getLevel() -2;
1711 $tocData .= "\t<p>" . str_repeat(" &#160; &#160; &#160;", $level) . "<a href=\"" . $this->sanitizeFileName($fileName) . "\">" . $chapterName . "</a></p>\n";
1712 }
1713 } else if ($this->tocAddReferences === TRUE) {
1714 if (array_key_exists($item, $this->ncx->referencesList)) {
1715 $tocData .= "\t<p><a href=\"" . $this->ncx->referencesList[$item] . "\">" . $descriptive . "</a></p>\n";
1716 } else if ($item === "toc") {
1717 $tocData .= "\t<p><a href=\"TOC.xhtml\">" . $this->tocTitle . "</a></p>\n";
1718 } else if ($item === "cover" && $this->isCoverImageSet) {
1719 $tocData .= "\t<p><a href=\"CoverPage.xhtml\">" . $descriptive . "</a></p>\n";
1720 }
1721 }
1722 }
1723 $tocData .= "</div>\n</body>\n</html>\n";
1724
1725 $this->addReferencePage($this->tocTitle, $this->tocFileName, $tocData, Reference::TABLE_OF_CONTENTS);
1726
1727 }
1728
1729 /**
1730 * @return bool
1731 */
1732 function isEPubVersion2() {
1733 return $this->bookVersion === EPub::BOOK_VERSION_EPUB2;
1734 }
1735
1736 /**
1737 * @param string $cssFileName
1738 * @param string $title
1739 * @return string
1740 */
1741 function buildEPub3TOC($cssFileName = NULL, $title = "Table of Contents") {
1742 $this->ncx->referencesOrder = $this->referencesOrder;
1743 $this->ncx->setDocTitle($this->decodeHtmlEntities($this->title));
1744 return $this->ncx->finalizeEPub3($title, $cssFileName);
1745 }
1746
1747 /**
1748 * @param string $fileName
1749 * @param string $tocData
1750 * @return bool
1751 */
1752 function addEPub3TOC($fileName, $tocData) {
1753 if ($this->isEPubVersion2() || $this->isFinalized || array_key_exists($fileName, $this->fileList)) {
1754 return FALSE;
1755 }
1756 $fileName = Zip::getRelativePath($fileName);
1757 $fileName = preg_replace('#^[/\.]+#i', "", $fileName);
1758
1759 $this->zip->addFile($tocData, $this->bookRoot.$fileName);
1760
1761 $this->fileList[$fileName] = $fileName;
1762 $this->opf->addItem("toc", $fileName, "application/xhtml+xml", "nav");
1763 return TRUE;
1764 }
1765
1766 /**
1767 * Check for mandatory parameters and finalize the e-book.
1768 * Once finalized, the book is locked for further additions.
1769 *
1770 * @return bool $success
1771 */
1772 function finalize() {
1773 if ($this->isFinalized || $this->chapterCount == 0 || empty($this->title) || empty($this->language)) {
1774 return FALSE;
1775 }
1776
1777 if (empty($this->identifier) || empty($this->identifierType)) {
1778 $this->setIdentifier($this->createUUID(4), EPub::IDENTIFIER_UUID);
1779 }
1780
1781 if ($this->date == 0) {
1782 $this->date = time();
1783 }
1784
1785 if (empty($this->sourceURL)) {
1786 $this->sourceURL = $this->getCurrentPageURL();
1787 }
1788
1789 if (empty($this->publisherURL)) {
1790 $this->sourceURL = $this->getCurrentServerURL();
1791 }
1792
1793 // Generate OPF data:
1794 $this->opf->setIdent("BookId");
1795 $this->opf->initialize($this->title, $this->language, $this->identifier, $this->identifierType);
1796
1797 $DCdate = new DublinCore(DublinCore::DATE, gmdate($this->dateformat, $this->date));
1798 $DCdate->addOpfAttr("event", "publication");
1799 $this->opf->metadata->addDublinCore($DCdate);
1800
1801 if (!empty($this->description)) {
1802 $this->opf->addDCMeta(DublinCore::DESCRIPTION, $this->decodeHtmlEntities($this->description));
1803 }
1804
1805 if (!empty($this->publisherName)) {
1806 $this->opf->addDCMeta(DublinCore::PUBLISHER, $this->decodeHtmlEntities($this->publisherName));
1807 }
1808
1809 if (!empty($this->publisherURL)) {
1810 $this->opf->addDCMeta(DublinCore::RELATION, $this->decodeHtmlEntities($this->publisherURL));
1811 }
1812
1813 if (!empty($this->author)) {
1814 $author = $this->decodeHtmlEntities($this->author);
1815 $this->opf->addCreator($author, $this->decodeHtmlEntities($this->authorSortKey), MarcCode::AUTHOR);
1816 $this->ncx->setDocAuthor($author);
1817 }
1818
1819 if (!empty($this->rights)) {
1820 $this->opf->addDCMeta(DublinCore::RIGHTS, $this->decodeHtmlEntities($this->rights));
1821 }
1822
1823 if (!empty($this->coverage)) {
1824 $this->opf->addDCMeta(DublinCore::COVERAGE, $this->decodeHtmlEntities($this->coverage));
1825 }
1826
1827 if (!empty($this->sourceURL)) {
1828 $this->opf->addDCMeta(DublinCore::SOURCE, $this->sourceURL);
1829 }
1830
1831 if (!empty($this->relation)) {
1832 $this->opf->addDCMeta(DublinCore::RELATION, $this->decodeHtmlEntities($this->relation));
1833 }
1834
1835 if ($this->isCoverImageSet) {
1836 $this->opf->addMeta("cover", "coverImage");
1837 }
1838
1839 if (!empty($this->generator)) {
1840 $gen = $this->decodeHtmlEntities($this->generator);
1841 $this->opf->addMeta("generator", $gen);
1842 $this->ncx->addMetaEntry("dtb:generator", $gen);
1843 }
1844
1845 if ($this->EPubMark) {
1846 $this->opf->addMeta("generator", "EPub (Version " . self::VERSION . ") by A. Grandt, http://www.phpclasses.org/package/6115");
1847 }
1848
1849 reset($this->ncx->chapterList);
1850 list($firstChapterName, $firstChapterNavPoint) = each($this->ncx->chapterList);
1851 $firstChapterFileName = $firstChapterNavPoint->getContentSrc();
1852 $this->opf->addReference(Reference::TEXT, $this->decodeHtmlEntities($firstChapterName), $firstChapterFileName);
1853
1854 $this->ncx->setUid($this->identifier);
1855
1856 $this->ncx->setDocTitle($this->decodeHtmlEntities($this->title));
1857
1858 $this->ncx->referencesOrder = $this->referencesOrder;
1859 if ($this->isReferencesAddedToToc) {
1860 $this->ncx->finalizeReferences();
1861 }
1862
1863 $this->finalizeTOC();
1864
1865 if (!$this->isEPubVersion2()) {
1866 $this->addEPub3TOC("epub3toc.xhtml", $this->buildEPub3TOC());
1867 }
1868
1869 $opfFinal = $this->fixEncoding($this->opf->finalize());
1870 $ncxFinal = $this->fixEncoding($this->ncx->finalize());
1871
1872 if (mb_detect_encoding($opfFinal, 'UTF-8', true) === "UTF-8") {
1873 $this->zip->addFile($opfFinal, $this->bookRoot."book.opf");
1874 } else {
1875 $this->zip->addFile(mb_convert_encoding($opfFinal, "UTF-8"), $this->bookRoot."book.opf");
1876 }
1877
1878 if (mb_detect_encoding($ncxFinal, 'UTF-8', true) === "UTF-8") {
1879 $this->zip->addFile($ncxFinal, $this->bookRoot."book.ncx");
1880 } else {
1881 $this->zip->addFile(mb_convert_encoding($ncxFinal, "UTF-8"), $this->bookRoot."book.ncx");
1882 }
1883
1884 $this->opf = NULL;
1885 $this->ncx = NULL;
1886
1887 $this->isFinalized = TRUE;
1888 return TRUE;
1889 }
1890
1891 /**
1892 * Ensure the encoded string is a valid UTF-8 string.
1893 *
1894 * Note, that a mb_detect_encoding on the returned string will still return ASCII if the entire string is comprized of characters in the 1-127 range.
1895 *
1896 * @link: http://snippetdb.com/php/convert-string-to-utf-8-for-mysql
1897 * @param string $in_str
1898 * @return string converted string.
1899 */
1900 function fixEncoding($in_str) {
1901 if (mb_detect_encoding($in_str) == "UTF-8" && mb_check_encoding($in_str,"UTF-8")) {
1902 return $in_str;
1903 } else {
1904 return utf8_encode($in_str);
1905 }
1906 }
1907
1908 /**
1909 * Return the finalized book.
1910 *
1911 * @return string with the book in binary form.
1912 */
1913 function getBook() {
1914 if (!$this->isFinalized) {
1915 $this->finalize();
1916 }
1917
1918 return $this->zip->getZipData();
1919 }
1920
1921 /**
1922 * Remove disallowed characters from string to get a nearly safe filename
1923 *
1924 * @param string $fileName
1925 * @return mixed|string
1926 */
1927 function sanitizeFileName($fileName) {
1928 $fileName1 = str_replace($this->forbiddenCharacters, '', $fileName);
1929 $fileName2 = preg_replace('/[\s-]+/', '-', $fileName1);
1930 return trim($fileName2, '.-_');
1931
1932 }
1933
1934 /**
1935 * Cleanup the filepath, and remove leading . and / characters.
1936 *
1937 * Sometimes, when a path is generated from multiple fragments,
1938 * you can get something like "../data/html/../images/image.jpeg"
1939 * ePub files don't work well with that, this will normalize that
1940 * example path to "data/images/image.jpeg"
1941 *
1942 * @param string $fileName
1943 * @return string normalized filename
1944 */
1945 function normalizeFileName($fileName) {
1946 return preg_replace('#^[/\.]+#i', "", Zip::getRelativePath($fileName));
1947 }
1948
1949 /**
1950 * Save the ePub file to local disk.
1951 *
1952 * @param string $fileName
1953 * @param string $baseDir If empty baseDir is absolute to server path, if omitted it's relative to script path
1954 * @return The sent file name if successfull, FALSE if it failed.
1955 */
1956 function saveBook($fileName, $baseDir = '.') {
1957
1958 // Make fileName safe
1959 $fileName = $this->sanitizeFileName($fileName);
1960
1961 // Finalize book, if it's not done already
1962 if (!$this->isFinalized) {
1963 $this->finalize();
1964 }
1965
1966 if (stripos(strrev($fileName), "bupe.") !== 0) {
1967 $fileName .= ".epub";
1968 }
1969
1970 // Try to open file access
1971 $fh = fopen($baseDir.'/'.$fileName, "w");
1972
1973 if ($fh) {
1974 fputs($fh, $this->getBook());
1975 fclose($fh);
1976
1977 // if file is written return TRUE
1978 return $fileName;
1979 }
1980
1981 // return FALSE by default
1982 return FALSE;
1983 }
1984
1985 /**
1986 * Return the finalized book size.
1987 *
1988 * @return string
1989 */
1990 function getBookSize() {
1991 if (!$this->isFinalized) {
1992 $this->finalize();
1993 }
1994
1995 return $this->zip->getArchiveSize();
1996 }
1997
1998 /**
1999 * Send the book as a zip download
2000 *
2001 * Sending will fail if the output buffer is in use. You can override this limit by
2002 * calling setIgnoreEmptyBuffer(TRUE), though the function will still fail if that
2003 * buffer is not empty.
2004 *
2005 * @param string $fileName The name of the book without the .epub at the end.
2006 * @return The sent file name if successfull, FALSE if it failed.
2007 */
2008 function sendBook($fileName) {
2009 if (!$this->isFinalized) {
2010 $this->finalize();
2011 }
2012
2013 if (stripos(strrev($fileName), "bupe.") !== 0) {
2014 $fileName .= ".epub";
2015 }
2016
2017 if (TRUE === $this->zip->sendZip($fileName, "application/epub+zip")) {
2018 return $fileName;
2019 }
2020 return FALSE;
2021 }
2022
2023 /**
2024 * Generates an UUID.
2025 *
2026 * Default version (4) will generate a random UUID, version 3 will URL based UUID.
2027 *
2028 * Added for convinience
2029 *
2030 * @param int $bookVersion UUID version to retrieve, See lib.uuid.manual.html for details.
2031 * @param string $url
2032 * @return string The formatted uuid
2033 */
2034 function createUUID($bookVersion = 4, $url = NULL) {
2035 include_once("lib.uuid.php");
2036 return UUID::mint($bookVersion, $url, UUID::nsURL);
2037 }
2038
2039 /**
2040 * Get the url of the current page.
2041 * Example use: Default Source URL
2042 *
2043 * $return string Page URL.
2044 */
2045 function getCurrentPageURL() {
2046 $pageURL = $this->getCurrentServerURL() . filter_input(INPUT_SERVER, "REQUEST_URI");
2047 return $pageURL;
2048 }
2049
2050 /**
2051 * Get the url of the server.
2052 * Example use: Default Publisher URL
2053 *
2054 * $return string Server URL.
2055 */
2056 function getCurrentServerURL() {
2057 $serverURL = 'http';
2058 $https = filter_input(INPUT_SERVER, "HTTPS");
2059 $port = filter_input(INPUT_SERVER, "SERVER_PORT");
2060
2061 if ($https === "on") {
2062 $serverURL .= "s";
2063 }
2064 $serverURL .= "://" . filter_input(INPUT_SERVER, "SERVER_NAME");
2065 if ($port != "80") {
2066 $serverURL .= ":" . $port;
2067 }
2068 return $serverURL . '/';
2069 }
2070
2071 /**
2072 * Try to determine the mimetype of the file path.
2073 *
2074 * @param string $source Path
2075 * @return string mimetype, or FALSE.
2076 */
2077 function getMime($source) {
2078 return $this->mimetypes[pathinfo($source, PATHINFO_EXTENSION)];
2079 }
2080
2081 /**
2082 * Get an image from a file or url, return it resized if the image exceeds the $maxImageWidth or $maxImageHeight directives.
2083 *
2084 * The return value is an array.
2085 * ['width'] is the width of the image.
2086 * ['height'] is the height of the image.
2087 * ['mime'] is the mime type of the image. Resized images are always in jpeg format.
2088 * ['image'] is the image data.
2089 * ['ext'] is the extension of the image file.
2090 *
2091 * @param string $source path or url to file.
2092 * $return array
2093 */
2094 function getImage($source) {
2095 $width = -1;
2096 $height = -1;
2097 $mime = "application/octet-stream";
2098 $type = FALSE;
2099 $ext = "";
2100
2101
2102 $image = $this->getFileContents($source);
2103
2104 if ($image !== FALSE && strlen($image) > 0) {
2105 $imageFile = imagecreatefromstring($image);
2106 if ($imageFile !== false) {
2107 $width = ImageSX($imageFile);
2108 $height = ImageSY($imageFile);
2109 }
2110 if ($this->isExifInstalled) {
2111 @$type = exif_imagetype($source);
2112 $mime = image_type_to_mime_type($type);
2113 }
2114 if ($mime === "application/octet-stream") {
2115 $mime = $this->image_file_type_from_binary($image);
2116 }
2117 if ($mime === "application/octet-stream") {
2118 $mime = $this->getMimeTypeFromUrl($source);
2119 }
2120 } else {
2121 return FALSE;
2122 }
2123
2124 if ($width <= 0 || $height <= 0) {
2125 return FALSE;
2126 }
2127
2128 $ratio = 1;
2129
2130 if ($this->isGdInstalled) {
2131 if ($width > $this->maxImageWidth) {
2132 $ratio = $this->maxImageWidth/$width;
2133 }
2134 if ($height*$ratio > $this->maxImageHeight) {
2135 $ratio = $this->maxImageHeight/$height;
2136 }
2137
2138 if ($ratio < 1 || empty($mime) || ($this->isGifImagesEnabled !== FALSE && $mime == "image/gif")) {
2139 $image_o = imagecreatefromstring($image);
2140 $image_p = imagecreatetruecolor($width*$ratio, $height*$ratio);
2141
2142 if ($mime == "image/png") {
2143 imagealphablending($image_p, false);
2144 imagesavealpha($image_p, true);
2145 imagealphablending($image_o, true);
2146
2147 imagecopyresampled($image_p, $image_o, 0, 0, 0, 0, ($width*$ratio), ($height*$ratio), $width, $height);
2148 ob_start();
2149 imagepng($image_p, NULL, 9);
2150 $image = ob_get_contents();
2151 ob_end_clean();
2152
2153 $ext = "png";
2154 } else {
2155 imagecopyresampled($image_p, $image_o, 0, 0, 0, 0, ($width*$ratio), ($height*$ratio), $width, $height);
2156 ob_start();
2157 imagejpeg($image_p, NULL, 80);
2158 $image = ob_get_contents();
2159 ob_end_clean();
2160
2161 $mime = "image/jpeg";
2162 $ext = "jpg";
2163 }
2164 imagedestroy($image_o);
2165 imagedestroy($image_p);
2166 }
2167 }
2168
2169 if ($ext === "") {
2170 static $mimeToExt = array (
2171 'image/jpeg' => 'jpg',
2172 'image/gif' => 'gif',
2173 'image/png' => 'png'
2174 );
2175
2176 if (isset($mimeToExt[$mime])) {
2177 $ext = $mimeToExt[$mime];
2178 }
2179 }
2180
2181 $rv = array();
2182 $rv['width'] = $width*$ratio;
2183 $rv['height'] = $height*$ratio;
2184 $rv['mime'] = $mime;
2185 $rv['image'] = $image;
2186 $rv['ext'] = $ext;
2187
2188 return $rv;
2189 }
2190
2191 /**
2192 * Get file contents, using curl if available, else file_get_contents
2193 *
2194 * @param string $source
2195 * @return bool
2196 */
2197 function getFileContents($source, $toTempFile = FALSE) {
2198 $isExternal = preg_match('#^(http|ftp)s?://#i', $source) == 1;
2199
2200 if ($isExternal && $this->isCurlInstalled) {
2201 $ch = curl_init();
2202 $outFile = NULL;
2203 $fp = NULL;
2204 $res = FALSE;
2205 $info = array('http_code' => 500);
2206
2207 curl_setopt($ch, CURLOPT_HEADER, 0);
2208 curl_setopt($ch, CURLOPT_URL, str_replace(" ","%20",$source));
2209 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
2210 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2211 curl_setopt($ch, CURLOPT_BUFFERSIZE, 4096);
2212
2213 if ($toTempFile) {
2214 $outFile = tempnam(sys_get_temp_dir(), "EPub_v" . EPub::VERSION . "_");
2215 $fp = fopen($outFile, "w+b");
2216 curl_setopt($ch, CURLOPT_FILE, $fp);
2217
2218 $res = curl_exec($ch);
2219 $info = curl_getinfo($ch);
2220
2221 curl_close($ch);
2222 fclose($fp);
2223 } else {
2224 $res = curl_exec($ch);
2225 $info = curl_getinfo($ch);
2226
2227 curl_close($ch);
2228 }
2229
2230 if ($info['http_code'] == 200 && $res != false) {
2231 if ($toTempFile) {
2232 return $outFile;
2233 }
2234 return $res;
2235 }
2236 return FALSE;
2237 }
2238
2239 if ($this->isFileGetContentsInstalled && (!$isExternal || $this->isFileGetContentsExtInstalled)) {
2240 @$data = file_get_contents($source);
2241 return $data;
2242 }
2243 return FALSE;
2244 }
2245
2246 /**
2247 * get mime type from image data
2248 *
2249 * By fireweasel found on http://stackoverflow.com/questions/2207095/get-image-mimetype-from-resource-in-php-gd
2250 * @staticvar array $type
2251 * @param object $binary
2252 * @return string
2253 */
2254 function image_file_type_from_binary($binary) {
2255 $hits = 0;
2256 if (!preg_match(
2257 '/\A(?:(\xff\xd8\xff)|(GIF8[79]a)|(\x89PNG\x0d\x0a)|(BM)|(\x49\x49(?:\x2a\x00|\x00\x4a))|(FORM.{4}ILBM))/',
2258 $binary, $hits)) {
2259 return 'application/octet-stream';
2260 }
2261 static $type = array (
2262 1 => 'image/jpeg',
2263 2 => 'image/gif',
2264 3 => 'image/png',
2265 4 => 'image/x-windows-bmp',
2266 5 => 'image/tiff',
2267 6 => 'image/x-ilbm',
2268 );
2269 return $type[count($hits) - 1];
2270 }
2271
2272 /**
2273 * @param string $source URL Source
2274 * @return string MimeType
2275 */
2276 function getMimeTypeFromUrl($source) {
2277 $ext = FALSE;
2278
2279 $srev = strrev($source);
2280 $pos = strpos($srev, "?");
2281 if ($pos !== FALSE) {
2282 $srev = substr($srev, $pos+1);
2283 }
2284
2285 $pos = strpos($srev, ".");
2286 if ($pos !== FALSE) {
2287 $ext = strtolower(strrev(substr($srev, 0, $pos)));
2288 }
2289
2290 if ($ext !== FALSE) {
2291 return $this->getMimeTypeFromExtension($ext);
2292 }
2293 return "application/octet-stream";
2294 }
2295
2296 /**
2297 * @param string $ext Extension
2298 * @return string MimeType
2299 */
2300 function getMimeTypeFromExtension($ext) {
2301 switch ($ext) {
2302 case "jpg":
2303 case "jpe":
2304 case "jpeg":
2305 return 'image/jpeg';
2306 case "gif":
2307 return 'image/gif';
2308 case "png":
2309 return 'image/png';
2310 case "bmp":
2311 return 'image/x-windows-bmp';
2312 case "tif":
2313 case "tiff":
2314 case "cpt":
2315 return 'image/tiff';
2316 case "lbm":
2317 case "ilbm":
2318 return 'image/x-ilbm';
2319 default:
2320 return "application/octet-stream";
2321 }
2322 }
2323
2324 /**
2325 * Encode html code to use html entities, safeguarding it from potential character encoding peoblems
2326 * This function is a bit different from the vanilla htmlentities function in that it does not encode html tags.
2327 *
2328 * The regexp is taken from the PHP Manual discussion, it was written by user "busbyjon".
2329 * http://www.php.net/manual/en/function.htmlentities.php#90111
2330 *
2331 * @param string $string string to encode.
2332 */
2333 public function encodeHtml($string) {
2334 $string = strtr($string, $this->html_encoding_characters);
2335
2336 //return preg_replace("/&amp;(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/", "&\\1", $string);
2337 //return preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/", "&amp;", $string);
2338 return $string;
2339 }
2340
2341 /**
2342 * Helper function to create a DOM fragment with given markup.
2343 *
2344 * @author Adam Schmalhofer
2345 *
2346 * @param DOMDocument $dom
2347 * @param string $markup
2348 * @return DOMNode fragment in a node.
2349 */
2350 protected function createDomFragment($dom, $markup) {
2351 $node = $dom->createDocumentFragment();
2352 $node->appendXML($markup);
2353 return $node;
2354 }
2355
2356 /**
2357 * Retrieve an array of file names currently added to the book.
2358 * $key is the filename used in the book
2359 * $value is the original filename, will be the same as $key for most entries
2360 *
2361 * @return array file list
2362 */
2363 function getFileList() {
2364 return $this->fileList;
2365 }
2366
2367 /**
2368 * @deprecated Use Zip::getRelativePath($relPath) instead.
2369 */
2370 function relPath($relPath) {
2371 die ("Function was deprecated, use Zip::getRelativePath(\$relPath); instead");
2372 }
2373
2374 /**
2375 * Set default chapter target size.
2376 * Default is 250000 bytes, and minimum is 10240 bytes.
2377 *
2378 * @param int $size segment size in bytes
2379 * @return void
2380 */
2381 function setSplitSize($size) {
2382 $this->splitDefaultSize = (int)$size;
2383 if ($size < 10240) {
2384 $this->splitDefaultSize = 10240; // Making the file smaller than 10k is not a good idea.
2385 }
2386 }
2387
2388 /**
2389 * Get the chapter target size.
2390 *
2391 * @return $size
2392 */
2393 function getSplitSize() {
2394 return $this->splitDefaultSize;
2395 }
2396
2397 /**
2398 * Remove all non essential html tags and entities.
2399 *
2400 * @global type $htmlEntities
2401 * @param string $string
2402 * @return string with the stripped entities.
2403 */
2404 function decodeHtmlEntities($string) {
2405 global $htmlEntities;
2406
2407 $string = preg_replace('~\s*<br\s*/*\s*>\s*~i', "\n", $string);
2408 $string = preg_replace('~\s*</(p|div)\s*>\s*~i', "\n\n", $string);
2409 $string = preg_replace('~<[^>]*>~', '', $string);
2410
2411 $string = strtr($string, $htmlEntities);
2412
2413 $string = str_replace('&', '&amp;', $string);
2414 $string = str_replace('&amp;amp;', '&amp;', $string);
2415 $string = preg_replace('~&amp;(#x*[a-fA-F0-9]+;)~', '&\1', $string);
2416 $string = str_replace('<', '&lt;', $string);
2417 $string = str_replace('>', '&gt;', $string);
2418
2419 return $string;
2420 }
2421
2422 /**
2423 * Simply remove all HTML tags, brute force and no finesse.
2424 *
2425 * @param string $string html
2426 * @return string
2427 */
2428 function html2text($string) {
2429 return preg_replace('~<[^>]*>~', '', $string);
2430 }
2431
2432 /**
2433 * @return string
2434 */
2435 function getLog() {
2436 return $this->log->getLog();
2437 }
2438}
diff --git a/inc/3rdparty/libraries/PHPePub/EPubChapterSplitter.php b/inc/3rdparty/libraries/PHPePub/EPubChapterSplitter.php
deleted file mode 100644
index 1d44f238..00000000
--- a/inc/3rdparty/libraries/PHPePub/EPubChapterSplitter.php
+++ /dev/null
@@ -1,201 +0,0 @@
1<?php
2/**
3 * Split an HTML file into smaller html files, retaining the formatting and structure for the individual parts.
4 * What this splitter does is using DOM to try and retain any formatting in the file, including rebuilding the DOM tree for subsequent parts.
5 * Split size is considered max target size. The actual size is the result of an even split across the resulting files.
6 *
7 * @author A. Grandt <php@grandt.com>
8 * @copyright 2009-2014 A. Grandt
9 * @license GNU LGPL 2.1
10 * @link http://www.phpclasses.org/package/6115
11 * @link https://github.com/Grandt/PHPePub
12 * @version 3.20
13 */
14class EPubChapterSplitter {
15 const VERSION = 3.20;
16
17 private $splitDefaultSize = 250000;
18 private $bookVersion = EPub::BOOK_VERSION_EPUB2;
19
20 /**
21 *
22 * Enter description here ...
23 *
24 * @param unknown_type $ident
25 */
26 function setVersion($bookVersion) {
27 $this->bookVersion = is_string($bookVersion) ? trim($bookVersion) : EPub::BOOK_VERSION_EPUB2;
28 }
29
30 /**
31 * Set default chapter target size.
32 * Default is 250000 bytes, and minimum is 10240 bytes.
33 *
34 * @param $size segment size in bytes
35 * @return void
36 */
37 function setSplitSize($size) {
38 $this->splitDefaultSize = (int)$size;
39 if ($size < 10240) {
40 $this->splitDefaultSize = 10240; // Making the file smaller than 10k is not a good idea.
41 }
42 }
43
44 /**
45 * Get the chapter target size.
46 *
47 * @return $size
48 */
49 function getSplitSize() {
50 return $this->splitDefaultSize;
51 }
52
53 /**
54 * Split $chapter into multiple parts.
55 *
56 * The search string can either be a regular string or a PHP PECL Regular Expression pattern as defined here: http://www.php.net/manual/en/pcre.pattern.php
57 * If the search string is a regular string, the matching will be for lines in the HTML starting with the string given
58 *
59 * @param String $chapter XHTML file
60 * @param Bool $splitOnSearchString Split on chapter boundaries, Splitting on search strings disables the split size check.
61 * @param String $searchString Chapter string to search for can be fixed text, or a regular expression pattern.
62 *
63 * @return array with 1 or more parts
64 */
65 function splitChapter($chapter, $splitOnSearchString = false, $searchString = '/^Chapter\\ /i') {
66 $chapterData = array();
67 $isSearchRegexp = $splitOnSearchString && (preg_match('#^(\D|\S|\W).+\1[imsxeADSUXJu]*$#m', $searchString) == 1);
68 if ($splitOnSearchString && !$isSearchRegexp) {
69 $searchString = '#^<.+?>' . preg_quote($searchString, '#') . "#";
70 }
71
72 if (!$splitOnSearchString && strlen($chapter) <= $this->splitDefaultSize) {
73 return array($chapter);
74 }
75
76 $xmlDoc = new DOMDocument();
77 @$xmlDoc->loadHTML($chapter);
78
79 $head = $xmlDoc->getElementsByTagName("head");
80 $body = $xmlDoc->getElementsByTagName("body");
81
82 $htmlPos = stripos($chapter, "<html");
83 $htmlEndPos = stripos($chapter, ">", $htmlPos);
84 $newXML = substr($chapter, 0, $htmlEndPos+1) . "\n</html>";
85 if (strpos(trim($newXML), "<?xml ") === FALSE) {
86 $newXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" . $newXML;
87 }
88 $headerLength = strlen($newXML);
89
90 $files = array();
91 $chapterNames = array();
92 $domDepth = 0;
93 $domPath = array();
94 $domClonedPath = array();
95
96 $curFile = $xmlDoc->createDocumentFragment();
97 $files[] = $curFile;
98 $curParent = $curFile;
99 $curSize = 0;
100
101 $bodyLen = strlen($xmlDoc->saveXML($body->item(0)));
102 $headLen = strlen($xmlDoc->saveXML($head->item(0))) + $headerLength;
103
104 $partSize = $this->splitDefaultSize - $headLen;
105
106 if ($bodyLen > $partSize) {
107 $parts = ceil($bodyLen / $partSize);
108 $partSize = ($bodyLen / $parts) - $headLen;
109 }
110
111 $node = $body->item(0)->firstChild;
112
113 do {
114 $nodeData = $xmlDoc->saveXML($node);
115 $nodeLen = strlen($nodeData);
116
117 if ($nodeLen > $partSize && $node->hasChildNodes()) {
118 $domPath[] = $node;
119 $domClonedPath[] = $node->cloneNode(false);
120 $domDepth++;
121
122 $node = $node->firstChild;
123 }
124
125 $node2 = $node->nextSibling;
126
127 if ($node != null && $node->nodeName != "#text") {
128 $doSplit = false;
129 if ($splitOnSearchString) {
130 $doSplit = preg_match($searchString, $nodeData) == 1;
131 if ($doSplit) {
132 $chapterNames[] = trim($nodeData);
133 }
134 }
135
136 if ($curSize > 0 && ($doSplit || (!$splitOnSearchString && $curSize + $nodeLen > $partSize))) {
137 $curFile = $xmlDoc->createDocumentFragment();
138 $files[] = $curFile;
139 $curParent = $curFile;
140 if ($domDepth > 0) {
141 reset($domPath);
142 reset($domClonedPath);
143 $oneDomClonedPath = each($domClonedPath);
144 while ($oneDomClonedPath) {
145 list($k, $v) = $oneDomClonedPath;
146 $newParent = $v->cloneNode(false);
147 $curParent->appendChild($newParent);
148 $curParent = $newParent;
149 $oneDomClonedPath = each($domClonedPath);
150 }
151 }
152 $curSize = strlen($xmlDoc->saveXML($curFile));
153 }
154 $curParent->appendChild($node->cloneNode(true));
155 $curSize += $nodeLen;
156 }
157
158 $node = $node2;
159 while ($node == null && $domDepth > 0) {
160 $domDepth--;
161 $node = end($domPath)->nextSibling;
162 array_pop($domPath);
163 array_pop($domClonedPath);
164 $curParent = $curParent->parentNode;
165 }
166 } while ($node != null);
167
168 $curFile = null;
169 $curSize = 0;
170
171 $xml = new DOMDocument('1.0', $xmlDoc->xmlEncoding);
172 $xml->lookupPrefix("http://www.w3.org/1999/xhtml");
173 $xml->preserveWhiteSpace = false;
174 $xml->formatOutput = true;
175
176 for ($idx = 0; $idx < count($files); $idx++) {
177 $xml2Doc = new DOMDocument('1.0', $xmlDoc->xmlEncoding);
178 $xml2Doc->lookupPrefix("http://www.w3.org/1999/xhtml");
179 $xml2Doc->loadXML($newXML);
180 $html = $xml2Doc->getElementsByTagName("html")->item(0);
181 $html->appendChild($xml2Doc->importNode($head->item(0), true));
182 $body = $xml2Doc->createElement("body");
183 $html->appendChild($body);
184 $body->appendChild($xml2Doc->importNode($files[$idx], true));
185
186 // force pretty printing and correct formatting, should not be needed, but it is.
187 $xml->loadXML($xml2Doc->saveXML());
188
189 $doc = $xml->saveXML();
190
191 if ($this->bookVersion === EPub::BOOK_VERSION_EPUB3) {
192 $doc = preg_replace('#^\s*<!DOCTYPE\ .+?>\s*#im', '', $doc);
193 }
194
195 $chapterData[$splitOnSearchString ? $chapterNames[$idx] : $idx] = $doc;
196 }
197
198 return $chapterData;
199 }
200}
201?>
diff --git a/inc/3rdparty/libraries/PHPePub/Logger.php b/inc/3rdparty/libraries/PHPePub/Logger.php
deleted file mode 100644
index 314019cb..00000000
--- a/inc/3rdparty/libraries/PHPePub/Logger.php
+++ /dev/null
@@ -1,92 +0,0 @@
1<?php
2/**
3 * Simple log line aggregator.
4 *
5 * @author A. Grandt <php@grandt.com>
6 * @copyright 2012-2013 A. Grandt
7 * @license GNU LGPL, Attribution required for commercial implementations, requested for everything else.
8 * @version 1.00
9 */
10class Logger {
11 const VERSION = 1.00;
12
13 private $log = "";
14 private $tStart;
15 private $tLast;
16 private $name = NULL;
17 private $isLogging = FALSE;
18 private $isDebugging = FALSE;
19
20 /**
21 * Class constructor.
22 *
23 * @return void
24 */
25 function __construct($name = NULL, $isLogging = FALSE) {
26 if ($name === NULL) {
27 $this->name = "";
28 } else {
29 $this->name = $name . " : ";
30 }
31 $this->isLogging = $isLogging;
32 $this->start();
33 }
34
35 /**
36 * Class destructor
37 *
38 * @return void
39 * @TODO make sure elements in the destructor match the current class elements
40 */
41 function __destruct() {
42 unset($this->log);
43 }
44
45 function start() {
46 /* Prepare Logging. Just in case it's used. later */
47 if ($this->isLogging) {
48 $this->tStart = gettimeofday();
49 $this->tLast = $this->tStart;
50 $this->log = "<h1>Log: " . $this->name . "</h1>\n<pre>Started: " . gmdate("D, d M Y H:i:s T", $this->tStart['sec']) . "\n &#916; Start ; &#916; Last ;";
51 $this->logLine("Start");
52 }
53 }
54
55 function dumpInstalledModules() {
56 if ($this->isLogging) {
57 $isCurlInstalled = extension_loaded('curl') && function_exists('curl_version');
58 $isGdInstalled = extension_loaded('gd') && function_exists('gd_info');
59 $isExifInstalled = extension_loaded('exif') && function_exists('exif_imagetype');
60 $isFileGetContentsInstalled = function_exists('file_get_contents');
61 $isFileGetContentsExtInstalled = $isFileGetContentsInstalled && ini_get('allow_url_fopen');
62
63 $this->logLine("isCurlInstalled...............: " . ($isCurlInstalled ? "Yes" : "No"));
64 $this->logLine("isGdInstalled.................: " . ($isGdInstalled ? "Yes" : "No"));
65 $this->logLine("isExifInstalled...............: " . ($isExifInstalled ? "Yes" : "No"));
66 $this->logLine("isFileGetContentsInstalled....: " . ($isFileGetContentsInstalled ? "Yes" : "No"));
67 $this->logLine("isFileGetContentsExtInstalled.: " . ($isFileGetContentsExtInstalled ? "Yes" : "No"));
68 }
69 }
70
71 function logLine($line) {
72 if ($this->isLogging) {
73 $tTemp = gettimeofday();
74 $tS = $this->tStart['sec'] + (((int)($this->tStart['usec']/100))/10000);
75 $tL = $this->tLast['sec'] + (((int)($this->tLast['usec']/100))/10000);
76 $tT = $tTemp['sec'] + (((int)($tTemp['usec']/100))/10000);
77
78 $logline = sprintf("\n+%08.04f; +%08.04f; ", ($tT-$tS), ($tT-$tL)) . $this->name . $line;
79 $this->log .= $logline;
80 $this->tLast = $tTemp;
81
82 if ($this->isDebugging) {
83 echo "<pre>" . $logline . "\n</pre>\n";
84 }
85 }
86 }
87
88 function getLog() {
89 return $this->log;
90 }
91}
92?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/PHPePub/Zip.php b/inc/3rdparty/libraries/PHPePub/Zip.php
deleted file mode 100644
index 01e03566..00000000
--- a/inc/3rdparty/libraries/PHPePub/Zip.php
+++ /dev/null
@@ -1,818 +0,0 @@
1<?php
2/**
3 * Class to create and manage a Zip file.
4 *
5 * Initially inspired by CreateZipFile by Rochak Chauhan www.rochakchauhan.com (http://www.phpclasses.org/browse/package/2322.html)
6 * and
7 * http://www.pkware.com/documents/casestudies/APPNOTE.TXT Zip file specification.
8 *
9 * License: GNU LGPL, Attribution required for commercial implementations, requested for everything else.
10 *
11 * @author A. Grandt <php@grandt.com>
12 * @copyright 2009-2014 A. Grandt
13 * @license GNU LGPL 2.1
14 * @link http://www.phpclasses.org/package/6110
15 * @link https://github.com/Grandt/PHPZip
16 * @version 1.60
17 */
18class Zip {
19 const VERSION = 1.60;
20
21 const ZIP_LOCAL_FILE_HEADER = "\x50\x4b\x03\x04"; // Local file header signature
22 const ZIP_CENTRAL_FILE_HEADER = "\x50\x4b\x01\x02"; // Central file header signature
23 const ZIP_END_OF_CENTRAL_DIRECTORY = "\x50\x4b\x05\x06\x00\x00\x00\x00"; //end of Central directory record
24
25 const EXT_FILE_ATTR_DIR = 010173200020; // Permission 755 drwxr-xr-x = (((S_IFDIR | 0755) << 16) | S_DOS_D);
26 const EXT_FILE_ATTR_FILE = 020151000040; // Permission 644 -rw-r--r-- = (((S_IFREG | 0644) << 16) | S_DOS_A);
27
28 const ATTR_VERSION_TO_EXTRACT = "\x14\x00"; // Version needed to extract
29 const ATTR_MADE_BY_VERSION = "\x1E\x03"; // Made By Version
30
31 // Unix file types
32 const S_IFIFO = 0010000; // named pipe (fifo)
33 const S_IFCHR = 0020000; // character special
34 const S_IFDIR = 0040000; // directory
35 const S_IFBLK = 0060000; // block special
36 const S_IFREG = 0100000; // regular
37 const S_IFLNK = 0120000; // symbolic link
38 const S_IFSOCK = 0140000; // socket
39
40 // setuid/setgid/sticky bits, the same as for chmod:
41
42 const S_ISUID = 0004000; // set user id on execution
43 const S_ISGID = 0002000; // set group id on execution
44 const S_ISTXT = 0001000; // sticky bit
45
46 // And of course, the other 12 bits are for the permissions, the same as for chmod:
47 // When addding these up, you can also just write the permissions as a simgle octal number
48 // ie. 0755. The leading 0 specifies octal notation.
49 const S_IRWXU = 0000700; // RWX mask for owner
50 const S_IRUSR = 0000400; // R for owner
51 const S_IWUSR = 0000200; // W for owner
52 const S_IXUSR = 0000100; // X for owner
53 const S_IRWXG = 0000070; // RWX mask for group
54 const S_IRGRP = 0000040; // R for group
55 const S_IWGRP = 0000020; // W for group
56 const S_IXGRP = 0000010; // X for group
57 const S_IRWXO = 0000007; // RWX mask for other
58 const S_IROTH = 0000004; // R for other
59 const S_IWOTH = 0000002; // W for other
60 const S_IXOTH = 0000001; // X for other
61 const S_ISVTX = 0001000; // save swapped text even after use
62
63 // Filetype, sticky and permissions are added up, and shifted 16 bits left BEFORE adding the DOS flags.
64
65 // DOS file type flags, we really only use the S_DOS_D flag.
66
67 const S_DOS_A = 0000040; // DOS flag for Archive
68 const S_DOS_D = 0000020; // DOS flag for Directory
69 const S_DOS_V = 0000010; // DOS flag for Volume
70 const S_DOS_S = 0000004; // DOS flag for System
71 const S_DOS_H = 0000002; // DOS flag for Hidden
72 const S_DOS_R = 0000001; // DOS flag for Read Only
73
74 private $zipMemoryThreshold = 1048576; // Autocreate tempfile if the zip data exceeds 1048576 bytes (1 MB)
75
76 private $zipData = NULL;
77 private $zipFile = NULL;
78 private $zipComment = NULL;
79 private $cdRec = array(); // central directory
80 private $offset = 0;
81 private $isFinalized = FALSE;
82 private $addExtraField = TRUE;
83
84 private $streamChunkSize = 65536;
85 private $streamFilePath = NULL;
86 private $streamTimestamp = NULL;
87 private $streamFileComment = NULL;
88 private $streamFile = NULL;
89 private $streamData = NULL;
90 private $streamFileLength = 0;
91 private $streamExtFileAttr = null;
92
93 /**
94 * Constructor.
95 *
96 * @param boolean $useZipFile Write temp zip data to tempFile? Default FALSE
97 */
98 function __construct($useZipFile = FALSE) {
99 if ($useZipFile) {
100 $this->zipFile = tmpfile();
101 } else {
102 $this->zipData = "";
103 }
104 }
105
106 function __destruct() {
107 if (is_resource($this->zipFile)) {
108 fclose($this->zipFile);
109 }
110 $this->zipData = NULL;
111 }
112
113 /**
114 * Extra fields on the Zip directory records are Unix time codes needed for compatibility on the default Mac zip archive tool.
115 * These are enabled as default, as they do no harm elsewhere and only add 26 bytes per file added.
116 *
117 * @param bool $setExtraField TRUE (default) will enable adding of extra fields, anything else will disable it.
118 */
119 function setExtraField($setExtraField = TRUE) {
120 $this->addExtraField = ($setExtraField === TRUE);
121 }
122
123 /**
124 * Set Zip archive comment.
125 *
126 * @param string $newComment New comment. NULL to clear.
127 * @return bool $success
128 */
129 public function setComment($newComment = NULL) {
130 if ($this->isFinalized) {
131 return FALSE;
132 }
133 $this->zipComment = $newComment;
134
135 return TRUE;
136 }
137
138 /**
139 * Set zip file to write zip data to.
140 * This will cause all present and future data written to this class to be written to this file.
141 * This can be used at any time, even after the Zip Archive have been finalized. Any previous file will be closed.
142 * Warning: If the given file already exists, it will be overwritten.
143 *
144 * @param string $fileName
145 * @return bool $success
146 */
147 public function setZipFile($fileName) {
148 if (is_file($fileName)) {
149 unlink($fileName);
150 }
151 $fd=fopen($fileName, "x+b");
152 if (is_resource($this->zipFile)) {
153 rewind($this->zipFile);
154 while (!feof($this->zipFile)) {
155 fwrite($fd, fread($this->zipFile, $this->streamChunkSize));
156 }
157
158 fclose($this->zipFile);
159 } else {
160 fwrite($fd, $this->zipData);
161 $this->zipData = NULL;
162 }
163 $this->zipFile = $fd;
164
165 return TRUE;
166 }
167
168 /**
169 * Add an empty directory entry to the zip archive.
170 * Basically this is only used if an empty directory is added.
171 *
172 * @param string $directoryPath Directory Path and name to be added to the archive.
173 * @param int $timestamp (Optional) Timestamp for the added directory, if omitted or set to 0, the current time will be used.
174 * @param string $fileComment (Optional) Comment to be added to the archive for this directory. To use fileComment, timestamp must be given.
175 * @param int $extFileAttr (Optional) The external file reference, use generateExtAttr to generate this.
176 * @return bool $success
177 */
178 public function addDirectory($directoryPath, $timestamp = 0, $fileComment = NULL, $extFileAttr = self::EXT_FILE_ATTR_DIR) {
179 if ($this->isFinalized) {
180 return FALSE;
181 }
182 $directoryPath = str_replace("\\", "/", $directoryPath);
183 $directoryPath = rtrim($directoryPath, "/");
184
185 if (strlen($directoryPath) > 0) {
186 $this->buildZipEntry($directoryPath.'/', $fileComment, "\x00\x00", "\x00\x00", $timestamp, "\x00\x00\x00\x00", 0, 0, $extFileAttr);
187 return TRUE;
188 }
189 return FALSE;
190 }
191
192 /**
193 * Add a file to the archive at the specified location and file name.
194 *
195 * @param string $data File data.
196 * @param string $filePath Filepath and name to be used in the archive.
197 * @param int $timestamp (Optional) Timestamp for the added file, if omitted or set to 0, the current time will be used.
198 * @param string $fileComment (Optional) Comment to be added to the archive for this file. To use fileComment, timestamp must be given.
199 * @param bool $compress (Optional) Compress file, if set to FALSE the file will only be stored. Default TRUE.
200 * @param int $extFileAttr (Optional) The external file reference, use generateExtAttr to generate this.
201 * @return bool $success
202 */
203 public function addFile($data, $filePath, $timestamp = 0, $fileComment = NULL, $compress = TRUE, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
204 if ($this->isFinalized) {
205 return FALSE;
206 }
207
208 if (is_resource($data) && get_resource_type($data) == "stream") {
209 $this->addLargeFile($data, $filePath, $timestamp, $fileComment, $extFileAttr);
210 return FALSE;
211 }
212
213 $gzData = "";
214 $gzType = "\x08\x00"; // Compression type 8 = deflate
215 $gpFlags = "\x00\x00"; // General Purpose bit flags for compression type 8 it is: 0=Normal, 1=Maximum, 2=Fast, 3=super fast compression.
216 $dataLength = strlen($data);
217 $fileCRC32 = pack("V", crc32($data));
218
219 if ($compress) {
220 $gzTmp = gzcompress($data);
221 $gzData = substr(substr($gzTmp, 0, strlen($gzTmp) - 4), 2); // gzcompress adds a 2 byte header and 4 byte CRC we can't use.
222 // The 2 byte header does contain useful data, though in this case the 2 parameters we'd be interrested in will always be 8 for compression type, and 2 for General purpose flag.
223 $gzLength = strlen($gzData);
224 } else {
225 $gzLength = $dataLength;
226 }
227
228 if ($gzLength >= $dataLength) {
229 $gzLength = $dataLength;
230 $gzData = $data;
231 $gzType = "\x00\x00"; // Compression type 0 = stored
232 $gpFlags = "\x00\x00"; // Compression type 0 = stored
233 }
234
235 if (!is_resource($this->zipFile) && ($this->offset + $gzLength) > $this->zipMemoryThreshold) {
236 $this->zipflush();
237 }
238
239 $this->buildZipEntry($filePath, $fileComment, $gpFlags, $gzType, $timestamp, $fileCRC32, $gzLength, $dataLength, $extFileAttr);
240
241 $this->zipwrite($gzData);
242
243 return TRUE;
244 }
245
246 /**
247 * Add the content to a directory.
248 *
249 * @author Adam Schmalhofer <Adam.Schmalhofer@gmx.de>
250 * @author A. Grandt
251 *
252 * @param string $realPath Path on the file system.
253 * @param string $zipPath Filepath and name to be used in the archive.
254 * @param bool $recursive Add content recursively, default is TRUE.
255 * @param bool $followSymlinks Follow and add symbolic links, if they are accessible, default is TRUE.
256 * @param array &$addedFiles Reference to the added files, this is used to prevent duplicates, efault is an empty array.
257 * If you start the function by parsing an array, the array will be populated with the realPath
258 * and zipPath kay/value pairs added to the archive by the function.
259 * @param bool $overrideFilePermissions Force the use of the file/dir permissions set in the $extDirAttr
260 * and $extFileAttr parameters.
261 * @param int $extDirAttr Permissions for directories.
262 * @param int $extFileAttr Permissions for files.
263 */
264 public function addDirectoryContent($realPath, $zipPath, $recursive = TRUE, $followSymlinks = TRUE, &$addedFiles = array(),
265 $overrideFilePermissions = FALSE, $extDirAttr = self::EXT_FILE_ATTR_DIR, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
266 if (file_exists($realPath) && !isset($addedFiles[realpath($realPath)])) {
267 if (is_dir($realPath)) {
268 if ($overrideFilePermissions) {
269 $this->addDirectory($zipPath, 0, null, $extDirAttr);
270 } else {
271 $this->addDirectory($zipPath, 0, null, self::getFileExtAttr($realPath));
272 }
273 }
274
275 $addedFiles[realpath($realPath)] = $zipPath;
276
277 $iter = new DirectoryIterator($realPath);
278 foreach ($iter as $file) {
279 if ($file->isDot()) {
280 continue;
281 }
282 $newRealPath = $file->getPathname();
283 $newZipPath = self::pathJoin($zipPath, $file->getFilename());
284
285 if (file_exists($newRealPath) && ($followSymlinks === TRUE || !is_link($newRealPath))) {
286 if ($file->isFile()) {
287 $addedFiles[realpath($newRealPath)] = $newZipPath;
288 if ($overrideFilePermissions) {
289 $this->addLargeFile($newRealPath, $newZipPath, 0, null, $extFileAttr);
290 } else {
291 $this->addLargeFile($newRealPath, $newZipPath, 0, null, self::getFileExtAttr($newRealPath));
292 }
293 } else if ($recursive === TRUE) {
294 $this->addDirectoryContent($newRealPath, $newZipPath, $recursive, $followSymlinks, $addedFiles, $overrideFilePermissions, $extDirAttr, $extFileAttr);
295 } else {
296 if ($overrideFilePermissions) {
297 $this->addDirectory($zipPath, 0, null, $extDirAttr);
298 } else {
299 $this->addDirectory($zipPath, 0, null, self::getFileExtAttr($newRealPath));
300 }
301 }
302 }
303 }
304 }
305 }
306
307 /**
308 * Add a file to the archive at the specified location and file name.
309 *
310 * @param string $dataFile File name/path.
311 * @param string $filePath Filepath and name to be used in the archive.
312 * @param int $timestamp (Optional) Timestamp for the added file, if omitted or set to 0, the current time will be used.
313 * @param string $fileComment (Optional) Comment to be added to the archive for this file. To use fileComment, timestamp must be given.
314 * @param int $extFileAttr (Optional) The external file reference, use generateExtAttr to generate this.
315 * @return bool $success
316 */
317 public function addLargeFile($dataFile, $filePath, $timestamp = 0, $fileComment = NULL, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
318 if ($this->isFinalized) {
319 return FALSE;
320 }
321
322 if (is_string($dataFile) && is_file($dataFile)) {
323 $this->processFile($dataFile, $filePath, $timestamp, $fileComment, $extFileAttr);
324 } else if (is_resource($dataFile) && get_resource_type($dataFile) == "stream") {
325 $fh = $dataFile;
326 $this->openStream($filePath, $timestamp, $fileComment, $extFileAttr);
327
328 while (!feof($fh)) {
329 $this->addStreamData(fread($fh, $this->streamChunkSize));
330 }
331 $this->closeStream($this->addExtraField);
332 }
333 return TRUE;
334 }
335
336 /**
337 * Create a stream to be used for large entries.
338 *
339 * @param string $filePath Filepath and name to be used in the archive.
340 * @param int $timestamp (Optional) Timestamp for the added file, if omitted or set to 0, the current time will be used.
341 * @param string $fileComment (Optional) Comment to be added to the archive for this file. To use fileComment, timestamp must be given.
342 * @param int $extFileAttr (Optional) The external file reference, use generateExtAttr to generate this.
343 * @return bool $success
344 */
345 public function openStream($filePath, $timestamp = 0, $fileComment = null, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
346 if (!function_exists('sys_get_temp_dir')) {
347 die ("ERROR: Zip " . self::VERSION . " requires PHP version 5.2.1 or above if large files are used.");
348 }
349
350 if ($this->isFinalized) {
351 return FALSE;
352 }
353
354 $this->zipflush();
355
356 if (strlen($this->streamFilePath) > 0) {
357 $this->closeStream();
358 }
359
360 $this->streamFile = tempnam(sys_get_temp_dir(), 'Zip');
361 $this->streamData = fopen($this->streamFile, "wb");
362 $this->streamFilePath = $filePath;
363 $this->streamTimestamp = $timestamp;
364 $this->streamFileComment = $fileComment;
365 $this->streamFileLength = 0;
366 $this->streamExtFileAttr = $extFileAttr;
367
368 return TRUE;
369 }
370
371 /**
372 * Add data to the open stream.
373 *
374 * @param string $data
375 * @return mixed length in bytes added or FALSE if the archive is finalized or there are no open stream.
376 */
377 public function addStreamData($data) {
378 if ($this->isFinalized || strlen($this->streamFilePath) == 0) {
379 return FALSE;
380 }
381
382 $length = fwrite($this->streamData, $data, strlen($data));
383 if ($length != strlen($data)) {
384 die ("<p>Length mismatch</p>\n");
385 }
386 $this->streamFileLength += $length;
387
388 return $length;
389 }
390
391 /**
392 * Close the current stream.
393 *
394 * @return bool $success
395 */
396 public function closeStream() {
397 if ($this->isFinalized || strlen($this->streamFilePath) == 0) {
398 return FALSE;
399 }
400
401 fflush($this->streamData);
402 fclose($this->streamData);
403
404 $this->processFile($this->streamFile, $this->streamFilePath, $this->streamTimestamp, $this->streamFileComment, $this->streamExtFileAttr);
405
406 $this->streamData = null;
407 $this->streamFilePath = null;
408 $this->streamTimestamp = null;
409 $this->streamFileComment = null;
410 $this->streamFileLength = 0;
411 $this->streamExtFileAttr = null;
412
413 // Windows is a little slow at times, so a millisecond later, we can unlink this.
414 unlink($this->streamFile);
415
416 $this->streamFile = null;
417
418 return TRUE;
419 }
420
421 private function processFile($dataFile, $filePath, $timestamp = 0, $fileComment = null, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
422 if ($this->isFinalized) {
423 return FALSE;
424 }
425
426 $tempzip = tempnam(sys_get_temp_dir(), 'ZipStream');
427
428 $zip = new ZipArchive;
429 if ($zip->open($tempzip) === TRUE) {
430 $zip->addFile($dataFile, 'file');
431 $zip->close();
432 }
433
434 $file_handle = fopen($tempzip, "rb");
435 $stats = fstat($file_handle);
436 $eof = $stats['size']-72;
437
438 fseek($file_handle, 6);
439
440 $gpFlags = fread($file_handle, 2);
441 $gzType = fread($file_handle, 2);
442 fread($file_handle, 4);
443 $fileCRC32 = fread($file_handle, 4);
444 $v = unpack("Vval", fread($file_handle, 4));
445 $gzLength = $v['val'];
446 $v = unpack("Vval", fread($file_handle, 4));
447 $dataLength = $v['val'];
448
449 $this->buildZipEntry($filePath, $fileComment, $gpFlags, $gzType, $timestamp, $fileCRC32, $gzLength, $dataLength, $extFileAttr);
450
451 fseek($file_handle, 34);
452 $pos = 34;
453
454 while (!feof($file_handle) && $pos < $eof) {
455 $datalen = $this->streamChunkSize;
456 if ($pos + $this->streamChunkSize > $eof) {
457 $datalen = $eof-$pos;
458 }
459 $data = fread($file_handle, $datalen);
460 $pos += $datalen;
461
462 $this->zipwrite($data);
463 }
464
465 fclose($file_handle);
466
467 unlink($tempzip);
468 }
469
470 /**
471 * Close the archive.
472 * A closed archive can no longer have new files added to it.
473 *
474 * @return bool $success
475 */
476 public function finalize() {
477 if (!$this->isFinalized) {
478 if (strlen($this->streamFilePath) > 0) {
479 $this->closeStream();
480 }
481 $cd = implode("", $this->cdRec);
482
483 $cdRecSize = pack("v", sizeof($this->cdRec));
484 $cdRec = $cd . self::ZIP_END_OF_CENTRAL_DIRECTORY
485 . $cdRecSize . $cdRecSize
486 . pack("VV", strlen($cd), $this->offset);
487 if (!empty($this->zipComment)) {
488 $cdRec .= pack("v", strlen($this->zipComment)) . $this->zipComment;
489 } else {
490 $cdRec .= "\x00\x00";
491 }
492
493 $this->zipwrite($cdRec);
494
495 $this->isFinalized = TRUE;
496 $this->cdRec = NULL;
497
498 return TRUE;
499 }
500 return FALSE;
501 }
502
503 /**
504 * Get the handle ressource for the archive zip file.
505 * If the zip haven't been finalized yet, this will cause it to become finalized
506 *
507 * @return zip file handle
508 */
509 public function getZipFile() {
510 if (!$this->isFinalized) {
511 $this->finalize();
512 }
513
514 $this->zipflush();
515
516 rewind($this->zipFile);
517
518 return $this->zipFile;
519 }
520
521 /**
522 * Get the zip file contents
523 * If the zip haven't been finalized yet, this will cause it to become finalized
524 *
525 * @return zip data
526 */
527 public function getZipData() {
528 if (!$this->isFinalized) {
529 $this->finalize();
530 }
531 if (!is_resource($this->zipFile)) {
532 return $this->zipData;
533 } else {
534 rewind($this->zipFile);
535 $filestat = fstat($this->zipFile);
536 return fread($this->zipFile, $filestat['size']);
537 }
538 }
539
540 /**
541 * Send the archive as a zip download
542 *
543 * @param String $fileName The name of the Zip archive, in ISO-8859-1 (or ASCII) encoding, ie. "archive.zip". Optional, defaults to NULL, which means that no ISO-8859-1 encoded file name will be specified.
544 * @param String $contentType Content mime type. Optional, defaults to "application/zip".
545 * @param String $utf8FileName The name of the Zip archive, in UTF-8 encoding. Optional, defaults to NULL, which means that no UTF-8 encoded file name will be specified.
546 * @param bool $inline Use Content-Disposition with "inline" instead of "attached". Optional, defaults to FALSE.
547 * @return bool $success
548 */
549 function sendZip($fileName = null, $contentType = "application/zip", $utf8FileName = null, $inline = false) {
550 if (!$this->isFinalized) {
551 $this->finalize();
552 }
553
554 $headerFile = null;
555 $headerLine = null;
556 if (!headers_sent($headerFile, $headerLine) or die("<p><strong>Error:</strong> Unable to send file $fileName. HTML Headers have already been sent from <strong>$headerFile</strong> in line <strong>$headerLine</strong></p>")) {
557 if ((ob_get_contents() === FALSE || ob_get_contents() == '') or die("\n<p><strong>Error:</strong> Unable to send file <strong>$fileName</strong>. Output buffer contains the following text (typically warnings or errors):<br>" . htmlentities(ob_get_contents()) . "</p>")) {
558 if (ini_get('zlib.output_compression')) {
559 ini_set('zlib.output_compression', 'Off');
560 }
561
562 header("Pragma: public");
563 header("Last-Modified: " . gmdate("D, d M Y H:i:s T"));
564 header("Expires: 0");
565 header("Accept-Ranges: bytes");
566 header("Connection: close");
567 header("Content-Type: " . $contentType);
568 $cd = "Content-Disposition: ";
569 if ($inline) {
570 $cd .= "inline";
571 } else{
572 $cd .= "attached";
573 }
574 if ($fileName) {
575 $cd .= '; filename="' . $fileName . '"';
576 }
577 if ($utf8FileName) {
578 $cd .= "; filename*=UTF-8''" . rawurlencode($utf8FileName);
579 }
580 header($cd);
581 header("Content-Length: ". $this->getArchiveSize());
582
583 if (!is_resource($this->zipFile)) {
584 echo $this->zipData;
585 } else {
586 rewind($this->zipFile);
587
588 while (!feof($this->zipFile)) {
589 echo fread($this->zipFile, $this->streamChunkSize);
590 }
591 }
592 }
593 return TRUE;
594 }
595 return FALSE;
596 }
597
598 /**
599 * Return the current size of the archive
600 *
601 * @return $size Size of the archive
602 */
603 public function getArchiveSize() {
604 if (!is_resource($this->zipFile)) {
605 return strlen($this->zipData);
606 }
607 $filestat = fstat($this->zipFile);
608
609 return $filestat['size'];
610 }
611
612 /**
613 * Calculate the 2 byte dostime used in the zip entries.
614 *
615 * @param int $timestamp
616 * @return 2-byte encoded DOS Date
617 */
618 private function getDosTime($timestamp = 0) {
619 $timestamp = (int)$timestamp;
620 $oldTZ = @date_default_timezone_get();
621 date_default_timezone_set('UTC');
622 $date = ($timestamp == 0 ? getdate() : getdate($timestamp));
623 date_default_timezone_set($oldTZ);
624 if ($date["year"] >= 1980) {
625 return pack("V", (($date["mday"] + ($date["mon"] << 5) + (($date["year"]-1980) << 9)) << 16) |
626 (($date["seconds"] >> 1) + ($date["minutes"] << 5) + ($date["hours"] << 11)));
627 }
628 return "\x00\x00\x00\x00";
629 }
630
631 /**
632 * Build the Zip file structures
633 *
634 * @param string $filePath
635 * @param string $fileComment
636 * @param string $gpFlags
637 * @param string $gzType
638 * @param int $timestamp
639 * @param string $fileCRC32
640 * @param int $gzLength
641 * @param int $dataLength
642 * @param int $extFileAttr Use self::EXT_FILE_ATTR_FILE for files, self::EXT_FILE_ATTR_DIR for Directories.
643 */
644 private function buildZipEntry($filePath, $fileComment, $gpFlags, $gzType, $timestamp, $fileCRC32, $gzLength, $dataLength, $extFileAttr) {
645 $filePath = str_replace("\\", "/", $filePath);
646 $fileCommentLength = (empty($fileComment) ? 0 : strlen($fileComment));
647 $timestamp = (int)$timestamp;
648 $timestamp = ($timestamp == 0 ? time() : $timestamp);
649
650 $dosTime = $this->getDosTime($timestamp);
651 $tsPack = pack("V", $timestamp);
652
653 $ux = "\x75\x78\x0B\x00\x01\x04\xE8\x03\x00\x00\x04\x00\x00\x00\x00";
654
655 if (!isset($gpFlags) || strlen($gpFlags) != 2) {
656 $gpFlags = "\x00\x00";
657 }
658
659 $isFileUTF8 = mb_check_encoding($filePath, "UTF-8") && !mb_check_encoding($filePath, "ASCII");
660 $isCommentUTF8 = !empty($fileComment) && mb_check_encoding($fileComment, "UTF-8") && !mb_check_encoding($fileComment, "ASCII");
661 if ($isFileUTF8 || $isCommentUTF8) {
662 $flag = 0;
663 $gpFlagsV = unpack("vflags", $gpFlags);
664 if (isset($gpFlagsV['flags'])) {
665 $flag = $gpFlagsV['flags'];
666 }
667 $gpFlags = pack("v", $flag | (1 << 11));
668 }
669
670 $header = $gpFlags . $gzType . $dosTime. $fileCRC32
671 . pack("VVv", $gzLength, $dataLength, strlen($filePath)); // File name length
672
673 $zipEntry = self::ZIP_LOCAL_FILE_HEADER;
674 $zipEntry .= self::ATTR_VERSION_TO_EXTRACT;
675 $zipEntry .= $header;
676 $zipEntry .= pack("v", ($this->addExtraField ? 28 : 0)); // Extra field length
677 $zipEntry .= $filePath; // FileName
678 // Extra fields
679 if ($this->addExtraField) {
680 $zipEntry .= "\x55\x54\x09\x00\x03" . $tsPack . $tsPack . $ux;
681 }
682 $this->zipwrite($zipEntry);
683
684 $cdEntry = self::ZIP_CENTRAL_FILE_HEADER;
685 $cdEntry .= self::ATTR_MADE_BY_VERSION;
686 $cdEntry .= ($dataLength === 0 ? "\x0A\x00" : self::ATTR_VERSION_TO_EXTRACT);
687 $cdEntry .= $header;
688 $cdEntry .= pack("v", ($this->addExtraField ? 24 : 0)); // Extra field length
689 $cdEntry .= pack("v", $fileCommentLength); // File comment length
690 $cdEntry .= "\x00\x00"; // Disk number start
691 $cdEntry .= "\x00\x00"; // internal file attributes
692 $cdEntry .= pack("V", $extFileAttr); // External file attributes
693 $cdEntry .= pack("V", $this->offset); // Relative offset of local header
694 $cdEntry .= $filePath; // FileName
695 // Extra fields
696 if ($this->addExtraField) {
697 $cdEntry .= "\x55\x54\x05\x00\x03" . $tsPack . $ux;
698 }
699 if (!empty($fileComment)) {
700 $cdEntry .= $fileComment; // Comment
701 }
702
703 $this->cdRec[] = $cdEntry;
704 $this->offset += strlen($zipEntry) + $gzLength;
705 }
706
707 private function zipwrite($data) {
708 if (!is_resource($this->zipFile)) {
709 $this->zipData .= $data;
710 } else {
711 fwrite($this->zipFile, $data);
712 fflush($this->zipFile);
713 }
714 }
715
716 private function zipflush() {
717 if (!is_resource($this->zipFile)) {
718 $this->zipFile = tmpfile();
719 fwrite($this->zipFile, $this->zipData);
720 $this->zipData = NULL;
721 }
722 }
723
724 /**
725 * Join $file to $dir path, and clean up any excess slashes.
726 *
727 * @param string $dir
728 * @param string $file
729 */
730 public static function pathJoin($dir, $file) {
731 if (empty($dir) || empty($file)) {
732 return self::getRelativePath($dir . $file);
733 }
734 return self::getRelativePath($dir . '/' . $file);
735 }
736
737 /**
738 * Clean up a path, removing any unnecessary elements such as /./, // or redundant ../ segments.
739 * If the path starts with a "/", it is deemed an absolute path and any /../ in the beginning is stripped off.
740 * The returned path will not end in a "/".
741 *
742 * Sometimes, when a path is generated from multiple fragments,
743 * you can get something like "../data/html/../images/image.jpeg"
744 * This will normalize that example path to "../data/images/image.jpeg"
745 *
746 * @param string $path The path to clean up
747 * @return string the clean path
748 */
749 public static function getRelativePath($path) {
750 $path = preg_replace("#/+\.?/+#", "/", str_replace("\\", "/", $path));
751 $dirs = explode("/", rtrim(preg_replace('#^(?:\./)+#', '', $path), '/'));
752
753 $offset = 0;
754 $sub = 0;
755 $subOffset = 0;
756 $root = "";
757
758 if (empty($dirs[0])) {
759 $root = "/";
760 $dirs = array_splice($dirs, 1);
761 } else if (preg_match("#[A-Za-z]:#", $dirs[0])) {
762 $root = strtoupper($dirs[0]) . "/";
763 $dirs = array_splice($dirs, 1);
764 }
765
766 $newDirs = array();
767 foreach ($dirs as $dir) {
768 if ($dir !== "..") {
769 $subOffset--;
770 $newDirs[++$offset] = $dir;
771 } else {
772 $subOffset++;
773 if (--$offset < 0) {
774 $offset = 0;
775 if ($subOffset > $sub) {
776 $sub++;
777 }
778 }
779 }
780 }
781
782 if (empty($root)) {
783 $root = str_repeat("../", $sub);
784 }
785 return $root . implode("/", array_slice($newDirs, 0, $offset));
786 }
787
788 /**
789 * Create the file permissions for a file or directory, for use in the extFileAttr parameters.
790 *
791 * @param int $owner Unix permisions for owner (octal from 00 to 07)
792 * @param int $group Unix permisions for group (octal from 00 to 07)
793 * @param int $other Unix permisions for others (octal from 00 to 07)
794 * @param bool $isFile
795 * @return EXTRERNAL_REF field.
796 */
797 public static function generateExtAttr($owner = 07, $group = 05, $other = 05, $isFile = true) {
798 $fp = $isFile ? self::S_IFREG : self::S_IFDIR;
799 $fp |= (($owner & 07) << 6) | (($group & 07) << 3) | ($other & 07);
800
801 return ($fp << 16) | ($isFile ? self::S_DOS_A : self::S_DOS_D);
802 }
803
804 /**
805 * Get the file permissions for a file or directory, for use in the extFileAttr parameters.
806 *
807 * @param string $filename
808 * @return external ref field, or FALSE if the file is not found.
809 */
810 public static function getFileExtAttr($filename) {
811 if (file_exists($filename)) {
812 $fp = fileperms($filename) << 16;
813 return $fp | (is_dir($filename) ? self::S_DOS_D : self::S_DOS_A);
814 }
815 return FALSE;
816 }
817}
818?>
diff --git a/inc/3rdparty/libraries/PHPePub/lib.uuid.LICENCE.txt b/inc/3rdparty/libraries/PHPePub/lib.uuid.LICENCE.txt
deleted file mode 100644
index 9424a83e..00000000
--- a/inc/3rdparty/libraries/PHPePub/lib.uuid.LICENCE.txt
+++ /dev/null
@@ -1,31 +0,0 @@
1 DrUUID RFC4122 library for PHP5
2 by J. King (http://jkingweb.ca/)
3 Licensed under MIT license
4
5 See http://jkingweb.ca/code/php/lib.uuid/
6 for documentation
7
8 Last revised 2010-02-15
9
10Copyright (c) 2009 J. King
11
12Permission is hereby granted, free of charge, to any person
13obtaining a copy of this software and associated documentation
14files (the "Software"), to deal in the Software without
15restriction, including without limitation the rights to use,
16copy, modify, merge, publish, distribute, sublicense, and/or sell
17copies of the Software, and to permit persons to whom the
18Software is furnished to do so, subject to the following
19conditions:
20
21The above copyright notice and this permission notice shall be
22included in all copies or substantial portions of the Software.
23
24THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
26OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
28HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
29WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
31OTHER DEALINGS IN THE SOFTWARE.
diff --git a/inc/3rdparty/libraries/PHPePub/lib.uuid.php b/inc/3rdparty/libraries/PHPePub/lib.uuid.php
deleted file mode 100644
index c6a8de52..00000000
--- a/inc/3rdparty/libraries/PHPePub/lib.uuid.php
+++ /dev/null
@@ -1,314 +0,0 @@
1<?php
2/*
3 DrUUID RFC4122 library for PHP5
4by J. King (http://jkingweb.ca/)
5Licensed under MIT license
6
7See http://jkingweb.ca/code/php/lib.uuid/
8for documentation
9
10Last revised 2010-02-15
11*/
12
13/*
14 Copyright (c) 2009 J. King
15
16Permission is hereby granted, free of charge, to any person
17obtaining a copy of this software and associated documentation
18files (the "Software"), to deal in the Software without
19restriction, including without limitation the rights to use,
20copy, modify, merge, publish, distribute, sublicense, and/or sell
21copies of the Software, and to permit persons to whom the
22Software is furnished to do so, subject to the following
23conditions:
24
25The above copyright notice and this permission notice shall be
26included in all copies or substantial portions of the Software.
27
28THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
30OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
32HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
33WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
34FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35OTHER DEALINGS IN THE SOFTWARE.
36*/
37
38
39class UUID {
40 const MD5 = 3;
41 const SHA1 = 5;
42 const clearVer = 15; // 00001111 Clears all bits of version byte with AND
43 const clearVar = 63; // 00111111 Clears all relevant bits of variant byte with AND
44 const varRes = 224; // 11100000 Variant reserved for future use
45 const varMS = 192; // 11000000 Microsft GUID variant
46 const varRFC = 128; // 10000000 The RFC 4122 variant (this variant)
47 const varNCS = 0; // 00000000 The NCS compatibility variant
48 const version1 = 16; // 00010000
49 const version3 = 48; // 00110000
50 const version4 = 64; // 01000000
51 const version5 = 80; // 01010000
52 const interval = 0x01b21dd213814000; // Time (in 100ns steps) between the start of the UTC and Unix epochs
53 const nsDNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
54 const nsURL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';
55 const nsOID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8';
56 const nsX500 = '6ba7b814-9dad-11d1-80b4-00c04fd430c8';
57 protected static $randomFunc = 'randomTwister';
58 protected static $randomSource = NULL;
59 //instance properties
60 protected $bytes;
61 protected $hex;
62 protected $string;
63 protected $urn;
64 protected $version;
65 protected $variant;
66 protected $node;
67 protected $time;
68
69 public static function mint($ver = 1, $node = NULL, $ns = NULL) {
70 /* Create a new UUID based on provided data. */
71 switch((int) $ver) {
72 case 1:
73 return new self(self::mintTime($node));
74 case 2:
75 // Version 2 is not supported
76 throw new UUIDException("Version 2 is unsupported.");
77 case 3:
78 return new self(self::mintName(self::MD5, $node, $ns));
79 case 4:
80 return new self(self::mintRand());
81 case 5:
82 return new self(self::mintName(self::SHA1, $node, $ns));
83 default:
84 throw new UUIDException("Selected version is invalid or unsupported.");
85 }
86 }
87
88 public static function import($uuid) {
89 /* Import an existing UUID. */
90 return new self(self::makeBin($uuid, 16));
91 }
92
93 public static function compare($a, $b) {
94 /* Compares the binary representations of two UUIDs.
95 The comparison will return true if they are bit-exact,
96 or if neither is valid. */
97 if (self::makeBin($a, 16)==self::makeBin($b, 16)) {
98 return TRUE;
99 } else {
100 return FALSE;
101 }
102 }
103
104 public function __toString() {
105 return $this->string;
106 }
107
108 public function __get($var) {
109 switch($var) {
110 case "bytes":
111 return $this->bytes;
112 case "hex":
113 return bin2hex($this->bytes);
114 case "string":
115 return $this->__toString();
116 case "urn":
117 return "urn:uuid:".$this->__toString();
118 case "version":
119 return ord($this->bytes[6]) >> 4;
120 case "variant":
121 $byte = ord($this->bytes[8]);
122 if ($byte >= self::varRes) {
123 return 3;
124 }
125 if ($byte >= self::varMS) {
126 return 2;
127 }
128 if ($byte >= self::varRFC) {
129 return 1;
130 }
131 return 0;
132 case "node":
133 if (ord($this->bytes[6])>>4==1) {
134 return bin2hex(substr($this->bytes,10));
135 } else {
136 return NULL;
137 }
138 case "time":
139 if (ord($this->bytes[6])>>4==1) {
140 // Restore contiguous big-endian byte order
141 $time = bin2hex($this->bytes[6].$this->bytes[7].$this->bytes[4].$this->bytes[5].$this->bytes[0].$this->bytes[1].$this->bytes[2].$this->bytes[3]);
142 // Clear version flag
143 $time[0] = "0";
144 // Do some reverse arithmetic to get a Unix timestamp
145 $time = (hexdec($time) - self::interval) / 10000000;
146 return $time;
147 } else {
148 return NULL;
149 }
150 default:
151 return NULL;
152 }
153 }
154
155 protected function __construct($uuid) {
156 if (strlen($uuid) != 16) {
157 throw new UUIDException("Input must be a 128-bit integer.");
158 }
159 $this->bytes = $uuid;
160 // Optimize the most common use
161 $this->string =
162 bin2hex(substr($uuid,0,4))."-".
163 bin2hex(substr($uuid,4,2))."-".
164 bin2hex(substr($uuid,6,2))."-".
165 bin2hex(substr($uuid,8,2))."-".
166 bin2hex(substr($uuid,10,6));
167 }
168
169 protected static function mintTime($node = NULL) {
170 /* Generates a Version 1 UUID.
171 These are derived from the time at which they were generated. */
172 // Get time since Gregorian calendar reform in 100ns intervals
173 // This is exceedingly difficult because of PHP's (and pack()'s)
174 // integer size limits.
175 // Note that this will never be more accurate than to the microsecond.
176 $time = microtime(1) * 10000000 + self::interval;
177 // Convert to a string representation
178 $time = sprintf("%F", $time);
179 preg_match("/^\d+/", $time, $time); //strip decimal point
180 // And now to a 64-bit binary representation
181 $time = base_convert($time[0], 10, 16);
182 $time = pack("H*", str_pad($time, 16, "0", STR_PAD_LEFT));
183 // Reorder bytes to their proper locations in the UUID
184 $uuid = $time[4].$time[5].$time[6].$time[7].$time[2].$time[3].$time[0].$time[1];
185 // Generate a random clock sequence
186 $uuid .= self::randomBytes(2);
187 // set variant
188 $uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
189 // set version
190 $uuid[6] = chr(ord($uuid[6]) & self::clearVer | self::version1);
191 // Set the final 'node' parameter, a MAC address
192 if ($node) {
193 $node = self::makeBin($node, 6);
194 }
195 if (!$node) {
196 // If no node was provided or if the node was invalid,
197 // generate a random MAC address and set the multicast bit
198 $node = self::randomBytes(6);
199 $node[0] = pack("C", ord($node[0]) | 1);
200 }
201 $uuid .= $node;
202 return $uuid;
203 }
204
205 protected static function mintRand() {
206 /* Generate a Version 4 UUID.
207 These are derived soly from random numbers. */
208 // generate random fields
209 $uuid = self::randomBytes(16);
210 // set variant
211 $uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
212 // set version
213 $uuid[6] = chr(ord($uuid[6]) & self::clearVer | self::version4);
214 return $uuid;
215 }
216
217 protected static function mintName($ver, $node, $ns) {
218 /* Generates a Version 3 or Version 5 UUID.
219 These are derived from a hash of a name and its namespace, in binary form. */
220 if (!$node) {
221 throw new UUIDException("A name-string is required for Version 3 or 5 UUIDs.");
222 }
223 // if the namespace UUID isn't binary, make it so
224 $ns = self::makeBin($ns, 16);
225 if (!$ns) {
226 throw new UUIDException("A binary namespace is required for Version 3 or 5 UUIDs.");
227 }
228 $uuid = null;
229 $version = self::version3;
230 switch($ver) {
231 case self::MD5:
232 $version = self::version3;
233 $uuid = md5($ns.$node,1);
234 break;
235 case self::SHA1:
236 $version = self::version5;
237 $uuid = substr(sha1($ns.$node,1),0, 16);
238 break;
239 }
240 // set variant
241 $uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
242 // set version
243 $uuid[6] = chr(ord($uuid[6]) & self::clearVer | $version);
244 return ($uuid);
245 }
246
247 protected static function makeBin($str, $len) {
248 /* Insure that an input string is either binary or hexadecimal.
249 Returns binary representation, or false on failure. */
250 if ($str instanceof self) {
251 return $str->bytes;
252 }
253 if (strlen($str)==$len) {
254 return $str;
255 } else {
256 $str = preg_replace("/^urn:uuid:/is", "", $str); // strip URN scheme and namespace
257 }
258 $str = preg_replace("/[^a-f0-9]/is", "", $str); // strip non-hex characters
259 if (strlen($str) != ($len * 2)) {
260 return FALSE;
261 } else {
262 return pack("H*", $str);
263 }
264 }
265
266 public static function initRandom() {
267 /* Look for a system-provided source of randomness, which is usually crytographically secure.
268 /dev/urandom is tried first simply out of bias for Linux systems. */
269 if (is_readable('/dev/urandom')) {
270 self::$randomSource = fopen('/dev/urandom', 'rb');
271 self::$randomFunc = 'randomFRead';
272 }
273 else if (class_exists('COM', 0)) {
274 try {
275 self::$randomSource = new COM('CAPICOM.Utilities.1'); // See http://msdn.microsoft.com/en-us/library/aa388182(VS.85).aspx
276 self::$randomFunc = 'randomCOM';
277 }
278 catch(Exception $e) {
279 }
280 }
281 return self::$randomFunc;
282 }
283
284 public static function randomBytes($bytes) {
285 return call_user_func(array('self', self::$randomFunc), $bytes);
286 }
287
288 protected static function randomTwister($bytes) {
289 /* Get the specified number of random bytes, using mt_rand().
290 Randomness is returned as a string of bytes. */
291 $rand = "";
292 for ($a = 0; $a < $bytes; $a++) {
293 $rand .= chr(mt_rand(0, 255));
294 }
295 return $rand;
296 }
297
298 protected static function randomFRead($bytes) {
299 /* Get the specified number of random bytes using a file handle
300 previously opened with UUID::initRandom().
301 Randomness is returned as a string of bytes. */
302 return fread(self::$randomSource, $bytes);
303 }
304
305 protected static function randomCOM($bytes) {
306 /* Get the specified number of random bytes using Windows'
307 randomness source via a COM object previously created by UUID::initRandom().
308 Randomness is returned as a string of bytes. */
309 return base64_decode(self::$randomSource->GetRandom($bytes,0)); // straight binary mysteriously doesn't work, hence the base64
310 }
311}
312
313class UUIDException extends Exception {
314}
diff --git a/inc/poche/global.inc.php b/inc/poche/global.inc.php
index c17d54e6..308a416f 100755
--- a/inc/poche/global.inc.php
+++ b/inc/poche/global.inc.php
@@ -25,22 +25,13 @@ require_once INCLUDES . '/poche/WallabagEBooks.class.php';
25require_once INCLUDES . '/poche/Poche.class.php'; 25require_once INCLUDES . '/poche/Poche.class.php';
26 26
27require_once INCLUDES . '/poche/Database.class.php'; 27require_once INCLUDES . '/poche/Database.class.php';
28require_once INCLUDES . '/3rdparty/paginator.php'; 28require_once INCLUDES . '/poche/FlattrItem.class.php';
29 29
30require_once INCLUDES . '/3rdparty/libraries/feedwriter/FeedItem.php'; 30require_once INCLUDES . '/3rdparty/libraries/feedwriter/FeedItem.php';
31require_once INCLUDES . '/3rdparty/libraries/feedwriter/FeedWriter.php'; 31require_once INCLUDES . '/3rdparty/libraries/feedwriter/FeedWriter.php';
32require_once INCLUDES . '/poche/FlattrItem.class.php';
33
34# epub library
35require_once INCLUDES . '/3rdparty/libraries/PHPePub/Logger.php';
36require_once INCLUDES . '/3rdparty/libraries/PHPePub/EPub.php';
37require_once INCLUDES . '/3rdparty/libraries/PHPePub/EPubChapterSplitter.php';
38
39# mobi library 32# mobi library
40require_once INCLUDES . '/3rdparty/libraries/MOBIClass/MOBI.php'; 33require_once INCLUDES . '/3rdparty/libraries/MOBIClass/MOBI.php';
41
42# pdf library 34# pdf library
43#require_once INCLUDES . '/3rdparty/libraries/mpdf/mpdf.php';
44require_once INCLUDES . '/3rdparty/libraries/tcpdf/tcpdf.php'; 35require_once INCLUDES . '/3rdparty/libraries/tcpdf/tcpdf.php';
45 36
46# system configuration; database credentials et caetera 37# system configuration; database credentials et caetera