1
0
mirror of https://github.com/moparisthebest/wallabag synced 2024-11-23 17:42:15 -05:00

Added epub export function

This commit is contained in:
tcit 2014-04-24 03:04:02 +02:00
parent 8af31ae0f7
commit 87090d8ae7
14 changed files with 6253 additions and 0 deletions

View File

@ -0,0 +1,266 @@
<?php
/**
* This should be a complete list of all HTML entities, mapped to their UTF-8 character codes.
*
* @author A. Grandt
* @copyright A. Grandt 2009-2013
* @license GNU LGPL, Attribution required for commercial implementations, requested for everything else.
* @version 3.00
*/
global $htmlEntities;
$htmlEntities = array();
$htmlEntities["&quot;"] ="\x22"; // &#34; ((double) quotation mark)
$htmlEntities["&amp;"] ="\x26"; // &#38; (ampersand)
$htmlEntities["&apos;"] ="\x27"; // &#39; (apostrophe = apostrophe-quote)
$htmlEntities["&lt;"] ="\x3C"; // &#60; (less-than sign)
$htmlEntities["&gt;"] ="\x3E"; // &#62; (greater-than sign)
$htmlEntities["&nbsp;"] ="\xC2\xA0"; // &#160; (non-breaking space)
$htmlEntities["&iexcl;"] ="\xC2\xA1"; // &#161; (inverted exclamation mark)
$htmlEntities["&cent;"] ="\xC2\xA2"; // &#162; (cent)
$htmlEntities["&pound;"] ="\xC2\xA3"; // &#163; (pound)
$htmlEntities["&curren;"] ="\xC2\xA4"; // &#164; (currency)
$htmlEntities["&yen;"] ="\xC2\xA5"; // &#165; (yen)
$htmlEntities["&brvbar;"] ="\xC2\xA6"; // &#166; (broken vertical bar)
$htmlEntities["&sect;"] ="\xC2\xA7"; // &#167; (section)
$htmlEntities["&uml;"] ="\xC2\xA8"; // &#168; (spacing diaeresis)
$htmlEntities["&copy;"] ="\xC2\xA9"; // &#169; (copyright)
$htmlEntities["&ordf;"] ="\xC2\xAA"; // &#170; (feminine ordinal indicator)
$htmlEntities["&laquo;"] ="\xC2\xAB"; // &#171; (angle quotation mark (left))
$htmlEntities["&not;"] ="\xC2\xAC"; // &#172; (negation)
$htmlEntities["&shy;"] ="\xC2\xAD"; // &#173; (soft hyphen)
$htmlEntities["&reg;"] ="\xC2\xAE"; // &#174; (registered trademark)
$htmlEntities["&macr;"] ="\xC2\xAF"; // &#175; (spacing macron)
$htmlEntities["&deg;"] ="\xC2\xB0"; // &#176; (degree)
$htmlEntities["&plusmn;"] ="\xC2\xB1"; // &#177; (plus-or-minus)
$htmlEntities["&sup2;"] ="\xC2\xB2"; // &#178; (superscript 2)
$htmlEntities["&sup3;"] ="\xC2\xB3"; // &#179; (superscript 3)
$htmlEntities["&acute;"] ="\xC2\xB4"; // &#180; (spacing acute)
$htmlEntities["&micro;"] ="\xC2\xB5"; // &#181; (micro)
$htmlEntities["&para;"] ="\xC2\xB6"; // &#182; (paragraph)
$htmlEntities["&middot;"] ="\xC2\xB7"; // &#183; (middle dot)
$htmlEntities["&cedil;"] ="\xC2\xB8"; // &#184; (spacing cedilla)
$htmlEntities["&sup1;"] ="\xC2\xB9"; // &#185; (superscript 1)
$htmlEntities["&ordm;"] ="\xC2\xBA"; // &#186; (masculine ordinal indicator)
$htmlEntities["&raquo;"] ="\xC2\xBB"; // &#187; (angle quotation mark (right))
$htmlEntities["&frac14;"] ="\xC2\xBC"; // &#188; (fraction 1/4)
$htmlEntities["&frac12;"] ="\xC2\xBD"; // &#189; (fraction 1/2)
$htmlEntities["&frac34;"] ="\xC2\xBE"; // &#190; (fraction 3/4)
$htmlEntities["&iquest;"] ="\xC2\xBF"; // &#191; (inverted question mark)
$htmlEntities["&Agrave;"] ="\xC3\x80"; // &#192; (capital a, grave accent)
$htmlEntities["&Aacute;"] ="\xC3\x81"; // &#193; (capital a, acute accent)
$htmlEntities["&Acirc;"] ="\xC3\x82"; // &#194; (capital a, circumflex accent)
$htmlEntities["&Atilde;"] ="\xC3\x83"; // &#195; (capital a, tilde)
$htmlEntities["&Auml;"] ="\xC3\x84"; // &#196; (capital a, umlaut mark)
$htmlEntities["&Aring;"] ="\xC3\x85"; // &#197; (capital a, ring)
$htmlEntities["&AElig;"] ="\xC3\x86"; // &#198; (capital ae)
$htmlEntities["&Ccedil;"] ="\xC3\x87"; // &#199; (capital c, cedilla)
$htmlEntities["&Egrave;"] ="\xC3\x88"; // &#200; (capital e, grave accent)
$htmlEntities["&Eacute;"] ="\xC3\x89"; // &#201; (capital e, acute accent)
$htmlEntities["&Ecirc;"] ="\xC3\x8A"; // &#202; (capital e, circumflex accent)
$htmlEntities["&Euml;"] ="\xC3\x8B"; // &#203; (capital e, umlaut mark)
$htmlEntities["&Igrave;"] ="\xC3\x8C"; // &#204; (capital i, grave accent)
$htmlEntities["&Iacute;"] ="\xC3\x8D"; // &#205; (capital i, acute accent)
$htmlEntities["&Icirc;"] ="\xC3\x8E"; // &#206; (capital i, circumflex accent)
$htmlEntities["&Iuml;"] ="\xC3\x8F"; // &#207; (capital i, umlaut mark)
$htmlEntities["&ETH;"] ="\xC3\x90"; // &#208; (capital eth, Icelandic)
$htmlEntities["&Ntilde;"] ="\xC3\x91"; // &#209; (capital n, tilde)
$htmlEntities["&Ograve;"] ="\xC3\x92"; // &#210; (capital o, grave accent)
$htmlEntities["&Oacute;"] ="\xC3\x93"; // &#211; (capital o, acute accent)
$htmlEntities["&Ocirc;"] ="\xC3\x94"; // &#212; (capital o, circumflex accent)
$htmlEntities["&Otilde;"] ="\xC3\x95"; // &#213; (capital o, tilde)
$htmlEntities["&Ouml;"] ="\xC3\x96"; // &#214; (capital o, umlaut mark)
$htmlEntities["&times;"] ="\xC3\x97"; // &#215; (multiplication)
$htmlEntities["&Oslash;"] ="\xC3\x98"; // &#216; (capital o, slash)
$htmlEntities["&Ugrave;"] ="\xC3\x99"; // &#217; (capital u, grave accent)
$htmlEntities["&Uacute;"] ="\xC3\x9A"; // &#218; (capital u, acute accent)
$htmlEntities["&Ucirc;"] ="\xC3\x9B"; // &#219; (capital u, circumflex accent)
$htmlEntities["&Uuml;"] ="\xC3\x9C"; // &#220; (capital u, umlaut mark)
$htmlEntities["&Yacute;"] ="\xC3\x9D"; // &#221; (capital y, acute accent)
$htmlEntities["&THORN;"] ="\xC3\x9E"; // &#222; (capital THORN, Icelandic)
$htmlEntities["&szlig;"] ="\xC3\x9F"; // &#223; (small sharp s, German)
$htmlEntities["&agrave;"] ="\xC3\xA0"; // &#224; (small a, grave accent)
$htmlEntities["&aacute;"] ="\xC3\xA1"; // &#225; (small a, acute accent)
$htmlEntities["&acirc;"] ="\xC3\xA2"; // &#226; (small a, circumflex accent)
$htmlEntities["&atilde;"] ="\xC3\xA3"; // &#227; (small a, tilde)
$htmlEntities["&auml;"] ="\xC3\xA4"; // &#228; (small a, umlaut mark)
$htmlEntities["&aring;"] ="\xC3\xA5"; // &#229; (small a, ring)
$htmlEntities["&aelig;"] ="\xC3\xA6"; // &#230; (small ae)
$htmlEntities["&ccedil;"] ="\xC3\xA7"; // &#231; (small c, cedilla)
$htmlEntities["&egrave;"] ="\xC3\xA8"; // &#232; (small e, grave accent)
$htmlEntities["&eacute;"] ="\xC3\xA9"; // &#233; (small e, acute accent)
$htmlEntities["&ecirc;"] ="\xC3\xAA"; // &#234; (small e, circumflex accent)
$htmlEntities["&euml;"] ="\xC3\xAB"; // &#235; (small e, umlaut mark)
$htmlEntities["&igrave;"] ="\xC3\xAC"; // &#236; (small i, grave accent)
$htmlEntities["&iacute;"] ="\xC3\xAD"; // &#237; (small i, acute accent)
$htmlEntities["&icirc;"] ="\xC3\xAE"; // &#238; (small i, circumflex accent)
$htmlEntities["&iuml;"] ="\xC3\xAF"; // &#239; (small i, umlaut mark)
$htmlEntities["&eth;"] ="\xC3\xB0"; // &#240; (small eth, Icelandic)
$htmlEntities["&ntilde;"] ="\xC3\xB1"; // &#241; (small n, tilde)
$htmlEntities["&ograve;"] ="\xC3\xB2"; // &#242; (small o, grave accent)
$htmlEntities["&oacute;"] ="\xC3\xB3"; // &#243; (small o, acute accent)
$htmlEntities["&ocirc;"] ="\xC3\xB4"; // &#244; (small o, circumflex accent)
$htmlEntities["&otilde;"] ="\xC3\xB5"; // &#245; (small o, tilde)
$htmlEntities["&ouml;"] ="\xC3\xB6"; // &#246; (small o, umlaut mark)
$htmlEntities["&divide;"] ="\xC3\xB7"; // &#247; (division)
$htmlEntities["&oslash;"] ="\xC3\xB8"; // &#248; (small o, slash)
$htmlEntities["&ugrave;"] ="\xC3\xB9"; // &#249; (small u, grave accent)
$htmlEntities["&uacute;"] ="\xC3\xBA"; // &#250; (small u, acute accent)
$htmlEntities["&ucirc;"] ="\xC3\xBB"; // &#251; (small u, circumflex accent)
$htmlEntities["&uuml;"] ="\xC3\xBC"; // &#252; (small u, umlaut mark)
$htmlEntities["&yacute;"] ="\xC3\xBD"; // &#253; (small y, acute accent)
$htmlEntities["&thorn;"] ="\xC3\xBE"; // &#254; (small thorn, Icelandic)
$htmlEntities["&yuml;"] ="\xC3\xBF"; // &#255; (small y, umlaut mark)
$htmlEntities["&OElig;"] ="\xC5\x92"; // &#338; (capital ligature OE)
$htmlEntities["&oelig;"] ="\xC5\x93"; // &#339; (small ligature oe)
$htmlEntities["&Scaron;"] ="\xC5\xA0"; // &#352; (capital S with caron)
$htmlEntities["&scaron;"] ="\xC5\xA1"; // &#353; (small S with caron)
$htmlEntities["&Yuml;"] ="\xC5\xB8"; // &#376; (capital Y with diaeres)
$htmlEntities["&fnof;"] ="\xC6\x92"; // &#402; (f with hook)
$htmlEntities["&circ;"] ="\xCB\x86"; // &#710; (modifier letter circumflex accent)
$htmlEntities["&tilde;"] ="\xCB\x9C"; // &#732; (small tilde)
$htmlEntities["&Alpha;"] ="\xCE\x91"; // &#913; (Alpha)
$htmlEntities["&Beta;"] ="\xCE\x92"; // &#914; (Beta)
$htmlEntities["&Gamma;"] ="\xCE\x93"; // &#915; (Gamma)
$htmlEntities["&Delta;"] ="\xCE\x94"; // &#916; (Delta)
$htmlEntities["&Epsilon;"] ="\xCE\x95"; // &#917; (Epsilon)
$htmlEntities["&Zeta;"] ="\xCE\x96"; // &#918; (Zeta)
$htmlEntities["&Eta;"] ="\xCE\x97"; // &#919; (Eta)
$htmlEntities["&Theta;"] ="\xCE\x98"; // &#920; (Theta)
$htmlEntities["&Iota;"] ="\xCE\x99"; // &#921; (Iota)
$htmlEntities["&Kappa;"] ="\xCE\x9A"; // &#922; (Kappa)
$htmlEntities["&Lambda;"] ="\xCE\x9B"; // &#923; (Lambda)
$htmlEntities["&Mu;"] ="\xCE\x9C"; // &#924; (Mu)
$htmlEntities["&Nu;"] ="\xCE\x9D"; // &#925; (Nu)
$htmlEntities["&Xi;"] ="\xCE\x9E"; // &#926; (Xi)
$htmlEntities["&Omicron;"] ="\xCE\x9F"; // &#927; (Omicron)
$htmlEntities["&Pi;"] ="\xCE\xA0"; // &#928; (Pi)
$htmlEntities["&Rho;"] ="\xCE\xA1"; // &#929; (Rho)
$htmlEntities["&Sigma;"] ="\xCE\xA3"; // &#931; (Sigma)
$htmlEntities["&Tau;"] ="\xCE\xA4"; // &#932; (Tau)
$htmlEntities["&Upsilon;"] ="\xCE\xA5"; // &#933; (Upsilon)
$htmlEntities["&Phi;"] ="\xCE\xA6"; // &#934; (Phi)
$htmlEntities["&Chi;"] ="\xCE\xA7"; // &#935; (Chi)
$htmlEntities["&Psi;"] ="\xCE\xA8"; // &#936; (Psi)
$htmlEntities["&Omega;"] ="\xCE\xA9"; // &#937; (Omega)
$htmlEntities["&alpha;"] ="\xCE\xB1"; // &#945; (alpha)
$htmlEntities["&beta;"] ="\xCE\xB2"; // &#946; (beta)
$htmlEntities["&gamma;"] ="\xCE\xB3"; // &#947; (gamma)
$htmlEntities["&delta;"] ="\xCE\xB4"; // &#948; (delta)
$htmlEntities["&epsilon;"] ="\xCE\xB5"; // &#949; (epsilon)
$htmlEntities["&zeta;"] ="\xCE\xB6"; // &#950; (zeta)
$htmlEntities["&eta;"] ="\xCE\xB7"; // &#951; (eta)
$htmlEntities["&theta;"] ="\xCE\xB8"; // &#952; (theta)
$htmlEntities["&iota;"] ="\xCE\xB9"; // &#953; (iota)
$htmlEntities["&kappa;"] ="\xCE\xBA"; // &#954; (kappa)
$htmlEntities["&lambda;"] ="\xCE\xBB"; // &#955; (lambda)
$htmlEntities["&mu;"] ="\xCE\xBC"; // &#956; (mu)
$htmlEntities["&nu;"] ="\xCE\xBD"; // &#957; (nu)
$htmlEntities["&xi;"] ="\xCE\xBE"; // &#958; (xi)
$htmlEntities["&omicron;"] ="\xCE\xBF"; // &#959; (omicron)
$htmlEntities["&pi;"] ="\xCF\x80"; // &#960; (pi)
$htmlEntities["&rho;"] ="\xCF\x81"; // &#961; (rho)
$htmlEntities["&sigmaf;"] ="\xCF\x82"; // &#962; (sigmaf)
$htmlEntities["&sigma;"] ="\xCF\x83"; // &#963; (sigma)
$htmlEntities["&tau;"] ="\xCF\x84"; // &#964; (tau)
$htmlEntities["&upsilon;"] ="\xCF\x85"; // &#965; (upsilon)
$htmlEntities["&phi;"] ="\xCF\x86"; // &#966; (phi)
$htmlEntities["&chi;"] ="\xCF\x87"; // &#967; (chi)
$htmlEntities["&psi;"] ="\xCF\x88"; // &#968; (psi)
$htmlEntities["&omega;"] ="\xCF\x89"; // &#969; (omega)
$htmlEntities["&thetasym;"] ="\xCF\x91"; // &#977; (theta symbol)
$htmlEntities["&upsih;"] ="\xCF\x92"; // &#978; (upsilon symbol)
$htmlEntities["&piv;"] ="\xCF\x96"; // &#982; (pi symbol)
$htmlEntities["&ensp;"] ="\xE2\x80\x82"; // &#8194; (en space)
$htmlEntities["&emsp;"] ="\xE2\x80\x83"; // &#8195; (em space)
$htmlEntities["&thinsp;"] ="\xE2\x80\x89"; // &#8201; (thin space)
$htmlEntities["&zwnj;"] ="\xE2\x80\x8C"; // &#8204; (zero width non-joiner)
$htmlEntities["&zwj;"] ="\xE2\x80\x8D"; // &#8205; (zero width joiner)
$htmlEntities["&lrm;"] ="\xE2\x80\x8E"; // &#8206; (left-to-right mark)
$htmlEntities["&rlm;"] ="\xE2\x80\x8F"; // &#8207; (right-to-left mark)
$htmlEntities["&ndash;"] ="\xE2\x80\x93"; // &#8211; (en dash)
$htmlEntities["&mdash;"] ="\xE2\x80\x94"; // &#8212; (em dash)
$htmlEntities["&lsquo;"] ="\xE2\x80\x98"; // &#8216; (left single quotation mark)
$htmlEntities["&rsquo;"] ="\xE2\x80\x99"; // &#8217; (right single quotation mark)
$htmlEntities["&sbquo;"] ="\xE2\x80\x9A"; // &#8218; (single low-9 quotation mark)
$htmlEntities["&ldquo;"] ="\xE2\x80\x9C"; // &#8220; (left double quotation mark)
$htmlEntities["&rdquo;"] ="\xE2\x80\x9D"; // &#8221; (right double quotation mark)
$htmlEntities["&bdquo;"] ="\xE2\x80\x9E"; // &#8222; (double low-9 quotation mark)
$htmlEntities["&dagger;"] ="\xE2\x80\xA0"; // &#8224; (dagger)
$htmlEntities["&Dagger;"] ="\xE2\x80\xA1"; // &#8225; (double dagger)
$htmlEntities["&bull;"] ="\xE2\x80\xA2"; // &#8226; (bullet)
$htmlEntities["&hellip;"] ="\xE2\x80\xA6"; // &#8230; (horizontal ellipsis)
$htmlEntities["&permil;"] ="\xE2\x80\xB0"; // &#8240; (per mille)
$htmlEntities["&prime;"] ="\xE2\x80\xB2"; // &#8242; (minutes or prime)
$htmlEntities["&Prime;"] ="\xE2\x80\xB3"; // &#8243; (seconds or Double Prime)
$htmlEntities["&lsaquo;"] ="\xE2\x80\xB9"; // &#8249; (single left angle quotation)
$htmlEntities["&rsaquo;"] ="\xE2\x80\xBA"; // &#8250; (single right angle quotation)
$htmlEntities["&oline;"] ="\xE2\x80\xBE"; // &#8254; (overline)
$htmlEntities["&frasl;"] ="\xE2\x81\x84"; // &#8260; (fraction slash)
$htmlEntities["&euro;"] ="\xE2\x82\xAC"; // &#8364; (euro)
$htmlEntities["&image;"] ="\xE2\x84\x91"; // &#8465; (blackletter capital I)
$htmlEntities["&weierp;"] ="\xE2\x84\x98"; // &#8472; (script capital P)
$htmlEntities["&real;"] ="\xE2\x84\x9C"; // &#8476; (blackletter capital R)
$htmlEntities["&trade;"] ="\xE2\x84\xA2"; // &#8482; (trademark)
$htmlEntities["&alefsym;"] ="\xE2\x84\xB5"; // &#8501; (alef)
$htmlEntities["&larr;"] ="\xE2\x86\x90"; // &#8592; (left arrow)
$htmlEntities["&uarr;"] ="\xE2\x86\x91"; // &#8593; (up arrow)
$htmlEntities["&rarr;"] ="\xE2\x86\x92"; // &#8594; (right arrow)
$htmlEntities["&darr;"] ="\xE2\x86\x93"; // &#8595; (down arrow)
$htmlEntities["&harr;"] ="\xE2\x86\x94"; // &#8596; (left right arrow)
$htmlEntities["&crarr;"] ="\xE2\x86\xB5"; // &#8629; (carriage return arrow)
$htmlEntities["&lArr;"] ="\xE2\x87\x90"; // &#8656; (left double arrow)
$htmlEntities["&uArr;"] ="\xE2\x87\x91"; // &#8657; (up double arrow)
$htmlEntities["&rArr;"] ="\xE2\x87\x92"; // &#8658; (right double arrow)
$htmlEntities["&dArr;"] ="\xE2\x87\x93"; // &#8659; (down double arrow)
$htmlEntities["&hArr;"] ="\xE2\x87\x94"; // &#8660; (left right double arrow)
$htmlEntities["&forall;"] ="\xE2\x88\x80"; // &#8704; (for all)
$htmlEntities["&part;"] ="\xE2\x88\x82"; // &#8706; (partial differential)
$htmlEntities["&exist;"] ="\xE2\x88\x83"; // &#8707; (there exists)
$htmlEntities["&empty;"] ="\xE2\x88\x85"; // &#8709; (empty set)
$htmlEntities["&nabla;"] ="\xE2\x88\x87"; // &#8711; (backward difference)
$htmlEntities["&isin;"] ="\xE2\x88\x88"; // &#8712; (element of)
$htmlEntities["&notin;"] ="\xE2\x88\x89"; // &#8713; (not an element of)
$htmlEntities["&ni;"] ="\xE2\x88\x8B"; // &#8715; (ni = contains as member)
$htmlEntities["&prod;"] ="\xE2\x88\x8F"; // &#8719; (n-ary product)
$htmlEntities["&sum;"] ="\xE2\x88\x91"; // &#8721; (n-ary sumation)
$htmlEntities["&minus;"] ="\xE2\x88\x92"; // &#8722; (minus)
$htmlEntities["&lowast;"] ="\xE2\x88\x97"; // &#8727; (asterisk operator)
$htmlEntities["&radic;"] ="\xE2\x88\x9A"; // &#8730; (square root)
$htmlEntities["&prop;"] ="\xE2\x88\x9D"; // &#8733; (proportional to)
$htmlEntities["&infin;"] ="\xE2\x88\x9E"; // &#8734; (infinity)
$htmlEntities["&ang;"] ="\xE2\x88\xA0"; // &#8736; (angle)
$htmlEntities["&and;"] ="\xE2\x88\xA7"; // &#8743; (logical and)
$htmlEntities["&or;"] ="\xE2\x88\xA8"; // &#8744; (logical or)
$htmlEntities["&cap;"] ="\xE2\x88\xA9"; // &#8745; (intersection)
$htmlEntities["&cup;"] ="\xE2\x88\xAA"; // &#8746; (union)
$htmlEntities["&int;"] ="\xE2\x88\xAB"; // &#8747; (integral)
$htmlEntities["&there4;"] ="\xE2\x88\xB4"; // &#8756; (therefore)
$htmlEntities["&sim;"] ="\xE2\x88\xBC"; // &#8764; (similar to)
$htmlEntities["&cong;"] ="\xE2\x89\x85"; // &#8773; (congruent to)
$htmlEntities["&asymp;"] ="\xE2\x89\x88"; // &#8776; (approximately equal)
$htmlEntities["&ne;"] ="\xE2\x89\xA0"; // &#8800; (not equal)
$htmlEntities["&equiv;"] ="\xE2\x89\xA1"; // &#8801; (equivalent)
$htmlEntities["&le;"] ="\xE2\x89\xA4"; // &#8804; (less or equal)
$htmlEntities["&ge;"] ="\xE2\x89\xA5"; // &#8805; (greater or equal)
$htmlEntities["&sub;"] ="\xE2\x8A\x82"; // &#8834; (subset of)
$htmlEntities["&sup;"] ="\xE2\x8A\x83"; // &#8835; (superset of)
$htmlEntities["&nsub;"] ="\xE2\x8A\x84"; // &#8836; (not subset of)
$htmlEntities["&sube;"] ="\xE2\x8A\x86"; // &#8838; (subset or equal)
$htmlEntities["&supe;"] ="\xE2\x8A\x87"; // &#8839; (superset or equal)
$htmlEntities["&oplus;"] ="\xE2\x8A\x95"; // &#8853; (circled plus)
$htmlEntities["&otimes;"] ="\xE2\x8A\x87"; // &#8855; (circled times)
$htmlEntities["&perp;"] ="\xE2\x8A\xA5"; // &#8869; (perpendicular)
$htmlEntities["&sdot;"] ="\xE2\x8C\x85"; // &#8901; (dot operator)
$htmlEntities["&lceil;"] ="\xE2\x8C\x88"; // &#8968; (left ceiling)
$htmlEntities["&rceil;"] ="\xE2\x8C\x89"; // &#8969; (right ceiling)
$htmlEntities["&lfloor;"] ="\xE2\x8C\x8A"; // &#8970; (left floor)
$htmlEntities["&rfloor;"] ="\xE2\x8C\x8B"; // &#8971; (right floor)
$htmlEntities["&lang;"] ="\xE2\x8C\xA9"; // &#9001; (left angle bracket = bra)
$htmlEntities["&rang;"] ="\xE2\x8C\xAA"; // &#9002; (right angle bracket = ket)
$htmlEntities["&loz;"] ="\xE2\x97\x8A"; // &#9674; (lozenge)
$htmlEntities["&spades;"] ="\xE2\x99\xA0"; // &#9824; (spade)
$htmlEntities["&clubs;"] ="\xE2\x99\xA3"; // &#9827; (club)
$htmlEntities["&hearts;"] ="\xE2\x99\xA5"; // &#9829; (heart)
$htmlEntities["&diams;"] ="\xE2\x99\xA6"; // &#9830; (diamond)
?>

View File

@ -0,0 +1,782 @@
<?php
/**
* ePub NCX file structure
*
* @author A. Grandt <php@grandt.com>
* @copyright 2009-2014 A. Grandt
* @license GNU LGPL, Attribution required for commercial implementations, requested for everything else.
* @version 3.20
*/
class Ncx {
const _VERSION = 3.20;
const MIMETYPE = "application/x-dtbncx+xml";
private $bookVersion = EPub::BOOK_VERSION_EPUB2;
private $navMap = NULL;
private $uid = NULL;
private $meta = array();
private $docTitle = NULL;
private $docAuthor = NULL;
private $currentLevel = NULL;
private $lastLevel = NULL;
private $languageCode = "en";
private $writingDirection = EPub::DIRECTION_LEFT_TO_RIGHT;
public $chapterList = array();
public $referencesTitle = "Guide";
public $referencesClass = "references";
public $referencesId = "references";
public $referencesList = array();
public $referencesName = array();
public $referencesOrder = NULL;
/**
* Class constructor.
*
* @param string $uid
* @param string $docTitle
* @param string $docAuthor
* @param string $languageCode
* @param string $writingDirection
*/
function __construct($uid = NULL, $docTitle = NULL, $docAuthor = NULL, $languageCode = "en", $writingDirection = EPub::DIRECTION_LEFT_TO_RIGHT) {
$this->navMap = new NavMap($writingDirection);
$this->currentLevel = $this->navMap;
$this->setUid($uid);
$this->setDocTitle($docTitle);
$this->setDocAuthor($docAuthor);
$this->setLanguageCode($languageCode);
$this->setWritingDirection($writingDirection);
}
/**
* Class destructor
*
* @return void
*/
function __destruct() {
unset($this->bookVersion, $this->navMap, $this->uid, $this->meta);
unset($this->docTitle, $this->docAuthor, $this->currentLevel, $this->lastLevel);
unset($this->languageCode, $this->writingDirection, $this->chapterList, $this->referencesTitle);
unset($this->referencesClass, $this->referencesId, $this->referencesList, $this->referencesName);
unset($this->referencesOrder);
}
/**
*
* Enter description here ...
*
* @param string $bookVersion
*/
function setVersion($bookVersion) {
$this->bookVersion = is_string($bookVersion) ? trim($bookVersion) : EPub::BOOK_VERSION_EPUB2;
}
/**
*
* @return bool TRUE if the book is set to type ePub 2
*/
function isEPubVersion2() {
return $this->bookVersion === EPub::BOOK_VERSION_EPUB2;
}
/**
*
* Enter description here ...
*
* @param string $uid
*/
function setUid($uid) {
$this->uid = is_string($uid) ? trim($uid) : NULL;
}
/**
*
* Enter description here ...
*
* @param string $docTitle
*/
function setDocTitle($docTitle) {
$this->docTitle = is_string($docTitle) ? trim($docTitle) : NULL;
}
/**
*
* Enter description here ...
*
* @param string $docAuthor
*/
function setDocAuthor($docAuthor) {
$this->docAuthor = is_string($docAuthor) ? trim($docAuthor) : NULL;
}
/**
*
* Enter description here ...
*
* @param string $languageCode
*/
function setLanguageCode($languageCode) {
$this->languageCode = is_string($languageCode) ? trim($languageCode) : "en";
}
/**
*
* Enter description here ...
*
* @param string $writingDirection
*/
function setWritingDirection($writingDirection) {
$this->writingDirection = is_string($writingDirection) ? trim($writingDirection) : EPub::DIRECTION_LEFT_TO_RIGHT;
}
/**
*
* Enter description here ...
*
* @param NavMap $navMap
*/
function setNavMap($navMap) {
if ($navMap != NULL && is_object($navMap) && get_class($navMap) === "NavMap") {
$this->navMap = $navMap;
}
}
/**
* Add one chapter level.
*
* Subsequent chapters will be added to this level.
*
* @param string $navTitle
* @param string $navId
* @param string $navClass
* @param string $isNavHidden
* @param string $writingDirection
* @return NavPoint
*/
function subLevel($navTitle = NULL, $navId = NULL, $navClass = NULL, $isNavHidden = FALSE, $writingDirection = NULL) {
$navPoint = FALSE;
if (isset($navTitle) && isset($navClass)) {
$navPoint = new NavPoint($navTitle, NULL, $navId, $navClass, $isNavHidden, $writingDirection);
$this->addNavPoint($navPoint);
}
if ($this->lastLevel !== NULL) {
$this->currentLevel = $this->lastLevel;
}
return $navPoint;
}
/**
* Step back one chapter level.
*
* Subsequent chapters will be added to this chapters parent level.
*/
function backLevel() {
$this->lastLevel = $this->currentLevel;
$this->currentLevel = $this->currentLevel->getParent();
}
/**
* Step back to the root level.
*
* Subsequent chapters will be added to the rooot NavMap.
*/
function rootLevel() {
$this->lastLevel = $this->currentLevel;
$this->currentLevel = $this->navMap;
}
/**
* Step back to the given level.
* Useful for returning to a previous level from deep within the structure.
* Values below 2 will have the same effect as rootLevel()
*
* @param int $newLevel
*/
function setCurrentLevel($newLevel) {
if ($newLevel <= 1) {
$this->rootLevel();
} else {
while ($this->currentLevel->getLevel() > $newLevel) {
$this->backLevel();
}
}
}
/**
* Get current level count.
* The indentation of the current structure point.
*
* @return current level count;
*/
function getCurrentLevel() {
return $this->currentLevel->getLevel();
}
/**
* Add child NavPoints to current level.
*
* @param NavPoint $navPoint
*/
function addNavPoint($navPoint) {
$this->lastLevel = $this->currentLevel->addNavPoint($navPoint);
}
/**
*
* Enter description here ...
*
* @return NavMap
*/
function getNavMap() {
return $this->navMap;
}
/**
*
* Enter description here ...
*
* @param string $name
* @param string $content
*/
function addMetaEntry($name, $content) {
$name = is_string($name) ? trim($name) : NULL;
$content = is_string($content) ? trim($content) : NULL;
if ($name != NULL && $content != NULL) {
$this->meta[] = array($name => $content);
}
}
/**
*
* Enter description here ...
*
* @return string
*/
function finalize() {
$nav = $this->navMap->finalize();
$ncx = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
if ($this->isEPubVersion2()) {
$ncx .= "<!DOCTYPE ncx PUBLIC \"-//NISO//DTD ncx 2005-1//EN\"\n"
. " \"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd\">\n";
}
$ncx .= "<ncx xmlns=\"http://www.daisy.org/z3986/2005/ncx/\" version=\"2005-1\" xml:lang=\"" . $this->languageCode . "\" dir=\"" . $this->writingDirection . "\">\n"
. "\t<head>\n"
. "\t\t<meta name=\"dtb:uid\" content=\"" . $this->uid . "\" />\n"
. "\t\t<meta name=\"dtb:depth\" content=\"" . $this->navMap->getNavLevels() . "\" />\n"
. "\t\t<meta name=\"dtb:totalPageCount\" content=\"0\" />\n"
. "\t\t<meta name=\"dtb:maxPageNumber\" content=\"0\" />\n";
if (sizeof($this->meta)) {
foreach ($this->meta as $metaEntry) {
list($name, $content) = each($metaEntry);
$ncx .= "\t\t<meta name=\"" . $name . "\" content=\"" . $content . "\" />\n";
}
}
$ncx .= "\t</head>\n\n\t<docTitle>\n\t\t<text>"
. $this->docTitle
. "</text>\n\t</docTitle>\n\n\t<docAuthor>\n\t\t<text>"
. $this->docAuthor
. "</text>\n\t</docAuthor>\n\n"
. $nav;
return $ncx . "</ncx>\n";
}
/**
*
* @param string $title
* @param string $cssFileName
* @return string
*/
function finalizeEPub3($title = "Table of Contents", $cssFileName = NULL) {
$end = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
. "<html xmlns=\"http://www.w3.org/1999/xhtml\"\n"
. " xmlns:epub=\"http://www.idpf.org/2007/ops\"\n"
. " xml:lang=\"" . $this->languageCode . "\" lang=\"" . $this->languageCode . "\" dir=\"" . $this->writingDirection . "\">\n"
. "\t<head>\n"
. "\t\t<title>" . $this->docTitle . "</title>\n"
. "\t\t<meta http-equiv=\"default-style\" content=\"text/html; charset=utf-8\"/>\n";
if ($cssFileName !== NULL) {
$end .= "\t\t<link rel=\"stylesheet\" href=\"" . $cssFileName . "\" type=\"text/css\"/>\n";
}
$end .= "\t</head>\n"
. "\t<body epub:type=\"frontmatter toc\">\n"
. "\t\t<header>\n"
. "\t\t\t<h1>" . $title . "</h1>\n"
. "\t\t</header>\n"
. $this->navMap->finalizeEPub3()
. $this->finalizeEPub3Landmarks()
. "\t</body>\n"
. "</html>\n";
return $end;
}
/**
* Build the references for the ePub 2 toc.
* These are merely reference pages added to the end of the navMap though.
*
* @return string
*/
function finalizeReferences() {
if (isset($this->referencesList) && sizeof($this->referencesList) > 0) {
$this->rootLevel();
$this->subLevel($this->referencesTitle, $this->referencesId, $this->referencesClass);
$refId = 1;
while (list($item, $descriptive) = each($this->referencesOrder)) {
if (array_key_exists($item, $this->referencesList)) {
$name = (empty($this->referencesName[$item]) ? $descriptive : $this->referencesName[$item]);
$navPoint = new NavPoint($name, $this->referencesList[$item], "ref-" . $refId++);
$this->addNavPoint($navPoint);
}
}
}
}
/**
* Build the landmarks for the ePub 3 toc.
* @return string
*/
function finalizeEPub3Landmarks() {
$lm = "";
if (isset($this->referencesList) && sizeof($this->referencesList) > 0) {
$lm = "\t\t\t<nav epub:type=\"landmarks\">\n"
. "\t\t\t\t<h2"
. ($this->writingDirection === EPub::DIRECTION_RIGHT_TO_LEFT ? " dir=\"rtl\"" : "")
. ">" . $this->referencesTitle . "</h2>\n"
. "\t\t\t\t<ol>\n";
$li = "";
while (list($item, $descriptive) = each($this->referencesOrder)) {
if (array_key_exists($item, $this->referencesList)) {
$li .= "\t\t\t\t\t<li><a epub:type=\""
. $item
. "\" href=\"" . $this->referencesList[$item] . "\">"
. (empty($this->referencesName[$item]) ? $descriptive : $this->referencesName[$item])
. "</a></li>\n";
}
}
if (empty($li)) {
return "";
}
$lm .= $li
. "\t\t\t\t</ol>\n"
. "\t\t\t</nav>\n";
}
return $lm;
}
}
/**
* ePub NavMap class
*/
class NavMap {
const _VERSION = 3.00;
private $navPoints = array();
private $navLevels = 0;
private $writingDirection = NULL;
/**
* Class constructor.
*
* @return void
*/
function __construct($writingDirection = NULL) {
$this->setWritingDirection($writingDirection);
}
/**
* Class destructor
*
* @return void
*/
function __destruct() {
unset($this->navPoints, $this->navLevels, $this->writingDirection);
}
/**
* Set the writing direction to be used for this NavPoint.
*
* @param string $writingDirection
*/
function setWritingDirection($writingDirection) {
$this->writingDirection = isset($writingDirection) && is_string($writingDirection) ? trim($writingDirection) : NULL;
}
function getWritingDirection() {
return $this->writingDirection;
}
/**
* Add a navPoint to the root of the NavMap.
*
* @param NavPoint $navPoint
* @return NavMap
*/
function addNavPoint($navPoint) {
if ($navPoint != NULL && is_object($navPoint) && get_class($navPoint) === "NavPoint") {
$navPoint->setParent($this);
if ($navPoint->getWritingDirection() == NULL) {
$navPoint->setWritingDirection($this->writingDirection);
}
$this->navPoints[] = $navPoint;
return $navPoint;
}
return $this;
}
/**
* The final max depth for the "dtb:depth" meta attribute
* Only available after finalize have been called.
*
* @return number
*/
function getNavLevels() {
return $this->navLevels+1;
}
function getLevel() {
return 1;
}
function getParent() {
return $this;
}
/**
* Finalize the navMap, the final max depth for the "dtb:depth" meta attribute can be retrieved with getNavLevels after finalization
*
*/
function finalize() {
$playOrder = 0;
$this->navLevels = 0;
$nav = "\t<navMap>\n";
if (sizeof($this->navPoints) > 0) {
$this->navLevels++;
foreach ($this->navPoints as $navPoint) {
$retLevel = $navPoint->finalize($nav, $playOrder, 0);
if ($retLevel > $this->navLevels) {
$this->navLevels = $retLevel;
}
}
}
return $nav . "\t</navMap>\n";
}
/**
* Finalize the navMap, the final max depth for the "dtb:depth" meta attribute can be retrieved with getNavLevels after finalization
*
*/
function finalizeEPub3() {
$playOrder = 0;
$level = 0;
$this->navLevels = 0;
$nav = "\t\t<nav epub:type=\"toc\" id=\"toc\">\n";
if (sizeof($this->navPoints) > 0) {
$this->navLevels++;
$nav .= str_repeat("\t", $level) . "\t\t\t<ol epub:type=\"list\">\n";
foreach ($this->navPoints as $navPoint) {
$retLevel = $navPoint->finalizeEPub3($nav, $playOrder, 0);
if ($retLevel > $this->navLevels) {
$this->navLevels = $retLevel;
}
}
$nav .= str_repeat("\t", $level) . "\t\t\t</ol>\n";
}
return $nav . "\t\t</nav>\n";
}
}
/**
* ePub NavPoint class
*/
class NavPoint {
const _VERSION = 3.00;
private $label = NULL;
private $contentSrc = NULL;
private $id = NULL;
private $navClass = NULL;
private $isNavHidden = FALSE;
private $navPoints = array();
private $parent = NULL;
/**
* Class constructor.
*
* All three attributes are mandatory, though if ID is set to null (default) the value will be generated.
*
* @param string $label
* @param string $contentSrc
* @param string $id
* @param string $navClass
* @param bool $isNavHidden
* @param string $writingDirection
*/
function __construct($label, $contentSrc = NULL, $id = NULL, $navClass = NULL, $isNavHidden = FALSE, $writingDirection = NULL) {
$this->setLabel($label);
$this->setContentSrc($contentSrc);
$this->setId($id);
$this->setNavClass($navClass);
$this->setNavHidden($isNavHidden);
$this->setWritingDirection($writingDirection);
}
/**
* Class destructor
*
* @return void
*/
function __destruct() {
unset($this->label, $this->contentSrc, $this->id, $this->navClass);
unset($this->isNavHidden, $this->navPoints, $this->parent);
}
/**
* Set the Text label for the NavPoint.
*
* The label is mandatory.
*
* @param string $label
*/
function setLabel($label) {
$this->label = is_string($label) ? trim($label) : NULL;
}
/**
* Get the Text label for the NavPoint.
*
* @return string Label
*/
function getLabel() {
return $this->label;
}
/**
* Set the src reference for the NavPoint.
*
* The src is mandatory for ePub 2.
*
* @param string $contentSrc
*/
function setContentSrc($contentSrc) {
$this->contentSrc = isset($contentSrc) && is_string($contentSrc) ? trim($contentSrc) : NULL;
}
/**
* Get the src reference for the NavPoint.
*
* @return string content src url.
*/
function getContentSrc() {
return $this->contentSrc;
}
/**
* Set the parent for this NavPoint.
*
* @param NavPoint or NavMap $parent
*/
function setParent($parent) {
if ($parent != NULL && is_object($parent) &&
(get_class($parent) === "NavPoint" || get_class($parent) === "NavMap") ) {
$this->parent = $parent;
}
}
/**
* Get the parent to this NavPoint.
*
* @return NavPoint, or NavMap if the parent is the root.
*/
function getParent() {
return $this->parent;
}
/**
* Get the current level. 1 = document root.
*
* @return int level
*/
function getLevel() {
return $this->parent === NULL ? 1 : $this->parent->getLevel()+1;
}
/**
* Set the id for the NavPoint.
*
* The id must be unique, and is mandatory.
*
* @param string $id
*/
function setId($id) {
$this->id = is_string($id) ? trim($id) : NULL;
}
/**
* Set the class to be used for this NavPoint.
*
* @param string $navClass
*/
function setNavClass($navClass) {
$this->navClass = isset($navClass) && is_string($navClass) ? trim($navClass) : NULL;
}
/**
* Set the class to be used for this NavPoint.
*
* @param string $navClass
*/
function setNavHidden($isNavHidden) {
$this->isNavHidden = $isNavHidden === TRUE;
}
/**
* Set the writing direction to be used for this NavPoint.
*
* @param string $writingDirection
*/
function setWritingDirection($writingDirection) {
$this->writingDirection = isset($writingDirection) && is_string($writingDirection) ? trim($writingDirection) : NULL;
}
function getWritingDirection() {
return $this->writingDirection;
}
/**
* Add child NavPoints for multi level NavMaps.
*
* @param NavPoint $navPoint
*/
function addNavPoint($navPoint) {
if ($navPoint != NULL && is_object($navPoint) && get_class($navPoint) === "NavPoint") {
$navPoint->setParent($this);
if ($navPoint->getWritingDirection() == NULL) {
$navPoint->setWritingDirection($this->writingDirection);
}
$this->navPoints[] = $navPoint;
return $navPoint;
}
return $this;
}
/**
*
* Enter description here ...
*
* @param string $nav
* @param int $playOrder
* @param int $level
* @return int
*/
function finalize(&$nav = "", &$playOrder = 0, $level = 0) {
$maxLevel = $level;
$levelAdjust = 0;
if ($this->isNavHidden) {
return $maxLevel;
}
if (isset($this->contentSrc)) {
$playOrder++;
if ($this->id == NULL) {
$this->id = "navpoint-" . $playOrder;
}
$nav .= str_repeat("\t", $level) . "\t\t<navPoint id=\"" . $this->id . "\" playOrder=\"" . $playOrder . "\">\n"
. str_repeat("\t", $level) . "\t\t\t<navLabel>\n"
. str_repeat("\t", $level) . "\t\t\t\t<text>" . $this->label . "</text>\n"
. str_repeat("\t", $level) . "\t\t\t</navLabel>\n"
. str_repeat("\t", $level) . "\t\t\t<content src=\"" . $this->contentSrc . "\" />\n";
} else {
$levelAdjust++;
}
if (sizeof($this->navPoints) > 0) {
$maxLevel++;
foreach ($this->navPoints as $navPoint) {
$retLevel = $navPoint->finalize($nav, $playOrder, ($level+1+$levelAdjust));
if ($retLevel > $maxLevel) {
$maxLevel = $retLevel;
}
}
}
if (isset($this->contentSrc)) {
$nav .= str_repeat("\t", $level) . "\t\t</navPoint>\n";
}
return $maxLevel;
}
/**
*
* Enter description here ...
*
* @param string $nav
* @param int $playOrder
* @param int $level
* @return int
*/
function finalizeEPub3(&$nav = "", &$playOrder = 0, $level = 0, $subLevelClass = NULL, $subLevelHidden = FALSE) {
$maxLevel = $level;
if ($this->id == NULL) {
$this->id = "navpoint-" . $playOrder;
}
$indent = str_repeat("\t", $level) . "\t\t\t\t";
$nav .= $indent . "<li id=\"" . $this->id . "\"";
if (isset($this->writingDirection)) {
$nav .= " dir=\"" . $this->writingDirection . "\"";
}
$nav .= ">\n";
if (isset($this->contentSrc)) {
$nav .= $indent . "\t<a href=\"" . $this->contentSrc . "\">" . $this->label . "</a>\n";
} else {
$nav .= $indent . "\t<span>" . $this->label . "</span>\n";
}
if (sizeof($this->navPoints) > 0) {
$maxLevel++;
$nav .= $indent . "\t<ol epub:type=\"list\"";
if (isset($subLevelClass)) {
$nav .= " class=\"" . $subLevelClass . "\"";
}
if ($subLevelHidden) {
$nav .= " hidden=\"hidden\"";
}
$nav .= ">\n";
foreach ($this->navPoints as $navPoint) {
$retLevel = $navPoint->finalizeEPub3($nav, $playOrder, ($level+2), $subLevelClass, $subLevelHidden);
if ($retLevel > $maxLevel) {
$maxLevel = $retLevel;
}
}
$nav .= $indent . "\t</ol>\n";
}
$nav .= $indent . "</li>\n";
return $maxLevel;
}
}
?>

File diff suppressed because it is too large Load Diff

2429
inc/3rdparty/libraries/PHPePub/EPub.php vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,201 @@
<?php
/**
* Split an HTML file into smaller html files, retaining the formatting and structure for the individual parts.
* What this splitter does is using DOM to try and retain any formatting in the file, including rebuilding the DOM tree for subsequent parts.
* Split size is considered max target size. The actual size is the result of an even split across the resulting files.
*
* @author A. Grandt <php@grandt.com>
* @copyright 2009-2014 A. Grandt
* @license GNU LGPL 2.1
* @link http://www.phpclasses.org/package/6115
* @link https://github.com/Grandt/PHPePub
* @version 3.20
*/
class EPubChapterSplitter {
const VERSION = 3.20;
private $splitDefaultSize = 250000;
private $bookVersion = EPub::BOOK_VERSION_EPUB2;
/**
*
* Enter description here ...
*
* @param unknown_type $ident
*/
function setVersion($bookVersion) {
$this->bookVersion = is_string($bookVersion) ? trim($bookVersion) : EPub::BOOK_VERSION_EPUB2;
}
/**
* Set default chapter target size.
* Default is 250000 bytes, and minimum is 10240 bytes.
*
* @param $size segment size in bytes
* @return void
*/
function setSplitSize($size) {
$this->splitDefaultSize = (int)$size;
if ($size < 10240) {
$this->splitDefaultSize = 10240; // Making the file smaller than 10k is not a good idea.
}
}
/**
* Get the chapter target size.
*
* @return $size
*/
function getSplitSize() {
return $this->splitDefaultSize;
}
/**
* Split $chapter into multiple parts.
*
* 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
* If the search string is a regular string, the matching will be for lines in the HTML starting with the string given
*
* @param String $chapter XHTML file
* @param Bool $splitOnSearchString Split on chapter boundaries, Splitting on search strings disables the split size check.
* @param String $searchString Chapter string to search for can be fixed text, or a regular expression pattern.
*
* @return array with 1 or more parts
*/
function splitChapter($chapter, $splitOnSearchString = false, $searchString = '/^Chapter\\ /i') {
$chapterData = array();
$isSearchRegexp = $splitOnSearchString && (preg_match('#^(\D|\S|\W).+\1[imsxeADSUXJu]*$#m', $searchString) == 1);
if ($splitOnSearchString && !$isSearchRegexp) {
$searchString = '#^<.+?>' . preg_quote($searchString, '#') . "#";
}
if (!$splitOnSearchString && strlen($chapter) <= $this->splitDefaultSize) {
return array($chapter);
}
$xmlDoc = new DOMDocument();
@$xmlDoc->loadHTML($chapter);
$head = $xmlDoc->getElementsByTagName("head");
$body = $xmlDoc->getElementsByTagName("body");
$htmlPos = stripos($chapter, "<html");
$htmlEndPos = stripos($chapter, ">", $htmlPos);
$newXML = substr($chapter, 0, $htmlEndPos+1) . "\n</html>";
if (strpos(trim($newXML), "<?xml ") === FALSE) {
$newXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" . $newXML;
}
$headerLength = strlen($newXML);
$files = array();
$chapterNames = array();
$domDepth = 0;
$domPath = array();
$domClonedPath = array();
$curFile = $xmlDoc->createDocumentFragment();
$files[] = $curFile;
$curParent = $curFile;
$curSize = 0;
$bodyLen = strlen($xmlDoc->saveXML($body->item(0)));
$headLen = strlen($xmlDoc->saveXML($head->item(0))) + $headerLength;
$partSize = $this->splitDefaultSize - $headLen;
if ($bodyLen > $partSize) {
$parts = ceil($bodyLen / $partSize);
$partSize = ($bodyLen / $parts) - $headLen;
}
$node = $body->item(0)->firstChild;
do {
$nodeData = $xmlDoc->saveXML($node);
$nodeLen = strlen($nodeData);
if ($nodeLen > $partSize && $node->hasChildNodes()) {
$domPath[] = $node;
$domClonedPath[] = $node->cloneNode(false);
$domDepth++;
$node = $node->firstChild;
}
$node2 = $node->nextSibling;
if ($node != null && $node->nodeName != "#text") {
$doSplit = false;
if ($splitOnSearchString) {
$doSplit = preg_match($searchString, $nodeData) == 1;
if ($doSplit) {
$chapterNames[] = trim($nodeData);
}
}
if ($curSize > 0 && ($doSplit || (!$splitOnSearchString && $curSize + $nodeLen > $partSize))) {
$curFile = $xmlDoc->createDocumentFragment();
$files[] = $curFile;
$curParent = $curFile;
if ($domDepth > 0) {
reset($domPath);
reset($domClonedPath);
$oneDomClonedPath = each($domClonedPath);
while ($oneDomClonedPath) {
list($k, $v) = $oneDomClonedPath;
$newParent = $v->cloneNode(false);
$curParent->appendChild($newParent);
$curParent = $newParent;
$oneDomClonedPath = each($domClonedPath);
}
}
$curSize = strlen($xmlDoc->saveXML($curFile));
}
$curParent->appendChild($node->cloneNode(true));
$curSize += $nodeLen;
}
$node = $node2;
while ($node == null && $domDepth > 0) {
$domDepth--;
$node = end($domPath)->nextSibling;
array_pop($domPath);
array_pop($domClonedPath);
$curParent = $curParent->parentNode;
}
} while ($node != null);
$curFile = null;
$curSize = 0;
$xml = new DOMDocument('1.0', $xmlDoc->xmlEncoding);
$xml->lookupPrefix("http://www.w3.org/1999/xhtml");
$xml->preserveWhiteSpace = false;
$xml->formatOutput = true;
for ($idx = 0; $idx < count($files); $idx++) {
$xml2Doc = new DOMDocument('1.0', $xmlDoc->xmlEncoding);
$xml2Doc->lookupPrefix("http://www.w3.org/1999/xhtml");
$xml2Doc->loadXML($newXML);
$html = $xml2Doc->getElementsByTagName("html")->item(0);
$html->appendChild($xml2Doc->importNode($head->item(0), true));
$body = $xml2Doc->createElement("body");
$html->appendChild($body);
$body->appendChild($xml2Doc->importNode($files[$idx], true));
// force pretty printing and correct formatting, should not be needed, but it is.
$xml->loadXML($xml2Doc->saveXML());
$doc = $xml->saveXML();
if ($this->bookVersion === EPub::BOOK_VERSION_EPUB3) {
$doc = preg_replace('#^\s*<!DOCTYPE\ .+?>\s*#im', '', $doc);
}
$chapterData[$splitOnSearchString ? $chapterNames[$idx] : $idx] = $doc;
}
return $chapterData;
}
}
?>

View File

@ -0,0 +1,92 @@
<?php
/**
* Simple log line aggregator.
*
* @author A. Grandt <php@grandt.com>
* @copyright 2012-2013 A. Grandt
* @license GNU LGPL, Attribution required for commercial implementations, requested for everything else.
* @version 1.00
*/
class Logger {
const VERSION = 1.00;
private $log = "";
private $tStart;
private $tLast;
private $name = NULL;
private $isLogging = FALSE;
private $isDebugging = FALSE;
/**
* Class constructor.
*
* @return void
*/
function __construct($name = NULL, $isLogging = FALSE) {
if ($name === NULL) {
$this->name = "";
} else {
$this->name = $name . " : ";
}
$this->isLogging = $isLogging;
$this->start();
}
/**
* Class destructor
*
* @return void
* @TODO make sure elements in the destructor match the current class elements
*/
function __destruct() {
unset($this->log);
}
function start() {
/* Prepare Logging. Just in case it's used. later */
if ($this->isLogging) {
$this->tStart = gettimeofday();
$this->tLast = $this->tStart;
$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 ;";
$this->logLine("Start");
}
}
function dumpInstalledModules() {
if ($this->isLogging) {
$isCurlInstalled = extension_loaded('curl') && function_exists('curl_version');
$isGdInstalled = extension_loaded('gd') && function_exists('gd_info');
$isExifInstalled = extension_loaded('exif') && function_exists('exif_imagetype');
$isFileGetContentsInstalled = function_exists('file_get_contents');
$isFileGetContentsExtInstalled = $isFileGetContentsInstalled && ini_get('allow_url_fopen');
$this->logLine("isCurlInstalled...............: " . ($isCurlInstalled ? "Yes" : "No"));
$this->logLine("isGdInstalled.................: " . ($isGdInstalled ? "Yes" : "No"));
$this->logLine("isExifInstalled...............: " . ($isExifInstalled ? "Yes" : "No"));
$this->logLine("isFileGetContentsInstalled....: " . ($isFileGetContentsInstalled ? "Yes" : "No"));
$this->logLine("isFileGetContentsExtInstalled.: " . ($isFileGetContentsExtInstalled ? "Yes" : "No"));
}
}
function logLine($line) {
if ($this->isLogging) {
$tTemp = gettimeofday();
$tS = $this->tStart['sec'] + (((int)($this->tStart['usec']/100))/10000);
$tL = $this->tLast['sec'] + (((int)($this->tLast['usec']/100))/10000);
$tT = $tTemp['sec'] + (((int)($tTemp['usec']/100))/10000);
$logline = sprintf("\n+%08.04f; +%08.04f; ", ($tT-$tS), ($tT-$tL)) . $this->name . $line;
$this->log .= $logline;
$this->tLast = $tTemp;
if ($this->isDebugging) {
echo "<pre>" . $logline . "\n</pre>\n";
}
}
}
function getLog() {
return $this->log;
}
}
?>

818
inc/3rdparty/libraries/PHPePub/Zip.php vendored Normal file
View File

@ -0,0 +1,818 @@
<?php
/**
* Class to create and manage a Zip file.
*
* Initially inspired by CreateZipFile by Rochak Chauhan www.rochakchauhan.com (http://www.phpclasses.org/browse/package/2322.html)
* and
* http://www.pkware.com/documents/casestudies/APPNOTE.TXT Zip file specification.
*
* License: GNU LGPL, Attribution required for commercial implementations, requested for everything else.
*
* @author A. Grandt <php@grandt.com>
* @copyright 2009-2014 A. Grandt
* @license GNU LGPL 2.1
* @link http://www.phpclasses.org/package/6110
* @link https://github.com/Grandt/PHPZip
* @version 1.60
*/
class Zip {
const VERSION = 1.60;
const ZIP_LOCAL_FILE_HEADER = "\x50\x4b\x03\x04"; // Local file header signature
const ZIP_CENTRAL_FILE_HEADER = "\x50\x4b\x01\x02"; // Central file header signature
const ZIP_END_OF_CENTRAL_DIRECTORY = "\x50\x4b\x05\x06\x00\x00\x00\x00"; //end of Central directory record
const EXT_FILE_ATTR_DIR = 010173200020; // Permission 755 drwxr-xr-x = (((S_IFDIR | 0755) << 16) | S_DOS_D);
const EXT_FILE_ATTR_FILE = 020151000040; // Permission 644 -rw-r--r-- = (((S_IFREG | 0644) << 16) | S_DOS_A);
const ATTR_VERSION_TO_EXTRACT = "\x14\x00"; // Version needed to extract
const ATTR_MADE_BY_VERSION = "\x1E\x03"; // Made By Version
// Unix file types
const S_IFIFO = 0010000; // named pipe (fifo)
const S_IFCHR = 0020000; // character special
const S_IFDIR = 0040000; // directory
const S_IFBLK = 0060000; // block special
const S_IFREG = 0100000; // regular
const S_IFLNK = 0120000; // symbolic link
const S_IFSOCK = 0140000; // socket
// setuid/setgid/sticky bits, the same as for chmod:
const S_ISUID = 0004000; // set user id on execution
const S_ISGID = 0002000; // set group id on execution
const S_ISTXT = 0001000; // sticky bit
// And of course, the other 12 bits are for the permissions, the same as for chmod:
// When addding these up, you can also just write the permissions as a simgle octal number
// ie. 0755. The leading 0 specifies octal notation.
const S_IRWXU = 0000700; // RWX mask for owner
const S_IRUSR = 0000400; // R for owner
const S_IWUSR = 0000200; // W for owner
const S_IXUSR = 0000100; // X for owner
const S_IRWXG = 0000070; // RWX mask for group
const S_IRGRP = 0000040; // R for group
const S_IWGRP = 0000020; // W for group
const S_IXGRP = 0000010; // X for group
const S_IRWXO = 0000007; // RWX mask for other
const S_IROTH = 0000004; // R for other
const S_IWOTH = 0000002; // W for other
const S_IXOTH = 0000001; // X for other
const S_ISVTX = 0001000; // save swapped text even after use
// Filetype, sticky and permissions are added up, and shifted 16 bits left BEFORE adding the DOS flags.
// DOS file type flags, we really only use the S_DOS_D flag.
const S_DOS_A = 0000040; // DOS flag for Archive
const S_DOS_D = 0000020; // DOS flag for Directory
const S_DOS_V = 0000010; // DOS flag for Volume
const S_DOS_S = 0000004; // DOS flag for System
const S_DOS_H = 0000002; // DOS flag for Hidden
const S_DOS_R = 0000001; // DOS flag for Read Only
private $zipMemoryThreshold = 1048576; // Autocreate tempfile if the zip data exceeds 1048576 bytes (1 MB)
private $zipData = NULL;
private $zipFile = NULL;
private $zipComment = NULL;
private $cdRec = array(); // central directory
private $offset = 0;
private $isFinalized = FALSE;
private $addExtraField = TRUE;
private $streamChunkSize = 65536;
private $streamFilePath = NULL;
private $streamTimestamp = NULL;
private $streamFileComment = NULL;
private $streamFile = NULL;
private $streamData = NULL;
private $streamFileLength = 0;
private $streamExtFileAttr = null;
/**
* Constructor.
*
* @param boolean $useZipFile Write temp zip data to tempFile? Default FALSE
*/
function __construct($useZipFile = FALSE) {
if ($useZipFile) {
$this->zipFile = tmpfile();
} else {
$this->zipData = "";
}
}
function __destruct() {
if (is_resource($this->zipFile)) {
fclose($this->zipFile);
}
$this->zipData = NULL;
}
/**
* Extra fields on the Zip directory records are Unix time codes needed for compatibility on the default Mac zip archive tool.
* These are enabled as default, as they do no harm elsewhere and only add 26 bytes per file added.
*
* @param bool $setExtraField TRUE (default) will enable adding of extra fields, anything else will disable it.
*/
function setExtraField($setExtraField = TRUE) {
$this->addExtraField = ($setExtraField === TRUE);
}
/**
* Set Zip archive comment.
*
* @param string $newComment New comment. NULL to clear.
* @return bool $success
*/
public function setComment($newComment = NULL) {
if ($this->isFinalized) {
return FALSE;
}
$this->zipComment = $newComment;
return TRUE;
}
/**
* Set zip file to write zip data to.
* This will cause all present and future data written to this class to be written to this file.
* This can be used at any time, even after the Zip Archive have been finalized. Any previous file will be closed.
* Warning: If the given file already exists, it will be overwritten.
*
* @param string $fileName
* @return bool $success
*/
public function setZipFile($fileName) {
if (is_file($fileName)) {
unlink($fileName);
}
$fd=fopen($fileName, "x+b");
if (is_resource($this->zipFile)) {
rewind($this->zipFile);
while (!feof($this->zipFile)) {
fwrite($fd, fread($this->zipFile, $this->streamChunkSize));
}
fclose($this->zipFile);
} else {
fwrite($fd, $this->zipData);
$this->zipData = NULL;
}
$this->zipFile = $fd;
return TRUE;
}
/**
* Add an empty directory entry to the zip archive.
* Basically this is only used if an empty directory is added.
*
* @param string $directoryPath Directory Path and name to be added to the archive.
* @param int $timestamp (Optional) Timestamp for the added directory, if omitted or set to 0, the current time will be used.
* @param string $fileComment (Optional) Comment to be added to the archive for this directory. To use fileComment, timestamp must be given.
* @param int $extFileAttr (Optional) The external file reference, use generateExtAttr to generate this.
* @return bool $success
*/
public function addDirectory($directoryPath, $timestamp = 0, $fileComment = NULL, $extFileAttr = self::EXT_FILE_ATTR_DIR) {
if ($this->isFinalized) {
return FALSE;
}
$directoryPath = str_replace("\\", "/", $directoryPath);
$directoryPath = rtrim($directoryPath, "/");
if (strlen($directoryPath) > 0) {
$this->buildZipEntry($directoryPath.'/', $fileComment, "\x00\x00", "\x00\x00", $timestamp, "\x00\x00\x00\x00", 0, 0, $extFileAttr);
return TRUE;
}
return FALSE;
}
/**
* Add a file to the archive at the specified location and file name.
*
* @param string $data File data.
* @param string $filePath Filepath and name to be used in the archive.
* @param int $timestamp (Optional) Timestamp for the added file, if omitted or set to 0, the current time will be used.
* @param string $fileComment (Optional) Comment to be added to the archive for this file. To use fileComment, timestamp must be given.
* @param bool $compress (Optional) Compress file, if set to FALSE the file will only be stored. Default TRUE.
* @param int $extFileAttr (Optional) The external file reference, use generateExtAttr to generate this.
* @return bool $success
*/
public function addFile($data, $filePath, $timestamp = 0, $fileComment = NULL, $compress = TRUE, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
if ($this->isFinalized) {
return FALSE;
}
if (is_resource($data) && get_resource_type($data) == "stream") {
$this->addLargeFile($data, $filePath, $timestamp, $fileComment, $extFileAttr);
return FALSE;
}
$gzData = "";
$gzType = "\x08\x00"; // Compression type 8 = deflate
$gpFlags = "\x00\x00"; // General Purpose bit flags for compression type 8 it is: 0=Normal, 1=Maximum, 2=Fast, 3=super fast compression.
$dataLength = strlen($data);
$fileCRC32 = pack("V", crc32($data));
if ($compress) {
$gzTmp = gzcompress($data);
$gzData = substr(substr($gzTmp, 0, strlen($gzTmp) - 4), 2); // gzcompress adds a 2 byte header and 4 byte CRC we can't use.
// 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.
$gzLength = strlen($gzData);
} else {
$gzLength = $dataLength;
}
if ($gzLength >= $dataLength) {
$gzLength = $dataLength;
$gzData = $data;
$gzType = "\x00\x00"; // Compression type 0 = stored
$gpFlags = "\x00\x00"; // Compression type 0 = stored
}
if (!is_resource($this->zipFile) && ($this->offset + $gzLength) > $this->zipMemoryThreshold) {
$this->zipflush();
}
$this->buildZipEntry($filePath, $fileComment, $gpFlags, $gzType, $timestamp, $fileCRC32, $gzLength, $dataLength, $extFileAttr);
$this->zipwrite($gzData);
return TRUE;
}
/**
* Add the content to a directory.
*
* @author Adam Schmalhofer <Adam.Schmalhofer@gmx.de>
* @author A. Grandt
*
* @param string $realPath Path on the file system.
* @param string $zipPath Filepath and name to be used in the archive.
* @param bool $recursive Add content recursively, default is TRUE.
* @param bool $followSymlinks Follow and add symbolic links, if they are accessible, default is TRUE.
* @param array &$addedFiles Reference to the added files, this is used to prevent duplicates, efault is an empty array.
* If you start the function by parsing an array, the array will be populated with the realPath
* and zipPath kay/value pairs added to the archive by the function.
* @param bool $overrideFilePermissions Force the use of the file/dir permissions set in the $extDirAttr
* and $extFileAttr parameters.
* @param int $extDirAttr Permissions for directories.
* @param int $extFileAttr Permissions for files.
*/
public function addDirectoryContent($realPath, $zipPath, $recursive = TRUE, $followSymlinks = TRUE, &$addedFiles = array(),
$overrideFilePermissions = FALSE, $extDirAttr = self::EXT_FILE_ATTR_DIR, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
if (file_exists($realPath) && !isset($addedFiles[realpath($realPath)])) {
if (is_dir($realPath)) {
if ($overrideFilePermissions) {
$this->addDirectory($zipPath, 0, null, $extDirAttr);
} else {
$this->addDirectory($zipPath, 0, null, self::getFileExtAttr($realPath));
}
}
$addedFiles[realpath($realPath)] = $zipPath;
$iter = new DirectoryIterator($realPath);
foreach ($iter as $file) {
if ($file->isDot()) {
continue;
}
$newRealPath = $file->getPathname();
$newZipPath = self::pathJoin($zipPath, $file->getFilename());
if (file_exists($newRealPath) && ($followSymlinks === TRUE || !is_link($newRealPath))) {
if ($file->isFile()) {
$addedFiles[realpath($newRealPath)] = $newZipPath;
if ($overrideFilePermissions) {
$this->addLargeFile($newRealPath, $newZipPath, 0, null, $extFileAttr);
} else {
$this->addLargeFile($newRealPath, $newZipPath, 0, null, self::getFileExtAttr($newRealPath));
}
} else if ($recursive === TRUE) {
$this->addDirectoryContent($newRealPath, $newZipPath, $recursive, $followSymlinks, $addedFiles, $overrideFilePermissions, $extDirAttr, $extFileAttr);
} else {
if ($overrideFilePermissions) {
$this->addDirectory($zipPath, 0, null, $extDirAttr);
} else {
$this->addDirectory($zipPath, 0, null, self::getFileExtAttr($newRealPath));
}
}
}
}
}
}
/**
* Add a file to the archive at the specified location and file name.
*
* @param string $dataFile File name/path.
* @param string $filePath Filepath and name to be used in the archive.
* @param int $timestamp (Optional) Timestamp for the added file, if omitted or set to 0, the current time will be used.
* @param string $fileComment (Optional) Comment to be added to the archive for this file. To use fileComment, timestamp must be given.
* @param int $extFileAttr (Optional) The external file reference, use generateExtAttr to generate this.
* @return bool $success
*/
public function addLargeFile($dataFile, $filePath, $timestamp = 0, $fileComment = NULL, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
if ($this->isFinalized) {
return FALSE;
}
if (is_string($dataFile) && is_file($dataFile)) {
$this->processFile($dataFile, $filePath, $timestamp, $fileComment, $extFileAttr);
} else if (is_resource($dataFile) && get_resource_type($dataFile) == "stream") {
$fh = $dataFile;
$this->openStream($filePath, $timestamp, $fileComment, $extFileAttr);
while (!feof($fh)) {
$this->addStreamData(fread($fh, $this->streamChunkSize));
}
$this->closeStream($this->addExtraField);
}
return TRUE;
}
/**
* Create a stream to be used for large entries.
*
* @param string $filePath Filepath and name to be used in the archive.
* @param int $timestamp (Optional) Timestamp for the added file, if omitted or set to 0, the current time will be used.
* @param string $fileComment (Optional) Comment to be added to the archive for this file. To use fileComment, timestamp must be given.
* @param int $extFileAttr (Optional) The external file reference, use generateExtAttr to generate this.
* @return bool $success
*/
public function openStream($filePath, $timestamp = 0, $fileComment = null, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
if (!function_exists('sys_get_temp_dir')) {
die ("ERROR: Zip " . self::VERSION . " requires PHP version 5.2.1 or above if large files are used.");
}
if ($this->isFinalized) {
return FALSE;
}
$this->zipflush();
if (strlen($this->streamFilePath) > 0) {
$this->closeStream();
}
$this->streamFile = tempnam(sys_get_temp_dir(), 'Zip');
$this->streamData = fopen($this->streamFile, "wb");
$this->streamFilePath = $filePath;
$this->streamTimestamp = $timestamp;
$this->streamFileComment = $fileComment;
$this->streamFileLength = 0;
$this->streamExtFileAttr = $extFileAttr;
return TRUE;
}
/**
* Add data to the open stream.
*
* @param string $data
* @return mixed length in bytes added or FALSE if the archive is finalized or there are no open stream.
*/
public function addStreamData($data) {
if ($this->isFinalized || strlen($this->streamFilePath) == 0) {
return FALSE;
}
$length = fwrite($this->streamData, $data, strlen($data));
if ($length != strlen($data)) {
die ("<p>Length mismatch</p>\n");
}
$this->streamFileLength += $length;
return $length;
}
/**
* Close the current stream.
*
* @return bool $success
*/
public function closeStream() {
if ($this->isFinalized || strlen($this->streamFilePath) == 0) {
return FALSE;
}
fflush($this->streamData);
fclose($this->streamData);
$this->processFile($this->streamFile, $this->streamFilePath, $this->streamTimestamp, $this->streamFileComment, $this->streamExtFileAttr);
$this->streamData = null;
$this->streamFilePath = null;
$this->streamTimestamp = null;
$this->streamFileComment = null;
$this->streamFileLength = 0;
$this->streamExtFileAttr = null;
// Windows is a little slow at times, so a millisecond later, we can unlink this.
unlink($this->streamFile);
$this->streamFile = null;
return TRUE;
}
private function processFile($dataFile, $filePath, $timestamp = 0, $fileComment = null, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
if ($this->isFinalized) {
return FALSE;
}
$tempzip = tempnam(sys_get_temp_dir(), 'ZipStream');
$zip = new ZipArchive;
if ($zip->open($tempzip) === TRUE) {
$zip->addFile($dataFile, 'file');
$zip->close();
}
$file_handle = fopen($tempzip, "rb");
$stats = fstat($file_handle);
$eof = $stats['size']-72;
fseek($file_handle, 6);
$gpFlags = fread($file_handle, 2);
$gzType = fread($file_handle, 2);
fread($file_handle, 4);
$fileCRC32 = fread($file_handle, 4);
$v = unpack("Vval", fread($file_handle, 4));
$gzLength = $v['val'];
$v = unpack("Vval", fread($file_handle, 4));
$dataLength = $v['val'];
$this->buildZipEntry($filePath, $fileComment, $gpFlags, $gzType, $timestamp, $fileCRC32, $gzLength, $dataLength, $extFileAttr);
fseek($file_handle, 34);
$pos = 34;
while (!feof($file_handle) && $pos < $eof) {
$datalen = $this->streamChunkSize;
if ($pos + $this->streamChunkSize > $eof) {
$datalen = $eof-$pos;
}
$data = fread($file_handle, $datalen);
$pos += $datalen;
$this->zipwrite($data);
}
fclose($file_handle);
unlink($tempzip);
}
/**
* Close the archive.
* A closed archive can no longer have new files added to it.
*
* @return bool $success
*/
public function finalize() {
if (!$this->isFinalized) {
if (strlen($this->streamFilePath) > 0) {
$this->closeStream();
}
$cd = implode("", $this->cdRec);
$cdRecSize = pack("v", sizeof($this->cdRec));
$cdRec = $cd . self::ZIP_END_OF_CENTRAL_DIRECTORY
. $cdRecSize . $cdRecSize
. pack("VV", strlen($cd), $this->offset);
if (!empty($this->zipComment)) {
$cdRec .= pack("v", strlen($this->zipComment)) . $this->zipComment;
} else {
$cdRec .= "\x00\x00";
}
$this->zipwrite($cdRec);
$this->isFinalized = TRUE;
$this->cdRec = NULL;
return TRUE;
}
return FALSE;
}
/**
* Get the handle ressource for the archive zip file.
* If the zip haven't been finalized yet, this will cause it to become finalized
*
* @return zip file handle
*/
public function getZipFile() {
if (!$this->isFinalized) {
$this->finalize();
}
$this->zipflush();
rewind($this->zipFile);
return $this->zipFile;
}
/**
* Get the zip file contents
* If the zip haven't been finalized yet, this will cause it to become finalized
*
* @return zip data
*/
public function getZipData() {
if (!$this->isFinalized) {
$this->finalize();
}
if (!is_resource($this->zipFile)) {
return $this->zipData;
} else {
rewind($this->zipFile);
$filestat = fstat($this->zipFile);
return fread($this->zipFile, $filestat['size']);
}
}
/**
* Send the archive as a zip download
*
* @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.
* @param String $contentType Content mime type. Optional, defaults to "application/zip".
* @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.
* @param bool $inline Use Content-Disposition with "inline" instead of "attached". Optional, defaults to FALSE.
* @return bool $success
*/
function sendZip($fileName = null, $contentType = "application/zip", $utf8FileName = null, $inline = false) {
if (!$this->isFinalized) {
$this->finalize();
}
$headerFile = null;
$headerLine = null;
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>")) {
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>")) {
if (ini_get('zlib.output_compression')) {
ini_set('zlib.output_compression', 'Off');
}
header("Pragma: public");
header("Last-Modified: " . gmdate("D, d M Y H:i:s T"));
header("Expires: 0");
header("Accept-Ranges: bytes");
header("Connection: close");
header("Content-Type: " . $contentType);
$cd = "Content-Disposition: ";
if ($inline) {
$cd .= "inline";
} else{
$cd .= "attached";
}
if ($fileName) {
$cd .= '; filename="' . $fileName . '"';
}
if ($utf8FileName) {
$cd .= "; filename*=UTF-8''" . rawurlencode($utf8FileName);
}
header($cd);
header("Content-Length: ". $this->getArchiveSize());
if (!is_resource($this->zipFile)) {
echo $this->zipData;
} else {
rewind($this->zipFile);
while (!feof($this->zipFile)) {
echo fread($this->zipFile, $this->streamChunkSize);
}
}
}
return TRUE;
}
return FALSE;
}
/**
* Return the current size of the archive
*
* @return $size Size of the archive
*/
public function getArchiveSize() {
if (!is_resource($this->zipFile)) {
return strlen($this->zipData);
}
$filestat = fstat($this->zipFile);
return $filestat['size'];
}
/**
* Calculate the 2 byte dostime used in the zip entries.
*
* @param int $timestamp
* @return 2-byte encoded DOS Date
*/
private function getDosTime($timestamp = 0) {
$timestamp = (int)$timestamp;
$oldTZ = @date_default_timezone_get();
date_default_timezone_set('UTC');
$date = ($timestamp == 0 ? getdate() : getdate($timestamp));
date_default_timezone_set($oldTZ);
if ($date["year"] >= 1980) {
return pack("V", (($date["mday"] + ($date["mon"] << 5) + (($date["year"]-1980) << 9)) << 16) |
(($date["seconds"] >> 1) + ($date["minutes"] << 5) + ($date["hours"] << 11)));
}
return "\x00\x00\x00\x00";
}
/**
* Build the Zip file structures
*
* @param string $filePath
* @param string $fileComment
* @param string $gpFlags
* @param string $gzType
* @param int $timestamp
* @param string $fileCRC32
* @param int $gzLength
* @param int $dataLength
* @param int $extFileAttr Use self::EXT_FILE_ATTR_FILE for files, self::EXT_FILE_ATTR_DIR for Directories.
*/
private function buildZipEntry($filePath, $fileComment, $gpFlags, $gzType, $timestamp, $fileCRC32, $gzLength, $dataLength, $extFileAttr) {
$filePath = str_replace("\\", "/", $filePath);
$fileCommentLength = (empty($fileComment) ? 0 : strlen($fileComment));
$timestamp = (int)$timestamp;
$timestamp = ($timestamp == 0 ? time() : $timestamp);
$dosTime = $this->getDosTime($timestamp);
$tsPack = pack("V", $timestamp);
$ux = "\x75\x78\x0B\x00\x01\x04\xE8\x03\x00\x00\x04\x00\x00\x00\x00";
if (!isset($gpFlags) || strlen($gpFlags) != 2) {
$gpFlags = "\x00\x00";
}
$isFileUTF8 = mb_check_encoding($filePath, "UTF-8") && !mb_check_encoding($filePath, "ASCII");
$isCommentUTF8 = !empty($fileComment) && mb_check_encoding($fileComment, "UTF-8") && !mb_check_encoding($fileComment, "ASCII");
if ($isFileUTF8 || $isCommentUTF8) {
$flag = 0;
$gpFlagsV = unpack("vflags", $gpFlags);
if (isset($gpFlagsV['flags'])) {
$flag = $gpFlagsV['flags'];
}
$gpFlags = pack("v", $flag | (1 << 11));
}
$header = $gpFlags . $gzType . $dosTime. $fileCRC32
. pack("VVv", $gzLength, $dataLength, strlen($filePath)); // File name length
$zipEntry = self::ZIP_LOCAL_FILE_HEADER;
$zipEntry .= self::ATTR_VERSION_TO_EXTRACT;
$zipEntry .= $header;
$zipEntry .= pack("v", ($this->addExtraField ? 28 : 0)); // Extra field length
$zipEntry .= $filePath; // FileName
// Extra fields
if ($this->addExtraField) {
$zipEntry .= "\x55\x54\x09\x00\x03" . $tsPack . $tsPack . $ux;
}
$this->zipwrite($zipEntry);
$cdEntry = self::ZIP_CENTRAL_FILE_HEADER;
$cdEntry .= self::ATTR_MADE_BY_VERSION;
$cdEntry .= ($dataLength === 0 ? "\x0A\x00" : self::ATTR_VERSION_TO_EXTRACT);
$cdEntry .= $header;
$cdEntry .= pack("v", ($this->addExtraField ? 24 : 0)); // Extra field length
$cdEntry .= pack("v", $fileCommentLength); // File comment length
$cdEntry .= "\x00\x00"; // Disk number start
$cdEntry .= "\x00\x00"; // internal file attributes
$cdEntry .= pack("V", $extFileAttr); // External file attributes
$cdEntry .= pack("V", $this->offset); // Relative offset of local header
$cdEntry .= $filePath; // FileName
// Extra fields
if ($this->addExtraField) {
$cdEntry .= "\x55\x54\x05\x00\x03" . $tsPack . $ux;
}
if (!empty($fileComment)) {
$cdEntry .= $fileComment; // Comment
}
$this->cdRec[] = $cdEntry;
$this->offset += strlen($zipEntry) + $gzLength;
}
private function zipwrite($data) {
if (!is_resource($this->zipFile)) {
$this->zipData .= $data;
} else {
fwrite($this->zipFile, $data);
fflush($this->zipFile);
}
}
private function zipflush() {
if (!is_resource($this->zipFile)) {
$this->zipFile = tmpfile();
fwrite($this->zipFile, $this->zipData);
$this->zipData = NULL;
}
}
/**
* Join $file to $dir path, and clean up any excess slashes.
*
* @param string $dir
* @param string $file
*/
public static function pathJoin($dir, $file) {
if (empty($dir) || empty($file)) {
return self::getRelativePath($dir . $file);
}
return self::getRelativePath($dir . '/' . $file);
}
/**
* Clean up a path, removing any unnecessary elements such as /./, // or redundant ../ segments.
* If the path starts with a "/", it is deemed an absolute path and any /../ in the beginning is stripped off.
* The returned path will not end in a "/".
*
* Sometimes, when a path is generated from multiple fragments,
* you can get something like "../data/html/../images/image.jpeg"
* This will normalize that example path to "../data/images/image.jpeg"
*
* @param string $path The path to clean up
* @return string the clean path
*/
public static function getRelativePath($path) {
$path = preg_replace("#/+\.?/+#", "/", str_replace("\\", "/", $path));
$dirs = explode("/", rtrim(preg_replace('#^(?:\./)+#', '', $path), '/'));
$offset = 0;
$sub = 0;
$subOffset = 0;
$root = "";
if (empty($dirs[0])) {
$root = "/";
$dirs = array_splice($dirs, 1);
} else if (preg_match("#[A-Za-z]:#", $dirs[0])) {
$root = strtoupper($dirs[0]) . "/";
$dirs = array_splice($dirs, 1);
}
$newDirs = array();
foreach ($dirs as $dir) {
if ($dir !== "..") {
$subOffset--;
$newDirs[++$offset] = $dir;
} else {
$subOffset++;
if (--$offset < 0) {
$offset = 0;
if ($subOffset > $sub) {
$sub++;
}
}
}
}
if (empty($root)) {
$root = str_repeat("../", $sub);
}
return $root . implode("/", array_slice($newDirs, 0, $offset));
}
/**
* Create the file permissions for a file or directory, for use in the extFileAttr parameters.
*
* @param int $owner Unix permisions for owner (octal from 00 to 07)
* @param int $group Unix permisions for group (octal from 00 to 07)
* @param int $other Unix permisions for others (octal from 00 to 07)
* @param bool $isFile
* @return EXTRERNAL_REF field.
*/
public static function generateExtAttr($owner = 07, $group = 05, $other = 05, $isFile = true) {
$fp = $isFile ? self::S_IFREG : self::S_IFDIR;
$fp |= (($owner & 07) << 6) | (($group & 07) << 3) | ($other & 07);
return ($fp << 16) | ($isFile ? self::S_DOS_A : self::S_DOS_D);
}
/**
* Get the file permissions for a file or directory, for use in the extFileAttr parameters.
*
* @param string $filename
* @return external ref field, or FALSE if the file is not found.
*/
public static function getFileExtAttr($filename) {
if (file_exists($filename)) {
$fp = fileperms($filename) << 16;
return $fp | (is_dir($filename) ? self::S_DOS_D : self::S_DOS_A);
}
return FALSE;
}
}
?>

View File

@ -0,0 +1,31 @@
DrUUID RFC4122 library for PHP5
by J. King (http://jkingweb.ca/)
Licensed under MIT license
See http://jkingweb.ca/code/php/lib.uuid/
for documentation
Last revised 2010-02-15
Copyright (c) 2009 J. King
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,314 @@
<?php
/*
DrUUID RFC4122 library for PHP5
by J. King (http://jkingweb.ca/)
Licensed under MIT license
See http://jkingweb.ca/code/php/lib.uuid/
for documentation
Last revised 2010-02-15
*/
/*
Copyright (c) 2009 J. King
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
class UUID {
const MD5 = 3;
const SHA1 = 5;
const clearVer = 15; // 00001111 Clears all bits of version byte with AND
const clearVar = 63; // 00111111 Clears all relevant bits of variant byte with AND
const varRes = 224; // 11100000 Variant reserved for future use
const varMS = 192; // 11000000 Microsft GUID variant
const varRFC = 128; // 10000000 The RFC 4122 variant (this variant)
const varNCS = 0; // 00000000 The NCS compatibility variant
const version1 = 16; // 00010000
const version3 = 48; // 00110000
const version4 = 64; // 01000000
const version5 = 80; // 01010000
const interval = 0x01b21dd213814000; // Time (in 100ns steps) between the start of the UTC and Unix epochs
const nsDNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
const nsURL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';
const nsOID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8';
const nsX500 = '6ba7b814-9dad-11d1-80b4-00c04fd430c8';
protected static $randomFunc = 'randomTwister';
protected static $randomSource = NULL;
//instance properties
protected $bytes;
protected $hex;
protected $string;
protected $urn;
protected $version;
protected $variant;
protected $node;
protected $time;
public static function mint($ver = 1, $node = NULL, $ns = NULL) {
/* Create a new UUID based on provided data. */
switch((int) $ver) {
case 1:
return new self(self::mintTime($node));
case 2:
// Version 2 is not supported
throw new UUIDException("Version 2 is unsupported.");
case 3:
return new self(self::mintName(self::MD5, $node, $ns));
case 4:
return new self(self::mintRand());
case 5:
return new self(self::mintName(self::SHA1, $node, $ns));
default:
throw new UUIDException("Selected version is invalid or unsupported.");
}
}
public static function import($uuid) {
/* Import an existing UUID. */
return new self(self::makeBin($uuid, 16));
}
public static function compare($a, $b) {
/* Compares the binary representations of two UUIDs.
The comparison will return true if they are bit-exact,
or if neither is valid. */
if (self::makeBin($a, 16)==self::makeBin($b, 16)) {
return TRUE;
} else {
return FALSE;
}
}
public function __toString() {
return $this->string;
}
public function __get($var) {
switch($var) {
case "bytes":
return $this->bytes;
case "hex":
return bin2hex($this->bytes);
case "string":
return $this->__toString();
case "urn":
return "urn:uuid:".$this->__toString();
case "version":
return ord($this->bytes[6]) >> 4;
case "variant":
$byte = ord($this->bytes[8]);
if ($byte >= self::varRes) {
return 3;
}
if ($byte >= self::varMS) {
return 2;
}
if ($byte >= self::varRFC) {
return 1;
}
return 0;
case "node":
if (ord($this->bytes[6])>>4==1) {
return bin2hex(substr($this->bytes,10));
} else {
return NULL;
}
case "time":
if (ord($this->bytes[6])>>4==1) {
// Restore contiguous big-endian byte order
$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]);
// Clear version flag
$time[0] = "0";
// Do some reverse arithmetic to get a Unix timestamp
$time = (hexdec($time) - self::interval) / 10000000;
return $time;
} else {
return NULL;
}
default:
return NULL;
}
}
protected function __construct($uuid) {
if (strlen($uuid) != 16) {
throw new UUIDException("Input must be a 128-bit integer.");
}
$this->bytes = $uuid;
// Optimize the most common use
$this->string =
bin2hex(substr($uuid,0,4))."-".
bin2hex(substr($uuid,4,2))."-".
bin2hex(substr($uuid,6,2))."-".
bin2hex(substr($uuid,8,2))."-".
bin2hex(substr($uuid,10,6));
}
protected static function mintTime($node = NULL) {
/* Generates a Version 1 UUID.
These are derived from the time at which they were generated. */
// Get time since Gregorian calendar reform in 100ns intervals
// This is exceedingly difficult because of PHP's (and pack()'s)
// integer size limits.
// Note that this will never be more accurate than to the microsecond.
$time = microtime(1) * 10000000 + self::interval;
// Convert to a string representation
$time = sprintf("%F", $time);
preg_match("/^\d+/", $time, $time); //strip decimal point
// And now to a 64-bit binary representation
$time = base_convert($time[0], 10, 16);
$time = pack("H*", str_pad($time, 16, "0", STR_PAD_LEFT));
// Reorder bytes to their proper locations in the UUID
$uuid = $time[4].$time[5].$time[6].$time[7].$time[2].$time[3].$time[0].$time[1];
// Generate a random clock sequence
$uuid .= self::randomBytes(2);
// set variant
$uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
// set version
$uuid[6] = chr(ord($uuid[6]) & self::clearVer | self::version1);
// Set the final 'node' parameter, a MAC address
if ($node) {
$node = self::makeBin($node, 6);
}
if (!$node) {
// If no node was provided or if the node was invalid,
// generate a random MAC address and set the multicast bit
$node = self::randomBytes(6);
$node[0] = pack("C", ord($node[0]) | 1);
}
$uuid .= $node;
return $uuid;
}
protected static function mintRand() {
/* Generate a Version 4 UUID.
These are derived soly from random numbers. */
// generate random fields
$uuid = self::randomBytes(16);
// set variant
$uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
// set version
$uuid[6] = chr(ord($uuid[6]) & self::clearVer | self::version4);
return $uuid;
}
protected static function mintName($ver, $node, $ns) {
/* Generates a Version 3 or Version 5 UUID.
These are derived from a hash of a name and its namespace, in binary form. */
if (!$node) {
throw new UUIDException("A name-string is required for Version 3 or 5 UUIDs.");
}
// if the namespace UUID isn't binary, make it so
$ns = self::makeBin($ns, 16);
if (!$ns) {
throw new UUIDException("A binary namespace is required for Version 3 or 5 UUIDs.");
}
$uuid = null;
$version = self::version3;
switch($ver) {
case self::MD5:
$version = self::version3;
$uuid = md5($ns.$node,1);
break;
case self::SHA1:
$version = self::version5;
$uuid = substr(sha1($ns.$node,1),0, 16);
break;
}
// set variant
$uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
// set version
$uuid[6] = chr(ord($uuid[6]) & self::clearVer | $version);
return ($uuid);
}
protected static function makeBin($str, $len) {
/* Insure that an input string is either binary or hexadecimal.
Returns binary representation, or false on failure. */
if ($str instanceof self) {
return $str->bytes;
}
if (strlen($str)==$len) {
return $str;
} else {
$str = preg_replace("/^urn:uuid:/is", "", $str); // strip URN scheme and namespace
}
$str = preg_replace("/[^a-f0-9]/is", "", $str); // strip non-hex characters
if (strlen($str) != ($len * 2)) {
return FALSE;
} else {
return pack("H*", $str);
}
}
public static function initRandom() {
/* Look for a system-provided source of randomness, which is usually crytographically secure.
/dev/urandom is tried first simply out of bias for Linux systems. */
if (is_readable('/dev/urandom')) {
self::$randomSource = fopen('/dev/urandom', 'rb');
self::$randomFunc = 'randomFRead';
}
else if (class_exists('COM', 0)) {
try {
self::$randomSource = new COM('CAPICOM.Utilities.1'); // See http://msdn.microsoft.com/en-us/library/aa388182(VS.85).aspx
self::$randomFunc = 'randomCOM';
}
catch(Exception $e) {
}
}
return self::$randomFunc;
}
public static function randomBytes($bytes) {
return call_user_func(array('self', self::$randomFunc), $bytes);
}
protected static function randomTwister($bytes) {
/* Get the specified number of random bytes, using mt_rand().
Randomness is returned as a string of bytes. */
$rand = "";
for ($a = 0; $a < $bytes; $a++) {
$rand .= chr(mt_rand(0, 255));
}
return $rand;
}
protected static function randomFRead($bytes) {
/* Get the specified number of random bytes using a file handle
previously opened with UUID::initRandom().
Randomness is returned as a string of bytes. */
return fread(self::$randomSource, $bytes);
}
protected static function randomCOM($bytes) {
/* Get the specified number of random bytes using Windows'
randomness source via a COM object previously created by UUID::initRandom().
Randomness is returned as a string of bytes. */
return base64_decode(self::$randomSource->GetRandom($bytes,0)); // straight binary mysteriously doesn't work, hence the base64
}
}
class UUIDException extends Exception {
}

View File

@ -1131,4 +1131,87 @@ class Poche
return new HTMLPurifier($config);
}
/**
* handle epub
*/
public function createEpub() {
if (isset($_GET['epub']) && isset($_GET['id'])) {
if ($_GET['id'] == "all") { // we put all entries in the file
$entries = $this->store->retrieveAll($this->user->getId());
}
else { // we put only one entry in the file
$entryID = filter_var($_GET['id'],FILTER_SANITIZE_NUMBER_INT);
$entry = $this->store->retrieveOneById($entryID, $this->user->getId());
$entries = array($entry);
}
}
$content_start =
"<?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"
. "<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\" />\n"
. "<title>Test Book</title>\n"
. "</head>\n"
. "<body>\n";
$bookEnd = "</body>\n</html>\n";
$log = new Logger($entryID, TRUE);
$fileDir = CACHE;
$book = new EPub();
$log->logLine("new EPub()");
$log->logLine("EPub class version: " . EPub::VERSION);
$log->logLine("EPub Req. Zip version: " . EPub::REQ_ZIP_VERSION);
$log->logLine("Zip version: " . Zip::VERSION);
$log->logLine("getCurrentServerURL: " . $book->getCurrentServerURL());
$log->logLine("getCurrentPageURL..: " . $book->getCurrentPageURL());
$book->setTitle("wallabag's articles");
$book->setIdentifier("http://$_SERVER[HTTP_HOST]", EPub::IDENTIFIER_URI); // Could also be the ISBN number, prefered for published books, or a UUID.
//$book->setLanguage("en"); // Not needed, but included for the example, Language is mandatory, but EPub defaults to "en". Use RFC3066 Language codes, such as "en", "da", "fr" etc.
$book->setDescription("Some articles saved on my wallabag");
$book->setAuthor("wallabag","wallabag");
$book->setPublisher("wallabag","wallabag"); // I hope this is a non existant address :)
$book->setDate(time()); // Strictly not needed as the book date defaults to time().
//$book->setRights("Copyright and licence information specific for the book."); // As this is generated, this _could_ contain the name or licence information of the user who purchased the book, if needed. If this is used that way, the identifier must also be made unique for the book.
$book->setSourceURL("http://$_SERVER[HTTP_HOST]");
$book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, "PHP");
$cssData = "body {\n margin-left: .5em;\n margin-right: .5em;\n text-align: justify;\n}\n\np {\n font-family: serif;\n font-size: 10pt;\n text-align: justify;\n text-indent: 1em;\n margin-top: 0px;\n margin-bottom: 1ex;\n}\n\nh1, h2 {\n font-family: sans-serif;\n font-style: italic;\n text-align: center;\n background-color: #6b879c;\n color: white;\n width: 100%;\n}\n\nh1 {\n margin-bottom: 2px;\n}\n\nh2 {\n margin-top: -2px;\n margin-bottom: 2px;\n}\n";
$cover = $content_start . "<h1>My articles on wallabag</h1>\n<h2>As seen on : http://$_SERVER[HTTP_HOST]</h2>\n" . $bookEnd;
$book->addChapter("Notices", "Cover.html", $cover);
$book->buildTOC(NULL, "toc", "Table of Contents", TRUE, TRUE);
foreach ($entries as $entry) {
$tags = $this->store->retrieveTagsByEntry($entry['id']);
foreach ($tags as $tag) {
$book->setSubject($tag);
}
$log->logLine("Set up parameters");
$chapter = $content_start . $entry['content'] . $bookEnd;
$book->addChapter("Chapter " . $entry['id'] . ": " . $entry['title'], htmlspecialchars($entry['title']) . ".html", $chapter, true, EPub::EXTERNAL_REF_ADD);
}
if (true) {
$epuplog = $book->getLog();
$book->addChapter("Log", "Log.html", $content_start . $log->getLog() . "\n</pre>" . $bookEnd); // generation log
// Only used in case we need to debug EPub.php.
//$book->addChapter("ePubLog", "ePubLog.html", $content_start . $epuplog . "\n</pre>" . $bookEnd);
}
$book->finalize();
$zipData = $book->sendBook("wallabag's articles");
}
}

View File

@ -31,6 +31,11 @@ require_once INCLUDES . '/3rdparty/FlattrItem.class.php';
require_once INCLUDES . '/3rdparty/htmlpurifier/HTMLPurifier.auto.php';
# epub library
require_once INCLUDES . '/3rdparty/libraries/PHPePub/Logger.php';
require_once INCLUDES . '/3rdparty/libraries/PHPePub/EPub.php';
require_once INCLUDES . '/3rdparty/libraries/PHPePub/EPubChapterSplitter.php';
# Composer its autoloader for automatically loading Twig
if (! file_exists(ROOT . '/vendor/autoload.php')) {
Poche::$canRenderTemplates = false;

View File

@ -70,6 +70,8 @@ if (isset($_GET['login'])) {
$poche->createNewUser();
} elseif (isset($_GET['deluser'])) {
$poche->deleteUser();
} elseif (isset($_GET['epub'])) {
$poche->createEpub();
} elseif (isset($_GET['import'])) {
$import = $poche->import();
$tpl_vars = array_merge($tpl_vars, $import);

View File

@ -125,6 +125,9 @@
<p><a href="?download" target="_blank">{% trans "Click here" %}</a> {% trans "to download your database." %}</p>{% endif %}
<p><a href="?export" target="_blank">{% trans "Click here" %}</a> {% trans "to export your wallabag data." %}</p>
<h2>Fancy a ebook ?</h2>
Click on <a href="./?epub&amp;id=all" title="Generate ePub">this link</a> to get all your articles in one ebook (ePub).
<h2>{% trans "Cache" %}</h2>
<p><a href="?empty-cache">{% trans "Click here" %}</a> {% trans "to delete cache." %}</p>

View File

@ -16,6 +16,7 @@
{% if constant('SHARE_SHAARLI') == 1 %}<li><a href="{{ constant('SHAARLI_URL') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|url_encode }}" target="_blank" class="tool shaarli" title="{% trans "shaarli" %}"><span>{% trans "shaarli" %}</span></a></li>{% endif %}
{% if constant('FLATTR') == 1 %}{% if flattr.status == constant('FLATTRABLE') %}<li><a href="http://flattr.com/submit/auto?url={{ entry.url }}" class="tool flattr icon icon-flattr" target="_blank" title="{% trans "flattr" %}"><span>{% trans "flattr" %}</span></a></li>{% elseif flattr.status == constant('FLATTRED') %}<li><a href="{{ flattr.flattrItemURL }}" class="tool flattr icon icon-flattr" target="_blank" title="{% trans "flattr" %}"><span>{% trans "flattr" %}</span> ({{ flattr.numflattrs }})</a></li>{% endif %}{% endif %}
{% if constant('SHOW_PRINTLINK') == 1 %}<li><a title="{% trans "Print" %}" class="tool icon icon-print" href="javascript: window.print();"><span>{% trans "Print" %}</span></a></li>{% endif %}
<li><a href="./?epub&amp;id={{ entry.id|e }}" title="Generate epub file">EPUB</a></li>
<li><a href="mailto:hello@wallabag.org?subject=Wrong%20display%20in%20wallabag&amp;body={{ entry.url|url_encode }}" title="{% trans "Does this article appear wrong?" %}" class="tool bad-display icon icon-delete"><span>{% trans "Does this article appear wrong?" %}</span></a></li>
</ul>
</div>