First commit

This commit is contained in:
Theodotos Andreou 2018-01-14 13:10:16 +00:00
commit c6e2478c40
13918 changed files with 2303184 additions and 0 deletions

View file

@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit5cdee2268f29abd76073fe42de4e8d15::getLoader();

View file

@ -0,0 +1,3 @@
*~
vendor/
tmp/

View file

@ -0,0 +1,19 @@
Copyright (c) 2015 CiviCRM LLC
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,149 @@
Civi\Cxn\Rpc
------------
Civi\Cxn\Rpc implements an RPC mechanism based on X.509 and JSON.
Generally, it is based on an asymmetric business relationship between three
parties:
* "Sites" are online properties owned by end-user organizations. They
represent an organization's canonical data-store. There are many sites.
In the tests and comments, we will refer to an example site
called `SaveTheWhales.org`.
* "Applications" are online properties with value-added services. They
supplement the sites. There are only a few applications, and they must
be certified to go live. In the tests and comments, we will refer to an
example service called `AddressCleanup.com`.
* An arbiter ("Directory Service" and "Certificate Authority") which
publishes and certifies a list of available applications. In the
comments, we will refer to a service called `cxn.civicrm.org`.
There is no pre-existing trust between sites and applications, and no
data-exchange can be established until a site opts-in by registering with an
application. The arbiter facilitates registration (by advertising and
certifying the application's public-key) and revocation (by revoking the
application's public-key) but cannot participate in any other
data-exchanges.
Test suite
----------
The test suite for `civicrm-cxn-rpc` is implemented in PHPUnit. It is
generallly executed with PHPUnit 4, e.g.
```
git clone https://github.com/civicrm/civicrm-cxn-rpc
cd civicrm-cxn-rpc
composer install
phpunit4
```
Protocol v0.2
-------------
CiviConnect Protocol v0.2 defines the major use-cases and message-exchanges among sites, applications, and arbiters. The use-cases are:
* _Registration Use-Case_: A site (`SaveTheWhales.org`) creates a new connection to an application (`AddressCleanup.com`) by POSTing a `RegistrationMessage`. `AddressCleanup.com` responds with a `StdMessage`.
* _CiviCRM API Use-Case_: An application (`AddressCleanup.com`) reads or writes records on a CiviCRM site (`SaveTheWhales.org`) by POSTing a `StdMessage`. `SaveTheWhales.org` responds with a `StdMessage`.
* _Service Discovery Use-Case_: A site (`SaveTheWhales.org`) gets a list of available applications by sending a basic HTTP GET request to the arbiter's directory service (`https://cxn.civicrm.org/cxn/apps`). The arbiter responds with an `AppMetasMessage`.
The most important message types are:
* [`RegistrationMessage`](src/Message/RegistrationMessage.php) (`SaveTheWhales.org` => `AddressCleanup.com`)
* _Use-Case_: Registration Use-Case
* _Payload_: The registration includes a unique identifer for the connection, a shared secret, and a callback URL. (More discussion below.)
* Crypto: A temporary secret is generated and encrypted with the application's public key (RSA-2048). The payload is encrypted (AES-CBC), dated (ttl), and signed (HMAC-SHA256) using the secret. (See also: [AesHelper](src/AesHelper.php), StdMessage)
* Note: The registration *request* uses RegistrationMessage, but the *acknowledgement* uses StdMessage.
* [`StdMessage`](src/Message/StdMessage.php) (`AddressCleanup.com` => `SaveTheWhales.org`)
* _Use-Case_: Registration Use-Case, CiviCRM API Use-Case
* _Payload_: Varies
* _Payload (CiviCRM API Request)_: An entity+action+params tuple (as in Civi APIv3).
* _Crypto_: The shared-secret is used to generate an AES encryption key and HMAC signing key. The payload and ttl are encrypted with AES-CBC (256-bit), and the ciphertext is signed with HMAC-SHA256. (See also: [AesHelper](src/AesHelper.php)) The same scheme is used for requests and responses.
* _Note_: When an application POSTs a `StdMessage`, it includes a copy of the latest cert. It is validated by the recipient to ensure that the application is still trusted by the arbiter.
* [`AppMetasMessage`](src/Message/AppMetasMessage.php) (`cxn.civicrm.org` => `SaveTheWhales.org`)
* _Use-Case_: Service Discovery Use-Case
* _Payload_: The list of applications includes the title, description, registration URL, and X.509 certificate for each.
* _Crypto_: The payload and ttl are signed by `cxn.civicrm.org` (RSA, 2048-bit key) and transferred in plaintext.
Additionally, there are two non-substantive message types. They should *not* be used for major activity but may assist in advisory error-reports:
* [`InsecureMessage`](src/Message/InsecureMessage.php)
* _Use-Case_: A server (`RegistrationServer` or `ApiServer`) receives an incoming message but cannot authenticate or decrypt it. The server must respond with a NACK, but it lacks sufficient information to securely communicate it. It sends an `InsecureMessage`.
* _Payload_: An error message.
* _Crypto_: Unencrypted and unsigned.
* [`GarbledMessage`](src/Message/GarbledMessage.php)
* _Use-Case_: A client (`RegistrationClient` or `ApiClient`) receives a response but cannot decode it.
* (Ex: The server was buggy or badly configured, and PHP error messages were dumped into the ciphertext.)
* (Ex: A man-in-the-middle interfered with the message transmission.)
* _Payload_: Unknown
* _Crypto_: Unknown
Some considerations:
* Messages can be passed over HTTP, HTTPS, or any other medium. Passing messages over HTTPS is preferrable (because HTTPS supports more sophisticated cryptography), but even with HTTP all interctions will be encrypted.
* Application certificates are validated using the CiviCRM CA. This seems better than trusting a hundred random CA's around the world -- there's one point of failure [rather than a hundred points of failure](http://googleonlinesecurity.blogspot.com/2015/03/maintaining-digital-certificate-security.html).
* If the CA were compromised and if an attacker could execute man-in-the-middle attacks against sites or applications, then it could compromise new connections. However, it cannot compromise existing connections because the CA lacks knowledge or means to manipulate the shared-secret.
* Sites do not need certificates. Only applications need certificates, and the number of applications is relatively small. Therefore, we don't need automated certificate enrollment. This significantly simplifies the technology and riskness of operating the CA.
Protocol v0.2: RegistrationMessage
----------------------------------
The `RegistrationMessage` format is used whenever a site (`SaveTheWhales.org`) sends a message to an application (`AddressCleanup.com`). The most common case is to send a `Cxn.register` request.
The message data includes the following keys:
* `entity`: string. Currently, only "Cxn" is used.
* `action`: string.
* `cxn`: array. See `Cxn.php`.
* `params`: array. Varies depending on entity/action.
The following entity/actions are supported:
* `Cxn`.`register` (mandatory): Establish a new connection or update an existing connection.
* `cxn`: For updates, both `cxnId` and `secret` must match the previous registration.
* `params`: none
* Note: `RegistrationServer` provides a standard implementation.
* `Cxn`.`unregister` (mandatory): Destroy an existing connection.
* `cxn`: Both `cxnId` and `secret` must match the previous registration.
* `params`: none
* Note: `RegistrationServer` provides a standard implementation.
* `Cxn`.`getlink` (optional): Compose a link for an authenticated service.
* `cxn`: Both `cxnId` and `secret` must match the previous registration.
* `params`:
* `page`: string. The name of the page to load (e.g. "settings").
* Note: Applications have discretion to define links in AppMeta. *If* there are links in `AppMeta`, they will be resolved using `getlink`. To support this, one may extend `RegistrationServer` and define `function onCxnGetlink(...)`.
Protocol v0.1
-------------
Never published or completed. Broadly, the v0.1 protocol relied on certificates for both client and server, and used RSA to encrypt all messages. v0.1 had a few issues:
* If the certificate authority were compromised, then the high trust placed in the CA could be abused to compromise existing connections.
* Using RSA for everything meant that the crypto was slower for typical API calls.
Base Classes
------------
When creating a new agent, one should use one of these four helper classes:
* RegistrationClient: A site uses this to establish a connection to a
an application.
* RegistrationServer: An application uses this to accept registrations
from sites.
* ApiClient: An application uses this to send API calls to the site.
* ApiServer: A site uses this to accept API calls from an application.
Policy Recommendations
----------------------
* Applications should accept new registrations. If a registration is
attempted with an existing cxnId, then use the shared-secret as
client authentication -- if the shared-secret matches, then
accept the updated registration; otherwise, reject it.
* Applications should periodically validate their connections --
i.e. issue an API call for "System.get" to ensure that the
connection corresponds to an active Civi installation running
a compatible version.
* Applications should be deployed on HTTPS to provide additional
security (e.g. forward-secrecy). However, this could impact
compatibility/reach, and the protocol encrypts all messages
regardless, so HTTP may still be used.

View file

@ -0,0 +1,33 @@
-----BEGIN CERTIFICATE-----
MIIFxjCCA66gAwIBAgIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzET
MBEGA1UECBMKQ2FsaWZvcm5pYTEQMA4GA1UEChMHQ2l2aUNSTTEYMBYGA1UEAxMP
Q2l2aUNSTSBSb290IENBMB4XDTE1MDcwMTAwMDAwMFoXDTMwMDYzMDIzNTk1OVow
TjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEDAOBgNVBAoTB0Np
dmlDUk0xGDAWBgNVBAMTD0NpdmlDUk0gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB
BQADggIPADCCAgoCggIBALXbD3H0BUHGVouoncNE1aXVowDMlLqOJtogSiheUWHv
aZDwd/rApVMTlqEqlc7cGeGwMS+0pT5xAtvIneLf01IKg768f85CXcGlhSImCpIV
PSLhi8Yadpl93YEesgGhstXgsDdYghI59tp57VAjcjFoOje8WqrnBrzaHMbuzM9n
cXIh7fN3XQ9tEdNNHzMbLs+sjWZkHU1p85wl9T0IZQHvoxxX6x2QXuHDHSPtKWsr
sFzvRrmXsAHu41NxIoV+VVuDz1jImKKoIfiE5GOWgwq6qhjyxY3EOrEM7Hi9MXxJ
HUnZ1JEV1Er9QT3wqE5kq8MKYdwKcx07je4UExA7d+g810/rgH3sYIRhKvOhz6ic
ifWkCtRb4MZ8yxOACCT1bNY0y2EfnNcZToTkpQEXX257YgdrWChTa6ot8g70KzR6
9MmFR97jamhm7xIAjV+je+lvLh26Z/qHVYwOY2tOpw38sxWYThuLIRJZvys8esp2
J5JS0sgK4veynUCiCaONgeVOqfc3joRsjskxrgM2fnwzNSkKA1nvb/fHY4LOgXIP
esr0xvBepUfGqruPV3q5YGDovPP2ETQu5bCatWXBGslpjwcF2QC1QXxbDdxoy6n8
sVAmHv+35VUTQmm/10QKKVjJtbvOGQ33hd2gTdnQPAJh6xaJ1BywIPV/5LLdBKqR
AgMBAAGjga4wgaswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUZLHj9SwJ2eBb
ThQ5wyWwbV/kSX4wCwYDVR0PBAQDAgEGMDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6
Ly9jYS5jaXZpY3JtLm9yZy9jYS9DaXZpUm9vdENBLmNybDAfBgNVHSMEGDAWgBRk
seP1LAnZ4FtOFDnDJbBtX+RJfjARBglghkgBhvhCAQEEBAMCAAcwDQYJKoZIhvcN
AQELBQADggIBAAOyDmtIng9jKeiBPqLPs2guYIrXlHRy5/+jmSL6XgvI3tx+3nIo
VR1LfF690tlXP9yX3XbtqKUgxWxDtjdDLpmHbQ/l81rzBTb+1bedhd7U98FZtVm+
7rWN2qoyll0k+Kr8OO+oElZbkUIKsJSOk/sQTkwUSE+jjc7lVpCwL2xcdOPgcFUK
NoPN4TzplA2mvbfd04kzi6yi3VN997HcAK4VBEQTx8HTTje7Q0gjdL0qbboNZz4Q
mXxgI/Qr6IMaJaZ2ylx1yxYHBamrgi52FaKV21zpVHzub/9zd5N2sXNQeSPZG0uR
1GCMYRLEoNlxT/SHg/bwBRDtJhLYjUlDUYAePRyXJtqwCc93A3o5VttPv1WItfOU
Ht+jim+SWoHxcK+Z23ITJrdsm2H/cfEPx4P+jM+pHaJefr01BW0NQPzF/aswwUin
m4aUgeI+u6n6elcWPJNU+yUGeZ8fZV9pgX8/mk1Qy+UrFkgxunwJYp4lpgMwgW/7
x373/CrsK+LLrA7pS9uTjrbHyIL3M98hSVLTyV5uTGK/Oo2511TO/Izx5LCoeOhM
c4EMzVyZ9XWoRBGt9t6T/43Gwl2NcJIscwPzV21JqxIA05chIZY10mhxEuBBzZ6A
gZ+/1vctsedrFkBstk+GOe16zlUTznY/5yfzgLNeI1Cur7Nm1SSKE/sI
-----END CERTIFICATE-----

View file

@ -0,0 +1,33 @@
-----BEGIN CERTIFICATE-----
MIIFsDCCA5igAwIBAgIBATANBgkqhkiG9w0BAQsFADBBMQswCQYDVQQGEwJVUzET
MBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUQ2l2aUNSTSBUZXN0IFJvb3Qg
Q0EwHhcNMTUwNzAxMDAwMDAwWhcNMjUwNjMwMjM1OTU5WjBBMQswCQYDVQQGEwJV
UzETMBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUQ2l2aUNSTSBUZXN0IFJv
b3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDcF0Kc/e99OShe
A0BnGfRc5QNnrU+Y3jf5G4SiDzk3sXf/YkYWJBA7VhE12rmdg7nwKm9uJlOpkSsx
MBE8mhs8Fq4q1b8nR2cGg6ZARSZiqQ9kJqK2tL9e1mBg4UVVvEj4DGTDWs7s5IoE
6Ej46is8OxxxTCuLW67htLjMjOnox2SwRNuBcqj75KCVyHmMktxVXI52PZMdk2/u
PoihLIeCn3fMzovhwj3PIZvbaAbHHAOkjxSU4dmmrcdnrdS0MtnBawAGEsSukYjP
2lPPmxgTLwsYSOCQ+DsKmAbpaXzQjaLxuLvyREnBmFAJj+4vYwEDo8FmPMzZrp2H
OYuM8zbNmuOKDEs8xe2DmVWRKk+ZS7lUus1J1xUZAJB1yzWMAelhQos9JEyjpC0l
ffhJ3zNx3CJ5mfxuQH/Gswt3nUOMPN7Ci+2EgfMgPbeEudR2myLhMpI98Em7KrPW
0TzRRe9kFjQUAG4iOWKggsYujt8elyO+PUKuWcFOkQek1Wufp10ItkiuCfcJKuk8
RzsJYX2z8HgfGtynBhrzzLkMPif5cXO/51wcTSNS+ng3KUZpfteHHO/7w1igl9AV
9HkZkjEgUAQTSBA+hPz4asboK8nvNl6c6F5vQTv3NL5ch5FT0XEG3Thi8Txs4Z3F
GR0XZFJcdSxF4GCbAzlZ3QlZN3oS8QIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMB
Af8wHQYDVR0OBBYEFAa+Lx14CEQsGhCrrk47Zt4nqDd+MAsGA1UdDwQEAwIBBjA8
BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY2EuY2l2aWNybS5vcmcvY2EvQ2l2aVRl
c3RSb290Q0EuY3JsMB8GA1UdIwQYMBaAFAa+Lx14CEQsGhCrrk47Zt4nqDd+MBEG
CWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQsFAAOCAgEAxvcfWHIwcnG750xq
glrWZgM4DMUmS8JjsZVNC+2zPkxPHTIFHHYYkuc2KDvJ8+h187yopOY5ecG9wYvH
6rudE+dH8AHE9GNbm2KJZ/t2z7yLWPwDvgcZGaRGiF3KsSmcrkEgC8HKbREo+WA3
yqxZwPD17B+wI0oATMVROFUYuCKKfAM/JkMFI2ECNmDYb6dLSqbcYGVSmXnyRbtz
UDmCff2w3DnAX0IvJ/bK/T8BC3Ftcf3ZDjkdiLBsquVjs89KT3SuOZVU4nSqWGqn
YkWGAwjd3iSjTx8oK393xAGSu4jgkPBjBCsaF1PWhGeEZ5xvyCpmYPqLhyYvOseQ
sCGPP5O/WCcDRkvDG1XnPsrUY/Yv9yQbyQHf6WaW92hEF4tTjJIU22ejkMzrjSBK
lqQniPAuuH8+5IBbkUbIiWG4U18c3rMp4n7K7dwNQRO6lUDmcCGAbUDL6WNY6vsd
zTNjSs72HhlMQOigjDmBJtVDDR7DBOA+EW1bYPV9ueGmj1GDh+7n5a2ZYftLZr4R
ySc+0PPEyBKzfDJGRojz582LkwXNL9Z551Kync4xiL68uuTZD+A7vJ3nQxYe6KXp
jt3RlHF4mkzWkNtGkx2ifNpbpML7tUrA8jnT1FzWywCtfBQHHSYoLBYyR/irmTg3
lSUXpaQSjP9ZxKeYGD7/P8t05gM=
-----END CERTIFICATE-----

View file

@ -0,0 +1,20 @@
{
"name": "civicrm/civicrm-cxn-rpc",
"description": "RPC library for CiviConnect",
"require": {
"psr/log": "~1.0.0",
"phpseclib/phpseclib": "1.0.*"
},
"autoload": {
"psr-4": {
"Civi\\Cxn\\Rpc\\": "src/"
}
},
"license": "MIT",
"authors": [
{
"name": "Tim Otten",
"email": "totten@civicrm.org"
}
]
}

View file

@ -0,0 +1,165 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "d0cb85a1f55862bb2db7fef988047ab7",
"content-hash": "50ac931d54e4bfd7179fa5d9c1b8cb14",
"packages": [
{
"name": "phpseclib/phpseclib",
"version": "1.0.7",
"source": {
"type": "git",
"url": "https://github.com/phpseclib/phpseclib.git",
"reference": "0bb6c9b974cada100cad40f72ef186a199274f9b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/0bb6c9b974cada100cad40f72ef186a199274f9b",
"reference": "0bb6c9b974cada100cad40f72ef186a199274f9b",
"shasum": ""
},
"require": {
"php": ">=5.0.0"
},
"require-dev": {
"phing/phing": "~2.7",
"phpunit/phpunit": "~4.0",
"sami/sami": "~2.0",
"squizlabs/php_codesniffer": "~2.0"
},
"suggest": {
"ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
"ext-mcrypt": "Install the Mcrypt extension in order to speed up a wide variety of cryptographic operations.",
"pear-pear/PHP_Compat": "Install PHP_Compat to get phpseclib working on PHP < 5.0.0."
},
"type": "library",
"autoload": {
"psr-0": {
"Crypt": "phpseclib/",
"File": "phpseclib/",
"Math": "phpseclib/",
"Net": "phpseclib/",
"System": "phpseclib/"
},
"files": [
"phpseclib/bootstrap.php",
"phpseclib/Crypt/Random.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
"phpseclib/"
],
"license": [
"MIT"
],
"authors": [
{
"name": "Jim Wigginton",
"email": "terrafrost@php.net",
"role": "Lead Developer"
},
{
"name": "Patrick Monnerat",
"email": "pm@datasphere.ch",
"role": "Developer"
},
{
"name": "Andreas Fischer",
"email": "bantu@phpbb.com",
"role": "Developer"
},
{
"name": "Hans-Jürgen Petrich",
"email": "petrich@tronic-media.com",
"role": "Developer"
},
{
"name": "Graham Campbell",
"email": "graham@alt-three.com",
"role": "Developer"
}
],
"description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
"homepage": "http://phpseclib.sourceforge.net",
"keywords": [
"BigInteger",
"aes",
"asn.1",
"asn1",
"blowfish",
"crypto",
"cryptography",
"encryption",
"rsa",
"security",
"sftp",
"signature",
"signing",
"ssh",
"twofish",
"x.509",
"x509"
],
"time": "2017-06-05 06:30:30"
},
{
"name": "psr/log",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"time": "2016-10-10 12:19:37"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": []
}

View file

@ -0,0 +1,23 @@
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="tests/bootstrap.php"
>
<testsuites>
<testsuite name="Cxn RPC Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>

View file

@ -0,0 +1,152 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\Exception\InvalidMessageException;
class AesHelper {
/**
* @return string
* A secret, expressed in a series of printable ASCII characters.
*/
public static function createSecret() {
return base64_encode(crypt_random_string(Constants::AES_BYTES));
}
/**
* @param $secret
* A secret, expressed in a series of printable ASCII characters.
* @return array
* - enc: string, raw encryption key
* - auth: string, raw authentication key
*/
public static function deriveAesKeys($secret) {
$rawSecret = base64_decode($secret);
if (Constants::AES_BYTES != strlen($rawSecret)) {
throw new InvalidMessageException("Failed to derive keys from secret.");
}
$result = array(
'enc' => BinHex::hex2bin(hash_hmac('sha256', 'dearbrutus', $rawSecret)),
'auth' => BinHex::hex2bin(hash_hmac('sha256', 'thefaultisinourselves', $rawSecret)),
);
if (Constants::AES_BYTES != strlen($result['enc']) || Constants::AES_BYTES != strlen($result['auth'])) {
throw new InvalidMessageException("Failed to derive keys from secret.");
}
return $result;
}
/**
* Encrypt $plaintext with $secret, then date and sign the message.
*
* @param string $secret
* @param string $plaintext
* @return array
* Array(string $body, string $signature).
* Note that $body begins with an unencrypted envelope (ttl, iv).
* @throws InvalidMessageException
*/
public static function encryptThenSign($secret, $plaintext) {
$iv = crypt_random_string(Constants::AES_BYTES);
$keys = AesHelper::deriveAesKeys($secret);
$cipher = new \Crypt_AES(CRYPT_AES_MODE_CBC);
$cipher->setKeyLength(Constants::AES_BYTES);
$cipher->setKey($keys['enc']);
$cipher->setIV($iv);
// JSON string; this will be signed but not encrypted
$jsonEnvelope = json_encode(array(
'ttl' => Time::getTime() + Constants::REQUEST_TTL,
'iv' => BinHex::bin2hex($iv),
));
// JSON string; this will be signed and encrypted
$jsonEncrypted = $cipher->encrypt($plaintext);
$body = $jsonEnvelope . Constants::PROTOCOL_DELIM . $jsonEncrypted;
$signature = hash_hmac('sha256', $body, $keys['auth']);
return array($body, $signature);
}
/**
* Validate the signature and date of the message, then
* decrypt it.
*
* @param string $secret
* @param string $body
* @param string $signature
* @return string
* Plain text.
* @throws InvalidMessageException
*/
public static function authenticateThenDecrypt($secret, $body, $signature) {
$keys = self::deriveAesKeys($secret);
$localHmac = hash_hmac('sha256', $body, $keys['auth']);
if (!self::hash_compare($signature, $localHmac)) {
throw new InvalidMessageException("Incorrect hash");
}
list ($jsonEnvelope, $jsonEncrypted) = explode(Constants::PROTOCOL_DELIM, $body, 2);
if (strlen($jsonEnvelope) > Constants::MAX_ENVELOPE_BYTES) {
throw new InvalidMessageException("Oversized envelope");
}
$envelope = json_decode($jsonEnvelope, TRUE);
if (!$envelope) {
throw new InvalidMessageException("Malformed envelope");
}
if (!is_numeric($envelope['ttl']) || Time::getTime() > $envelope['ttl']) {
throw new InvalidMessageException("Invalid TTL");
}
if (!is_string($envelope['iv']) || strlen($envelope['iv']) !== Constants::AES_BYTES * 2 || !preg_match('/^[a-f0-9]+$/', $envelope['iv'])) {
// AES_BYTES (32) ==> bin2hex ==> 2 hex digits (4-bit) per byte (8-bit)
throw new InvalidMessageException("Malformed initialization vector");
}
$jsonPlaintext = UserError::adapt('Civi\Cxn\Rpc\Exception\InvalidMessageException', function () use ($jsonEncrypted, $envelope, $keys) {
$cipher = new \Crypt_AES(CRYPT_AES_MODE_CBC);
$cipher->setKeyLength(Constants::AES_BYTES);
$cipher->setKey($keys['enc']);
$cipher->setIV(BinHex::hex2bin($envelope['iv']));
return $cipher->decrypt($jsonEncrypted);
});
return $jsonPlaintext;
}
/**
* Comparison function which resists timing attacks.
*
* @param string $a
* @param string $b
* @return bool
*/
private static function hash_compare($a, $b) {
if (!is_string($a) || !is_string($b)) {
return FALSE;
}
$len = strlen($a);
if ($len !== strlen($b)) {
return FALSE;
}
$status = 0;
for ($i = 0; $i < $len; $i++) {
$status |= ord($a[$i]) ^ ord($b[$i]);
}
return $status === 0;
}
}

View file

@ -0,0 +1,202 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\Exception\InvalidMessageException;
use Civi\Cxn\Rpc\Message\AppMetasMessage;
use Civi\Cxn\Rpc\Message\GarbledMessage;
use Civi\Cxn\Rpc\Message\InsecureMessage;
use Civi\Cxn\Rpc\Message\RegistrationMessage;
use Civi\Cxn\Rpc\Message\StdMessage;
use Psr\Log\NullLogger;
class Agent {
/**
* @var AppStore\AppStoreInterface
*/
protected $appStore;
/**
* @var string
*/
protected $caCert;
/**
* @var CxnStore\CxnStoreInterface
*/
protected $cxnStore;
/**
* @var CertificateValidatorInterface
*/
protected $certValidator;
/**
* @var Http\HttpInterface
*/
protected $http;
/**
* @var \Psr\Log\LoggerInterface
*/
protected $log;
public function __construct($appStore, $cxnStore) {
$this->appStore = $appStore;
$this->cxnStore = $cxnStore;
$this->certValidator = new DefaultCertificateValidator();
$this->log = new NullLogger();
$this->http = new Http\PhpHttp();
}
/**
* @param array|string $formats
* @param string $blob
* @return Message
* @throws InvalidMessageException
*/
public function decode($formats, $blob) {
$formats = (array) $formats;
$prefixLen = 0;
foreach ($formats as $format) {
$prefixLen = max($prefixLen, strlen($format));
}
list($prefix) = explode(Constants::PROTOCOL_DELIM, substr($blob, 0, $prefixLen + 1));
if (!in_array($prefix, $formats)) {
if (in_array(GarbledMessage::NAME, $formats)) {
return GarbledMessage::decode($blob);
}
else {
throw new InvalidMessageException("Unexpected message type.");
}
}
switch ($prefix) {
case StdMessage::NAME:
return StdMessage::decode($this->cxnStore, $blob);
case InsecureMessage::NAME:
return InsecureMessage::decode($blob);
case RegistrationMessage::NAME:
return RegistrationMessage::decode($this->appStore, $blob);
case AppMetasMessage::NAME:
return AppMetasMessage::decode($this->certValidator, $blob);
default:
throw new InvalidMessageException("Unrecognized message type.");
}
}
/* ----- boilerplate ----- */
/**
* @return AppStore\AppStoreInterface
*/
public function getAppStore() {
return $this->appStore;
}
/**
* @param AppStore\AppStoreInterface $appStore
*/
public function setAppStore($appStore) {
$this->appStore = $appStore;
return $this;
}
/**
* @return CertificateValidatorInterface
*/
public function getCertValidator() {
return $this->certValidator;
}
/**
* @param CertificateValidatorInterface $certValidator
*/
public function setCertValidator($certValidator) {
$this->certValidator = $certValidator;
return $this;
}
/**
* @return CxnStore\CxnStoreInterface
*/
public function getCxnStore() {
return $this->cxnStore;
}
/**
* @param CxnStore\CxnStoreInterface $cxnStore
*/
public function setCxnStore($cxnStore) {
$this->cxnStore = $cxnStore;
return $this;
}
/**
* @return Http\HttpInterface
*/
public function getHttp() {
return $this->http;
}
/**
* @param Http\HttpInterface $http
*/
public function setHttp($http) {
$this->http = $http;
return $this;
}
/**
* @return \Psr\Log\LoggerInterface
*/
public function getLog() {
return $this->log;
}
/**
* @param \Psr\Log\LoggerInterface $log
*/
public function setLog($log) {
$this->log = $log;
return $this;
}
/**
* @param array $values
* @return array
*/
protected function createSuccess($values) {
return array(
'is_error' => 0,
'values' => $values,
);
}
/**
* @param string $message
* @return array
*/
protected function createError($message) {
return array(
'is_error' => 1,
'error_message' => $message,
);
}
}

View file

@ -0,0 +1,117 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\Exception\GarbledMessageException;
use Civi\Cxn\Rpc\Exception\InvalidMessageException;
use Civi\Cxn\Rpc\Http\ViaPortHttp;
use Civi\Cxn\Rpc\Message\GarbledMessage;
use Civi\Cxn\Rpc\Message\StdMessage;
class ApiClient extends Agent {
/**
* @var array
*/
protected $appMeta;
/**
* @var string
*/
protected $cxnId;
/**
* @param array $appMeta
* @param CxnStore\CxnStoreInterface $cxnStore
* @param string $cxnId
*/
public function __construct($appMeta, $cxnStore, $cxnId) {
parent::__construct(NULL, $cxnStore);
$this->appMeta = $appMeta;
$this->cxnId = $cxnId;
$this->http = new Http\PhpHttp();
}
/**
* Call a remote API.
*
* Protocol errors will be reported as exceptions.
*
* @param string $entity
* @param string $action
* @param array $params
* @throws GarbledMessageException
* @throws InvalidMessageException
* @return mixed
*/
public function call($entity, $action, $params = array()) {
$this->log->debug("Send API call: {entity}.{action} over {cxnId}", array(
'entity' => $entity,
'action' => $action,
'cxnId' => $this->cxnId,
));
$cxn = $this->cxnStore->getByCxnId($this->cxnId);
$req = new StdMessage($cxn['cxnId'], $cxn['secret'],
array($entity, $action, $params, $this->appMeta['appCert']));
$http = empty($cxn['viaPort']) ? $this->http : new ViaPortHttp($this->http, $cxn['viaPort']);
list($respHeaders, $respCiphertext, $respCode) = $http->send('POST', $cxn['siteUrl'], $req->encode(), array(
'Content-type' => Constants::MIME_TYPE,
));
$respMessage = $this->decode(array(StdMessage::NAME, GarbledMessage::NAME), $respCiphertext);
if ($respMessage instanceof GarbledMessage) {
throw new GarbledMessageException($respMessage);
}
elseif ($respMessage instanceof StdMessage) {
if ($respMessage->getCxnId() != $cxn['cxnId']) {
// Tsk, tsk, Mallory!
throw new InvalidMessageException('Received response from incorrect connection.');
}
return $respMessage->getData();
}
else {
throw new InvalidMessageException('Unrecognized message type.');
}
}
/**
* Call a remote API.
*
* This is the same as call(), except that it wraps the request in a try-catch
* block and converts any exceptions to array(is_error=>...) format.
*
* @param $entity
* @param $action
* @param array $params
* @return array|mixed
*/
public function callSafe($entity, $action, $params = array()) {
try {
return $this->call($entity, $action, $params);
}
catch (GarbledMessageException $e) {
return array(
'is_error' => 1,
'error_message' => "Client exception: " . $e->getMessage(),
'garbled_message' => substr($e->getGarbledMessage()->getData(), 0, 77),
);
}
catch (\Exception $e) {
return array(
'is_error' => 1,
'error_message' => "Client exception: " . $e->getMessage(),
'trace' => $e->getTraceAsString(),
);
}
}
}

View file

@ -0,0 +1,113 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\Exception\InvalidMessageException;
use Civi\Cxn\Rpc\Message\InsecureMessage;
use Civi\Cxn\Rpc\Message\StdMessage;
class ApiServer extends Agent {
/**
* @var callable
*/
protected $router;
/**
* @param CxnStore\CxnStoreInterface $cxnStore
*/
public function __construct($cxnStore, $router = NULL) {
parent::__construct(NULL, $cxnStore);
$this->router = $router;
}
/**
* Parse the ciphertext, process it, and return the response.
*
* FIXME Catch exceptions and return in a nice format.
*
* @param string $blob
* POST'ed ciphertext.
* @return Message
*/
public function handle($blob) {
try {
$reqMessage = $this->decode(StdMessage::NAME, $blob);
}
catch (InvalidMessageException $e) {
$this->log->debug('Received invalid message', array(
'exception' => $e,
));
$resp = new InsecureMessage(array(
'is_error' => 1,
'error_message' => 'Invalid message coding',
array(
$e->getMessage(),
$e->getTraceAsString(),
),
));
return $resp->setCode(400);
}
$cxn = $this->cxnStore->getByCxnId($reqMessage->getCxnId());
$validation = Cxn::getValidationMessages($cxn);
if (!empty($validation)) {
$this->log->error('Invalid cxn ({cxnId})', array(
'cxnId' => $reqMessage->getCxnId(),
'messages' => $validation,
));
// $cxn is not valid, so we can't encode it use it for encoding.
$resp = new InsecureMessage(array(
'is_error' => 1,
'error_message' => 'Invalid cxn details: ' . implode(', ', array_keys($validation)),
));
return $resp->setCode(400);
}
try {
list ($entity, $action, $params, $appCert) = $reqMessage->getData();
if ($this->certValidator) {
$this->certValidator->validateCert($appCert);
$appCertObj = X509Util::loadCert($appCert);
$cn = $appCertObj->getDNProp('CN');
if (count($cn) != 1 || $cn[0] !== $cxn['appId']) {
throw new InvalidMessageException('Invalid message: Submitted certificate does not matched expected appId');
}
}
$respData = call_user_func($this->router, $cxn, $entity, $action, $params);
$this->log->info('Processed API call ({entity}.{action})', array(
'entity' => $entity,
'action' => $action,
));
}
catch (\Exception $e) {
$this->log->error('Error executing API call', array(
'request' => $reqMessage->getData(),
'exception' => $e,
));
$respData = array(
'is_error' => 1,
'error_message' => $e->getMessage(),
);
}
return new StdMessage($reqMessage->getCxnId(), $cxn['secret'], $respData);
}
/**
* @param callable $router
*/
public function setRouter($router) {
$this->router = $router;
}
}

View file

@ -0,0 +1,86 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\Exception\CxnException;
class AppMeta {
/**
* @return string
*/
public static function createId() {
return 'app:' . BinHex::bin2hex(crypt_random_string(Constants::APP_ID_CHARS));
}
public static function validate($appMeta) {
$errors = self::getValidationMessages($appMeta);
if (!empty($errors)) {
throw new CxnException("Invalid AppMeta:" . implode(', ', array_keys($errors)));
}
}
/**
* @param array $appMeta
* @return array
* List of errors. Empty error if OK.
*/
public static function getValidationMessages($appMeta) {
$errors = array();
if (!is_array($appMeta)) {
$errors['appMeta'] = 'Not an array';
}
foreach (array('title', 'appCert', 'appId') as $key) {
if (empty($appMeta[$key])) {
$errors[$key] = 'Required field';
}
}
if (!self::validateAppId($appMeta['appId'])) {
$errors['appId'] = 'Malformed';
}
foreach (array('appUrl') as $key) {
if (empty($appMeta[$key])) {
$errors[$key] = 'Required field';
}
elseif (!filter_var($appMeta[$key], FILTER_VALIDATE_URL)) {
$errors[$key] = 'Malformed URL';
}
}
if (!isset($appMeta['perm']) || !is_array($appMeta['perm'])) {
$errors['perm'] = 'Missing permissions';
}
if (!isset($appMeta['perm']['api']) || !is_array($appMeta['perm']['api'])) {
$errors['perm-api'] = 'Missing permissions (API whitelist)';
}
if (!isset($appMeta['perm']['grant'])) {
$errors['perm-grant'] = 'Missing permissions (grants)';
}
return $errors;
}
/**
* @param string $appId
* @return bool
*/
public static function validateAppId($appId) {
return !empty($appId) && preg_match('/^app:[a-zA-Z0-9\.]+$/', $appId);
}
}

View file

@ -0,0 +1,58 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\AppStore;
use Civi\Cxn\Rpc\AppMeta;
interface AppStoreInterface {
/**
* @return array
* List of App IDs.
*/
public function getAppIds();
/**
* @param string $appId
* The application's globally unique ID.
* @return array
* The application metadata.
* @see AppMeta
*/
public function getAppMeta($appId);
/**
* @param string $appId
* The application's globally unique ID.
* @return string
* PEM-encoded.
*/
public function getPublicKey($appId);
/**
* @param string $appId
* The application's globally unique ID.
* @return string
* PEM-encoded.
*/
public function getPrivateKey($appId);
/**
* @param string $appId
* The application's globally unique ID.
* @return array
* Array with elements:
* - publickey: string, pem.
* - privatekey: string, pem
*/
public function getKeyPair($appId);
}

View file

@ -0,0 +1,85 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\AppStore;
use Civi\Cxn\Rpc\AppMeta;
class SingletonAppStore implements AppStoreInterface {
private $appId;
private $appMeta;
private $publicKey;
private $privateKey;
public function __construct($appId, $appMeta, $privateKey, $publicKey) {
AppMeta::validate($appMeta);
$this->appId = $appId;
$this->appMeta = $appMeta;
$this->privateKey = $privateKey;
$this->publicKey = $publicKey;
}
public function getAppIds() {
return array($this->appId);
}
public function getAppMeta($appId) {
if ($appId == $this->appId) {
return $this->appMeta;
}
else {
return NULL;
}
}
public function getPublicKey($appId) {
if ($appId == $this->appId) {
return $this->publicKey;
}
else {
return NULL;
}
}
public function getPrivateKey($appId) {
if ($appId == $this->appId) {
return $this->privateKey;
}
else {
return NULL;
}
}
/**
* @param string $appId
* The application's globally unique ID.
* @return array
* Array with elements:
* - publickey: string, pem.
* - privatekey: string, pem
*/
public function getKeyPair($appId) {
if ($appId == $this->appId) {
return array(
'publickey' => $this->getPublicKey($appId),
'privatekey' => $this->getPrivateKey($appId),
);
}
else {
return NULL;
}
}
}

View file

@ -0,0 +1,41 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
class BinHex {
private static $emulate = NULL;
public static function hex2bin($str) {
// http://php.net/hex2bin -- PHP 5.4+
if (self::$emulate === NULL) {
self::$emulate = !function_exists('hex2bin');
}
if (self::$emulate) {
$sbin = "";
$len = strlen($str);
for ($i = 0; $i < $len; $i += 2) {
$sbin .= pack("H*", substr($str, $i, 2));
}
return $sbin;
}
else {
return hex2bin($str);
}
}
public static function bin2hex($str) {
// http://php.net/bin2hex -- PHP 4+
return bin2hex($str);
}
}

View file

@ -0,0 +1,194 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\Exception\ExpiredCertException;
use Civi\Cxn\Rpc\Exception\InvalidCertException;
class CA {
/**
* @param array $keyPair
* Array with elements:
* - privatekey: string.
* - publickey: string.
* @param string $dn
* Distinguished name (e.g. "/O=TestOrg").
* @return string
* Certificate data.
*/
public static function create($keyPair, $dn) {
$privKey = new \Crypt_RSA();
$privKey->loadKey($keyPair['privatekey']);
$pubKey = new \Crypt_RSA();
$pubKey->loadKey($keyPair['publickey']);
$pubKey->setPublicKey();
$subject = new \File_X509();
$subject->setDN($dn);
$subject->setPublicKey($pubKey);
$issuer = new \File_X509();
$issuer->setPrivateKey($privKey);
$issuer->setDN($dn);
$x509 = new \File_X509();
$x509->makeCA();
$x509->setEndDate(date('c', strtotime(Constants::CA_DURATION, Time::getTime())));
$result = $x509->sign($issuer, $subject, Constants::CERT_SIGNATURE_ALGORITHM);
return $x509->saveX509($result);
}
/**
* @param string $file
* File path.
* @return array
* Array with elements:
* - privatekey: string.
* - publickey: string.
*/
public static function load($file) {
return file_get_contents($file);
}
/**
* @param string $file
* File path.
* @param string $cert
* Certificate data.
*/
public static function save($file, $cert) {
file_put_contents($file, $cert);
}
/**
* Create a CSR for a CiviConnect application.
*
* @param array $keyPair
* Array with elements:
* - privatekey: string.
* - publickey: string.
* @param string $dn
* Distinguished name.
* @return string
* CSR data.
*/
public static function createAppCSR($keyPair, $dn) {
$privKey = new \Crypt_RSA();
$privKey->loadKey($keyPair['privatekey']);
$pubKey = new \Crypt_RSA();
$pubKey->loadKey($keyPair['publickey']);
$pubKey->setPublicKey();
$x509 = new \File_X509();
$x509->setPrivateKey($privKey);
$x509->setDN($dn);
$x509->loadCSR($x509->saveCSR($x509->signCSR(Constants::CERT_SIGNATURE_ALGORITHM)));
$x509->setExtension('id-ce-keyUsage', array('keyEncipherment'));
$csrData = $x509->signCSR(Constants::CERT_SIGNATURE_ALGORITHM);
return $x509->saveCSR($csrData);
}
/**
* Create a CSR for an authority that publishes a list of available
* applications.
*
* @param array $keyPair
* Array with elements:
* - privatekey: string.
* - publickey: string.
* @param string $dn
* Distinguished name.
* @return string
* CSR data.
*/
public static function createDirSvcCSR($keyPair, $dn) {
$privKey = new \Crypt_RSA();
$privKey->loadKey($keyPair['privatekey']);
$pubKey = new \Crypt_RSA();
$pubKey->loadKey($keyPair['publickey']);
$pubKey->setPublicKey();
$x509 = new \File_X509();
$x509->setPrivateKey($privKey);
$x509->setDN($dn);
$x509->loadCSR($x509->saveCSR($x509->signCSR(Constants::CERT_SIGNATURE_ALGORITHM)));
$x509->setExtension('id-ce-keyUsage', array('digitalSignature'));
$csrData = $x509->signCSR(Constants::CERT_SIGNATURE_ALGORITHM);
return $x509->saveCSR($csrData);
}
/**
* Create a CSR for an authority that can issue CRLs.
*
* @param array $keyPair
* @param string $dn
* @return string
* PEM-encoded CSR.
*/
public static function createCrlDistCSR($keyPair, $dn) {
$privKey = new \Crypt_RSA();
$privKey->loadKey($keyPair['privatekey']);
$pubKey = new \Crypt_RSA();
$pubKey->loadKey($keyPair['publickey']);
$pubKey->setPublicKey();
$csr = new \File_X509();
$csr->setPrivateKey($privKey);
$csr->setPublicKey($pubKey);
$csr->setDN($dn);
$csr->loadCSR($csr->saveCSR($csr->signCSR(Constants::CERT_SIGNATURE_ALGORITHM)));
$csr->setExtension('id-ce-keyUsage', array('cRLSign'));
$csrData = $csr->signCSR(Constants::CERT_SIGNATURE_ALGORITHM);
return $csr->saveCSR($csrData);
}
/**
* @param array $caKeyPair
* @param string $caCert
* PEM-encoded cert.
* @param string $csr
* PEM-encoded CSR.
* @param int $serialNumber
* @return string
* PEM-encoded cert.
*/
public static function signCSR($caKeyPair, $caCert, $csr, $serialNumber = 1) {
$privKey = new \Crypt_RSA();
$privKey->loadKey($caKeyPair['privatekey']);
$subject = new \File_X509();
$subject->loadCSR($csr);
$issuer = new \File_X509();
$issuer->loadX509($caCert);
$issuer->setPrivateKey($privKey);
$x509 = new \File_X509();
$x509->setSerialNumber($serialNumber, 10);
$x509->setEndDate(date('c', strtotime(Constants::APP_DURATION, Time::getTime())));
$result = $x509->sign($issuer, $subject, Constants::CERT_SIGNATURE_ALGORITHM);
return $x509->saveX509($result);
}
}

View file

@ -0,0 +1,35 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\Exception\InvalidCertException;
/**
* Interface CertificateValidatorInterface
* @package Civi\Cxn\Rpc
*
* A certificate validator determines whether a certificate is fully valid -- for whatever
* "valid" means in the system policy (eg signed by a trusted CA, not expired, not revoked).
*/
interface CertificateValidatorInterface {
/**
* Determine whether an X.509 certificate is currently valid.
*
* @param string $certPem
* PEM-encoded certificate.
* @throws InvalidCertException
* Invalid certificates are reported as exceptions.
*/
public function validateCert($certPem);
}

View file

@ -0,0 +1,87 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
/**
* Class Constants
*
* These values have been represented as constants for simplicity. At some point, it
* may be desirable to convert them to configuration options.
*
* @package Civi\Cxn\Rpc
*/
class Constants {
/**
* Number of seconds during which a signed request is considered valid.
*/
const REQUEST_TTL = 7200;
/**
* Number of characters in an agent ID.
*/
const APP_ID_CHARS = 16;
const RSA_ENC_MODE = CRYPT_RSA_ENCRYPTION_OAEP;
const RSA_HASH = 'sha256';
const RSA_SIG_MODE = CRYPT_RSA_SIGNATURE_PSS;
const RSA_KEYLEN = 2048;
// 2048 bits / 8 bits-per-byte = 256 bytes
const RSA_MSG_BYTES = 256;
const CERT_SIGNATURE_ALGORITHM = 'sha256WithRSAEncryption';
const MIME_TYPE = 'application/x-civi-cxn';
const PROTOCOL_DELIM = ""; // ^A, not visible in some editors
const CA_DURATION = '+10 years';
const APP_DURATION = '+1 year';
const AES_BYTES = 32; // 32 bytes = 256 bits
const CXN_ID_CHARS = 16;
// (TTL (10byte) + IV (32byte)) * leeway-for-json-inefficency (10x) =~ 512
const MAX_ENVELOPE_BYTES = 512;
/**
* We only trust metadata lists generated by cxn.civicrm.org. This implementation is a bit
* ham-handed, but it's simple. Ideally, we might have a special "usage" flag in the cert.
*/
const OFFICIAL_APPMETAS_CN = 'core:DirectoryService';
const OFFICIAL_APPMETAS_URL = 'https://cxn.civicrm.org/cxn/apps';
/**
* @return string
* The path to the PEM-encode X.509 certificate of the
* live CiviCRM Certificate Authority.
*/
public static function getCert() {
return dirname(__DIR__) . '/certs/CiviRootCA.crt';
}
/**
* @return string
* The path to the PEM-encode X.509 certificate of the
* test CiviCRM Certificate Authority.
*/
public static function getTestCert() {
return dirname(__DIR__) . '/certs/CiviTestRootCA.crt';
}
}

View file

@ -0,0 +1,75 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\Exception\CxnException;
use Civi\Cxn\Rpc\Http\ViaPortHttp;
class Cxn {
/**
* @return string
*/
public static function createId() {
return 'cxn:' . BinHex::bin2hex(crypt_random_string(Constants::CXN_ID_CHARS));
}
public static function validate($cxn) {
$errors = self::getValidationMessages($cxn);
if (!empty($errors)) {
throw new CxnException("Invalid Cxn: " . implode(', ', array_keys($errors)));
}
}
/**
* @param array $cxn
* @return array
* List of errors. Empty error if OK.
*/
public static function getValidationMessages($cxn) {
$errors = array();
if (!is_array($cxn)) {
$errors['appMeta'] = 'Not an array';
return $errors;
}
// cxnId is completely arbitrary.
// Secret is base64-encoded AES-256 key (32 bytes, ~45 base64 char).
foreach (array('cxnId', 'secret', 'appId') as $key) {
if (empty($cxn[$key])) {
$errors[$key] = 'Required field';
}
}
foreach (array('appUrl', 'siteUrl') as $key) {
if (empty($cxn[$key])) {
$errors[$key] = 'Required field';
}
elseif (!filter_var($cxn[$key], FILTER_VALIDATE_URL)) {
$errors[$key] = 'Malformed URL';
}
}
if (!isset($cxn['perm']) || !is_array($cxn['perm'])) {
$errors['perm'] = 'Missing permisisons';
}
// viaPort is optional. If specified, expect "ip:port" or "host:port"
if (!empty($cxn['viaPort']) && !ViaPortHttp::validate($cxn['viaPort'])) {
$errors['viaPort'] = 'Malformed proxy address';
}
return $errors;
}
}

View file

@ -0,0 +1,43 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\CxnStore;
class ArrayCxnStore implements CxnStoreInterface {
protected $cxns = array();
public function getAll() {
return $this->cxns;
}
public function getByCxnId($cxnId) {
return isset($this->cxns[$cxnId]) ? $this->cxns[$cxnId] : NULL;
}
public function getByAppId($appId) {
foreach ($this->cxns as $cxn) {
if ($appId == $cxn['appId']) {
return $cxn;
}
}
return NULL;
}
public function add($cxn) {
$this->cxns[$cxn['cxnId']] = $cxn;
}
public function remove($cxnId) {
unset($this->cxns[$cxnId]);
}
}

View file

@ -0,0 +1,52 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\CxnStore;
interface CxnStoreInterface {
/**
* Return a list of all Cxns.
*
* @return array
* Array(string $cxnId => array $cxn).
*/
public function getAll();
/**
* @param string $cxnId
* @return array|NULL
* Zero or one matching Cxn's (array-encoded).
* @see Cxn::validate
*/
public function getByCxnId($cxnId);
/**
* @param $appId
* @return array|NULL
* Zero or one matching Cxn's (array-encoded).
* @see Cxn::validate
*/
public function getByAppId($appId);
/**
* @param array $cxn
* An array-encoded Cxn.
* @see Cxn::validate
*/
public function add($cxn);
/**
* @param string $cxnId
*/
public function remove($cxnId);
}

View file

@ -0,0 +1,82 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\CxnStore;
/**
* Class JsonFileCxnStore
*
* This is a very simple implementation. DO NOT USE IN PRODUCTION. It is not multithread safe.
*
* @package Civi\Cxn\Rpc\CxnStore
*/
class JsonFileCxnStore implements CxnStoreInterface {
private $file;
private $cache;
public function __construct($file) {
$this->file = $file;
}
public function getCache() {
if (!$this->cache) {
$this->cache = $this->load();
}
return $this->cache;
}
public function getAll() {
return $this->getCache();
}
public function getByCxnId($cxnId) {
$cache = $this->getCache();
return isset($cache[$cxnId]) ? $cache[$cxnId] : NULL;
}
public function getByAppId($appId) {
$cache = $this->getCache();
foreach ($cache as $cxn) {
if ($cxn['appId'] == $appId) {
return $cxn;
}
}
return NULL;
}
public function add($cxn) {
$data = $this->load();
$data[$cxn['cxnId']] = $cxn;
$this->save($data);
}
public function remove($cxnId) {
$data = $this->load();
if (isset($data[$cxnId])) {
unset($data[$cxnId]);
$this->save($data);
}
}
/**
* @return mixed
*/
public function load() {
return json_decode(file_get_contents($this->file), TRUE);
}
public function save($data) {
file_put_contents($this->file, json_encode($data));
}
}

View file

@ -0,0 +1,287 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\Exception\ExpiredCertException;
use Civi\Cxn\Rpc\Exception\InvalidCertException;
use Civi\Cxn\Rpc\Http\HttpInterface;
use Civi\Cxn\Rpc\Http\PhpHttp;
/**
* Class DefaultCertificateValidator
* @package Civi\Cxn\Rpc
*
* The default certificate validator will:
* - Check that the certificate is signed by canonical CA.
* - Check that the certificate has not been revoked by the canonical CA
* (using the CRL URL of the CA).
*
* Validating the CRL requires issuing HTTP requests. To improve performance,
* consider replacing the default $http instance (PhpHttp) with something
* that supports caching.
*/
class DefaultCertificateValidator implements CertificateValidatorInterface {
/**
* Specify that content should be auto-loaded via HTTP.
*/
const AUTOLOAD = '*auto*';
/**
* @var string
* The CA certificate (PEM-encoded).
* Use DefaultCertificateValidator::AUTOLOAD to use the bundled CiviRootCA.
*/
protected $caCert;
/**
* @var string
* The URL for downloading the CRL.
* Use DefaultCertificateValidator::AUTOLOAD to extract from $caCert.
*/
protected $crlUrl = DefaultCertificateValidator::AUTOLOAD;
/**
* @var string
* The CRL data.
* Use DefaultCertificateValidator::AUTOLOAD to download via HTTP.
*/
protected $crl;
/**
* @var string
* The certificate which signs CRLs (PEM-encoded).
* Use DefaultCertificateValidator::AUTOLOAD to download via HTTP.
*/
protected $crlDistCert;
/**
* @var HttpInterface|string
* The service to use when autoloading data.
* Use DefaultCertificateValidator::AUTOLOAD to download via HTTP.
*/
protected $http;
/**
* @param string $caCertPem
* @param string $crlDistCertPem
* @param string $crlPem
* @param HttpInterface|string $http
*/
public function __construct(
$caCertPem = DefaultCertificateValidator::AUTOLOAD,
$crlDistCertPem = DefaultCertificateValidator::AUTOLOAD,
$crlPem = DefaultCertificateValidator::AUTOLOAD,
$http = DefaultCertificateValidator::AUTOLOAD) {
$this->caCert = $caCertPem;
$this->crlDistCert = $crlDistCertPem;
$this->crl = $crlPem;
$this->http = $http;
}
/**
* Determine whether an X.509 certificate is currently valid.
*
* @param string $certPem
* PEM-encoded certificate.
* @throws InvalidCertException
* Invalid certificates are reported as exceptions.
*/
public function validateCert($certPem) {
if ($this->getCaCert()) {
self::validate($certPem, $this->getCaCert(), $this->getCrl(), $this->getCrlDistCert());
}
}
protected static function validate($certPem, $caCertPem, $crlPem = NULL, $crlDistCertPem = NULL) {
$caCertObj = X509Util::loadCACert($caCertPem);
$certObj = new \File_X509();
$certObj->loadCA($caCertPem);
if ($crlPem !== NULL) {
$crlObj = new \File_X509();
if ($crlDistCertPem) {
$crlDistCertObj = X509Util::loadCrlDistCert($crlDistCertPem, NULL, $caCertPem);
if ($crlDistCertObj->getSubjectDN(FILE_X509_DN_STRING) !== $caCertObj->getSubjectDN(FILE_X509_DN_STRING)) {
throw new InvalidCertException(sprintf("CRL distributor (%s) does not act on behalf of this CA (%s)",
$crlDistCertObj->getSubjectDN(FILE_X509_DN_STRING),
$caCertObj->getSubjectDN(FILE_X509_DN_STRING)
));
}
try {
self::validate($crlDistCertPem, $caCertPem);
}
catch (InvalidCertException $ie) {
throw new InvalidCertException("CRL distributor has an invalid certificate", 0, $ie);
}
$crlObj->loadCA($crlDistCertPem);
}
$crlObj->loadCA($caCertPem);
$crlObj->loadCRL($crlPem);
if (!$crlObj->validateSignature()) {
throw new InvalidCertException("CRL signature is invalid");
}
}
$parsedCert = $certObj->loadX509($certPem);
if ($crlPem !== NULL) {
if (empty($parsedCert)) {
throw new InvalidCertException("Identity is invalid. Empty certificate.");
}
if (empty($parsedCert['tbsCertificate']['serialNumber'])) {
throw new InvalidCertException("Identity is invalid. No serial number.");
}
$revoked = $crlObj->getRevoked($parsedCert['tbsCertificate']['serialNumber']->toString());
if (!empty($revoked)) {
throw new InvalidCertException("Identity is invalid. Certificate revoked.");
}
}
if (!$certObj->validateSignature()) {
throw new InvalidCertException("Identity is invalid. Certificate is not signed by proper CA.");
}
if (!$certObj->validateDate(Time::getTime())) {
throw new ExpiredCertException("Identity is invalid. Certificate expired.");
}
}
/**
* @return string
*/
public function getCaCert() {
if ($this->caCert === self::AUTOLOAD) {
$this->caCert = file_get_contents(Constants::getCert());
}
return $this->caCert;
}
/**
* @param string $caCert
* @return $this
*/
public function setCaCert($caCert) {
$this->caCert = $caCert;
return $this;
}
/**
* Determine the CRL URL which corresponds to this CA.
*/
public function getCrlUrl() {
if ($this->crlUrl === self::AUTOLOAD) {
$this->crlUrl = NULL; // Default if we can't find something else.
$caCertObj = X509Util::loadCACert($this->getCaCert());
// There can be multiple DPs, but in practice CiviRootCA only has one.
$crlDPs = $caCertObj->getExtension('id-ce-cRLDistributionPoints');
if (is_array($crlDPs)) {
foreach ($crlDPs as $crlDP) {
foreach ($crlDP['distributionPoint']['fullName'] as $fullName) {
if (isset($fullName['uniformResourceIdentifier'])) {
$this->crlUrl = $fullName['uniformResourceIdentifier'];
break 2;
}
}
}
}
}
return $this->crlUrl;
}
/**
* @param string $crlUrl
* @return $this
*/
public function setCrlUrl($crlUrl) {
$this->crlUrl = $crlUrl;
return $this;
}
/**
* @return string
*/
public function getCrlDistCert() {
if ($this->crlDistCert === self::AUTOLOAD) {
if ($this->getCrlUrl()) {
$url = preg_replace('/\.crl/', '/dist.crt', $this->getCrlUrl());
list ($headers, $blob, $code) = $this->getHttp()->send('GET', $url, '');
if ($code != 200) {
throw new \RuntimeException("Certificate validation failed. Cannot load CRL distribution certificate: $url");
}
$this->crlDistCert = $blob;
}
else {
$this->crlDistCert = NULL;
}
}
return $this->crlDistCert;
}
/**
* @param string $crlDistCert
* @return $this
*/
public function setCrlDistCert($crlDistCert) {
$this->crlDistCert = $crlDistCert;
return $this;
}
/**
* @return string
*/
public function getCrl() {
if ($this->crl === self::AUTOLOAD) {
$url = $this->getCrlUrl();
if ($url) {
list ($headers, $blob, $code) = $this->getHttp()->send('GET', $url, '');
if ($code != 200) {
throw new \RuntimeException("Certificate validation failed. Cannot load CRL: $url");
}
$this->crl = $blob;
}
else {
$this->crl = NULL;
}
}
return $this->crl;
}
/**
* @param string $crl
* @return $this
*/
public function setCrl($crl) {
$this->crl = $crl;
return $this;
}
/**
* @return HttpInterface
*/
public function getHttp() {
if ($this->http === self::AUTOLOAD) {
$this->http = new PhpHttp();
}
return $this->http;
}
/**
* @param HttpInterface $http
* @return $this
*/
public function setHttp($http) {
$this->http = $http;
return $this;
}
}

View file

@ -0,0 +1,16 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Exception;
class CxnException extends \Exception {
}

View file

@ -0,0 +1,16 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Exception;
class ExpiredCertException extends InvalidCertException {
}

View file

@ -0,0 +1,39 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Exception;
use Civi\Cxn\Rpc\Message\GarbledMessage;
class GarbledMessageException extends InvalidMessageException {
private $garbledMessage;
/**
* @param GarbledMessage $garbledMessage
*/
public function __construct($garbledMessage) {
parent::__construct("Received garbled message");
$this->garbledMessage = $garbledMessage;
}
/**
* @return GarbledMessage
*/
public function getGarbledMessage() {
return $this->garbledMessage;
}
public function getData() {
return $this->garbledMessage->getData();
}
}

View file

@ -0,0 +1,16 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Exception;
class InvalidCertException extends CxnException {
}

View file

@ -0,0 +1,16 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Exception;
class InvalidMessageException extends CxnException {
}

View file

@ -0,0 +1,35 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Http;
class FakeHttp implements HttpInterface {
protected $callable;
public function __construct($callable) {
$this->callable = $callable;
}
/**
* @param string $verb
* @param string $url
* @param string $blob
* @param array $headers
* Array of headers (e.g. "Content-type" => "text/plain").
* @return array
* array($headers, $blob, $code)
*/
public function send($verb, $url, $blob, $headers = array()) {
return call_user_func($this->callable, $verb, $url, $blob, $headers);
}
}

View file

@ -0,0 +1,27 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Http;
interface HttpInterface {
/**
* @param string $verb
* @param string $url
* @param string $blob
* @param array $headers
* Array of headers (e.g. "Content-type" => "text/plain").
* @return array
* array($headers, $blob, $code)
*/
public function send($verb, $url, $blob, $headers = array());
}

View file

@ -0,0 +1,66 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Http;
class PhpHttp implements HttpInterface {
/**
* @param string $verb
* @param string $url
* @param string $blob
* @param array $headers
* Array of headers (e.g. "Content-type" => "text/plain").
* @return array
* array($headers, $blob, $code)
*/
public function send($verb, $url, $blob, $headers = array()) {
$opts = $this->createStreamOpts($verb, $url, $blob, $headers);
$context = stream_context_create($opts);
$respBlob = file_get_contents($url, FALSE, $context);
$code = NULL;
$headers = array();
foreach ($http_response_header as $line) {
if (preg_match('/^HTTP\/[0-9\.]+[^0-9]+([0-9]+)/', $line, $matches)) {
$code = $matches[1];
}
elseif (preg_match(';^([a-zA-Z0-9\-]+):[ \t](.*);', $line, $matches)) {
$headers[$matches[1]] = $matches[2];
}
}
return array($headers, $respBlob, $code);
}
/**
* @param $verb
* @param $blob
* @param $headers
* @return array
*/
protected function createStreamOpts($verb, $url, $blob, $headers) {
$opts = array(
'http' => array(
'method' => $verb,
'content' => $blob,
),
);
if (!empty($headers)) {
$encodedHeaders = '';
foreach ($headers as $k => $v) {
$encodedHeaders .= $k . ": " . $v . "\r\n";
}
$opts['http']['header'] = $encodedHeaders;
return $opts;
}
return $opts;
}
}

View file

@ -0,0 +1,160 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Http;
/**
* Class ViaPortHttp
* @package Civi\Cxn\Rpc\Http
*
* This decorator allows you to modify an existing HttpClient to redirect
* all requests through an alternate host/port. However, the HTTP request
* itself (the path and vhost) remain unchanged.
*
* @code
* $http = new ViaPortHttp(new PhpHttp(), 'proxy.example.com:1234');
* $http->send('http://example.net/');
* @endcode
*
* Terminology: Standard HTTP proxies support a header called "Via:", which
* is a different thing. This is just regular HTTP directed through an
* alternative host/port (as in "NAT with port-forwarding"). To keep it
* distinct, this functionality is referred to as "ViaPort".
*/
class ViaPortHttp implements HttpInterface {
/**
* @var \Civi\Cxn\Rpc\Http\HttpInterface
*/
private $http;
/**
* @var string
* Ex: "123.123.123.123:456".
* Ex: "proxy.example.com:789"
* Ex: "dhcp123.isp.example.net:456"
*/
private $viaPort;
/**
* ViaPortHttp constructor.
* @param string $viaPort
*/
public function __construct(HttpInterface $http, $viaPort) {
$this->http = $http;
$this->viaPort = $viaPort;
}
/**
* @param string $verb
* @param string $url
* @param string $blob
* @param array $headers
* Array of headers (e.g. "Content-type" => "text/plain").
* @return array
* array($headers, $blob, $code)
*/
public function send($verb, $url, $blob, $headers = array()) {
if ($this->getViaPort()) {
list($verb, $url, $blob, $headers) = $this->modifyRequest($verb, $url, $blob, $headers);
return $this->getHttp()->send($verb, $url, $blob, $headers);
}
else {
return $this->getHttp()->send($verb, $url, $blob, $headers);
}
}
/**
* @param string $url
* @return array
* Array($verb, $url, $blob, $headers)
*/
public function modifyRequest($verb, $url, $blob, $headers) {
$parsedUrl = parse_url($url);
list ($viaHost, $viaPort) = explode(':', $this->getViaPort());
$newUrl = $parsedUrl['scheme'] . '://' . $viaHost;
if ($viaPort) {
$newUrl .= ':' . $viaPort;
}
if (isset($parsedUrl['path'])) {
$newUrl .= $parsedUrl['path'];
}
if (isset($parsedUrl['query'])) {
$newUrl .= '?' . $parsedUrl['query'];
}
$headers['Host'] = $parsedUrl['host'];
return array($verb, $newUrl, $blob, $headers);
}
/**
* @return string
* Ex: "123.123.123.123:456".
* Ex: "proxy.example.com:789"
* Ex: "dhcp123.isp.example.net:456"
*/
public function getViaPort() {
return $this->viaPort;
}
/**
* @param string $viaPort
* Ex: "123.123.123.123:456".
* Ex: "proxy.example.com:789"
* Ex: "dhcp123.isp.example.net:456"
* @return $this
*/
public function setViaPort($viaPort) {
$this->viaPort = $viaPort;
$modified = array();
return $this;
}
/**
* @return HttpInterface
*/
public function getHttp() {
return $this->http;
}
/**
* @param HttpInterface $http
* @return $this
*/
public function setHttp($http) {
$this->http = $http;
return $this;
}
/**
* Determine whether $viaPort expression is well-formed.
*
* @param string $viaPort
* Ex: "123.123.123.123:456".
* Ex: "proxy.example.com:789"
* Ex: "dhcp123.isp.example.net:456"
* @return bool
* TRUE if valid. FALSE otherwise.
*/
public static function validate($viaPort) {
if (preg_match('/^(?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63}:\d+$/', $viaPort)) {
return TRUE;
}
if (preg_match('/([0-9a-fA-F\.:]+):\d+/', $viaPort, $matches)) {
return filter_var($matches[1], FILTER_VALIDATE_IP) !== FALSE;
}
return FALSE;
}
}

View file

@ -0,0 +1,50 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
class KeyPair {
/**
* @return array
* Array with elements:
* - privatekey: string.
* - publickey: string.
*/
public static function create() {
$rsa = new \Crypt_RSA();
return $rsa->createKey(Constants::RSA_KEYLEN);
}
/**
* @param string $file
* File path.
* @return array
* Array with elements:
* - privatekey: string.
* - publickey: string.
*/
public static function load($file) {
return json_decode(file_get_contents($file), TRUE);
}
/**
* @param string $file
* File path.
* @param array $keyPair
* Array with elements:
* - privatekey: string.
* - publickey: string.
*/
public static function save($file, $keyPair) {
file_put_contents($file, json_encode($keyPair, defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0));
}
}

View file

@ -0,0 +1,119 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
abstract class Message {
protected $code = 200;
protected $headers = array();
protected $data;
public function __construct($data) {
$this->data = $data;
}
/**
* @return string
* Encoded message.
*/
abstract public function encode();
/**
* @return int
*/
public function getCode() {
return $this->code;
}
/**
* @param int $code
* @return static
*/
public function setCode($code) {
$this->code = $code;
return $this;
}
/**
* @return mixed
*/
public function getData() {
return $this->data;
}
/**
* @param mixed $data
* @return static
*/
public function setData($data) {
$this->data = $data;
return $this;
}
/**
* @return array
*/
public function getHeaders() {
return $this->headers;
}
/**
* @param array $headers
* @return static
*/
public function setHeaders($headers) {
$this->headers = $headers;
return $this;
}
/**
* Extract the necessary parts to return this
* message as an HTTP response.
*
* @return array
* array($headers, $blob, $code)
*/
public function toHttp() {
return array($this->headers, $this->encode(), $this->code);
}
/**
* Send this message immediately.
*/
public function send() {
list ($headers, $blob, $code) = $this->toHttp();
header('Content-Type: ' . Constants::MIME_TYPE);
header("X-PHP-Response-Code: $code", TRUE, $code);
foreach ($headers as $n => $v) {
header("$n: $v");
}
echo $blob;
}
/**
* Convert this message a Symfony "Response" object.
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function toSymfonyResponse() {
$headers = array_merge(
array('Content-Type' => Constants::MIME_TYPE),
$this->getHeaders()
);
return new \Symfony\Component\HttpFoundation\Response(
$this->encode(),
$this->code,
$headers
);
}
}

View file

@ -0,0 +1,146 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Message;
use Civi\Cxn\Rpc\BinHex;
use Civi\Cxn\Rpc\CA;
use Civi\Cxn\Rpc\CertificateValidatorInterface;
use Civi\Cxn\Rpc\Exception\CxnException;
use Civi\Cxn\Rpc\Exception\InvalidMessageException;
use Civi\Cxn\Rpc\AppStore\AppStoreInterface;
use Civi\Cxn\Rpc\Message;
use Civi\Cxn\Rpc\UserError;
use Civi\Cxn\Rpc\Constants;
use Civi\Cxn\Rpc\Time;
/**
* Class AppMetasMessage
*
* A signed collection of AppMetas.
*
* @package Civi\Cxn\Rpc\Message
*/
class AppMetasMessage extends Message {
const NAME = 'CXN-0.2-APPS';
protected $cert;
protected $keyPair;
public function __construct($cert, $keyPair, $data) {
parent::__construct($data);
$this->cert = $cert;
$this->keyPair = $keyPair;
}
/**
* @return string
* Ciphertext.
*/
public function encode() {
$envelope = json_encode(array(
'ttl' => Time::getTime() + Constants::REQUEST_TTL,
'r' => json_encode($this->data),
));
$signature = self::getRsa($this->keyPair['privatekey'], 'private')->sign($envelope);
if (empty($signature)) {
throw new CxnException("Failed to compute signature");
}
return self::NAME . Constants::PROTOCOL_DELIM
. $this->cert . Constants::PROTOCOL_DELIM
. base64_encode($signature) . Constants::PROTOCOL_DELIM
. $envelope;
}
/**
* @param CertificateValidatorInterface|NULL $certValidator
* @param string $blob
* @return AppMetasMessage
* Validated message.
* @throws InvalidMessageException
*/
public static function decode($certValidator, $blob) {
$parts = explode(Constants::PROTOCOL_DELIM, $blob, 4);
if (count($parts) != 4) {
throw new InvalidMessageException('Invalid message: insufficient parameters');
}
list ($wireProt, $wireCert, $wireSig, $wireEnvelope) = $parts;
if ($wireProt != self::NAME) {
throw new InvalidMessageException('Invalid message: wrong protocol name');
}
if ($certValidator !== NULL) {
$certValidator->validateCert($wireCert);
$wireCertX509 = new \File_X509();
$wireCertX509->loadX509($wireCert);
$cn = $wireCertX509->getDNProp('CN');
if (count($cn) != 1 || $cn[0] != Constants::OFFICIAL_APPMETAS_CN) {
throw new InvalidMessageException('Invalid message: signed by unauthorized party');
}
$isValid = UserError::adapt('Civi\Cxn\Rpc\Exception\InvalidMessageException', function () use ($wireCertX509, $wireEnvelope, $wireSig) {
return AppMetasMessage::getRsaFromCert($wireCertX509)->verify($wireEnvelope, base64_decode($wireSig));
});
if (!$isValid) {
throw new InvalidMessageException("Invalid message: incorrect signature");
}
}
$envelope = json_decode($wireEnvelope, TRUE);
if (empty($envelope)) {
throw new InvalidMessageException("Invalid message: malformed envelope");
}
if (Time::getTime() > $envelope['ttl']) {
throw new InvalidMessageException("Invalid message: expired");
}
return new AppMetasMessage($wireCert, NULL, json_decode($envelope['r'], TRUE));
}
/**
* Quasi-private - marked public to work-around PHP 5.3 compat.
*
* @param string $key
* @param string $type
* 'public' or 'private'
* @return \Crypt_RSA
*/
public static function getRsa($key, $type) {
$rsa = new \Crypt_RSA();
$rsa->loadKey($key);
if ($type == 'public') {
$rsa->setPublicKey();
}
$rsa->setEncryptionMode(Constants::RSA_ENC_MODE);
$rsa->setSignatureMode(Constants::RSA_SIG_MODE);
$rsa->setHash(Constants::RSA_HASH);
return $rsa;
}
/**
* Quasi-private - marked public to work-around PHP 5.3 compat.
*
* @param \File_X509 $x509
* @return \Crypt_RSA
*/
public static function getRsaFromCert($x509) {
$rsa = $x509->getPublicKey();
if (!$rsa) {
throw new InvalidMessageException("Invalid message: certificate missing or does not have public key");
}
$rsa->setEncryptionMode(Constants::RSA_ENC_MODE);
$rsa->setSignatureMode(Constants::RSA_SIG_MODE);
$rsa->setHash(Constants::RSA_HASH);
return $rsa;
}
}

View file

@ -0,0 +1,46 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Message;
use Civi\Cxn\Rpc\Exception\InvalidMessageException;
use Civi\Cxn\Rpc\Message;
/**
* Class GarbledMessage
*
* A garbled message is one that lacks a proper prefix.
*
* This is common if the other end is using PHP and encounters a PHP error;
* PHP's debug output gets plopped into our pretty data stream.
*
* It may actually be possible to disregard PHP's error output by
* searching for prefix+delimiter... another day...
*
* @package Civi\Cxn\Rpc\Message
*/
class GarbledMessage extends Message {
const NAME = 'CXN-0.2-GARBLED';
public function encode() {
throw new \RuntimeException("Why would you intentionally encode a garbled message this way?");
}
/**
* @param string $message
* @return InsecureMessage
* @throws InvalidMessageException
*/
public static function decode($message) {
return new GarbledMessage($message);
}
}

View file

@ -0,0 +1,55 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Message;
use Civi\Cxn\Rpc\Exception\InvalidMessageException;
use Civi\Cxn\Rpc\Constants;
use Civi\Cxn\Rpc\Message;
/**
* Class InsecureMessage
*
* An insecure message is one that cannot be authenticated. It may be useful
* for reporting low-level connection errors (e.g. due to misconfigured
* crypto). Clients which receive InsecureMessages should treat them with
* suspicion because they can be forged by a man-in-the-middle.
*
* @package Civi\Cxn\Rpc\Message
*/
class InsecureMessage extends Message {
const NAME = 'CXN-0.2-INSECURE';
/**
* @return string
*/
public function encode() {
return self::NAME . Constants::PROTOCOL_DELIM . json_encode($this->data);
}
/**
* @param string $message
* @return InsecureMessage
* @throws InvalidMessageException
*/
public static function decode($message) {
list ($parsedProt, $parsedJson) = explode(Constants::PROTOCOL_DELIM, $message, 2);
if ($parsedProt != self::NAME) {
throw new InvalidMessageException('Incorrect coding. Expected: ' . self::NAME);
}
$data = json_decode($parsedJson, TRUE);
if (!$data) {
throw new InvalidMessageException("Invalid message");
}
return new InsecureMessage($data);
}
}

View file

@ -0,0 +1,131 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Message;
use Civi\Cxn\Rpc\AesHelper;
use Civi\Cxn\Rpc\Exception\InvalidMessageException;
use Civi\Cxn\Rpc\AppStore\AppStoreInterface;
use Civi\Cxn\Rpc\Message;
use Civi\Cxn\Rpc\UserError;
use Civi\Cxn\Rpc\Constants;
/**
* Class RegistrationMessage
*
* A registration message is sent from a site to an app when it wants to
* create or update a connection.
*
* The message includes two ciphertext blobs. The first is a single RSA
* block representing the AES key. The second is AES-CBC+HMAC with the
* real data. This will allow us to expand the registration data (i.e.
* passing along more fields) without changing the protocol.
*
* Note: Crypt_RSA can encrypt oversized messages using an adhoc block
* mode that smells like ECB. This doesn't compromise confidentiality,
* but long messages could have their ciphertext spliced -- compromising
* integrity.
*
* @package Civi\Cxn\Rpc\Message
*/
class RegistrationMessage extends Message {
const NAME = 'CXN-0.2-RSA';
protected $appId;
protected $appPubKey;
public function __construct($appId, $appPubKey, $data) {
parent::__construct($data);
$this->appId = $appId;
$this->appPubKey = $appPubKey;
}
/**
* @return string
* Ciphertext.
*/
public function encode() {
$secret = AesHelper::createSecret();
$rsaCiphertext = self::getRsa($this->appPubKey, 'public')->encrypt($secret);
if (strlen($rsaCiphertext) !== Constants::RSA_MSG_BYTES) {
throw new InvalidMessageException("RSA ciphertext has incorrect length");
}
list($body, $signature) = AesHelper::encryptThenSign($secret, json_encode($this->data));
return self::NAME
. Constants::PROTOCOL_DELIM . $this->appId
. Constants::PROTOCOL_DELIM . base64_encode($rsaCiphertext) // escape PROTOCOL_DELIM
. Constants::PROTOCOL_DELIM . $signature
. Constants::PROTOCOL_DELIM . $body;
}
/**
* @param AppStoreInterface $appStore
* @param string $blob
* @return array
* Decoded data.
*/
public static function decode($appStore, $blob) {
$parts = explode(Constants::PROTOCOL_DELIM, $blob, 5);
if (count($parts) != 5) {
throw new InvalidMessageException('Invalid message: insufficient parameters');
}
list ($wireProt, $wireAppId, $rsaCiphertextB64, $signature, $body) = $parts;
if ($wireProt !== self::NAME) {
throw new InvalidMessageException('Invalid message: wrong protocol name');
}
$appPrivKey = $appStore->getPrivateKey($wireAppId);
if (!$appPrivKey) {
throw new InvalidMessageException('Received message intended for unknown app.');
}
$rsaCiphertext = base64_decode($rsaCiphertextB64);
if (strlen($rsaCiphertext) !== Constants::RSA_MSG_BYTES) {
throw new InvalidMessageException("RSA ciphertext has incorrect length");
}
$secret = UserError::adapt('Civi\Cxn\Rpc\Exception\InvalidMessageException', function () use ($rsaCiphertext, $appPrivKey) {
return RegistrationMessage::getRsa($appPrivKey, 'private')->decrypt($rsaCiphertext);
});
if (empty($secret)) {
throw new InvalidMessageException("Invalid message: decryption produced empty secret");
}
$plaintext = AesHelper::authenticateThenDecrypt($secret, $body, $signature);
return json_decode($plaintext, TRUE);
}
/**
* Quasi-private - marked public to work-around PHP 5.3 compat.
*
* @param string $key
* @param string $type
* 'public' or 'private'
* @return \Crypt_RSA
*/
public static function getRsa($key, $type) {
$rsa = new \Crypt_RSA();
$rsa->loadKey($key);
if ($type == 'public') {
$rsa->setPublicKey();
}
$rsa->setEncryptionMode(Constants::RSA_ENC_MODE);
$rsa->setSignatureMode(Constants::RSA_SIG_MODE);
$rsa->setHash(Constants::RSA_HASH);
return $rsa;
}
}

View file

@ -0,0 +1,103 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc\Message;
use Civi\Cxn\Rpc\AesHelper;
use Civi\Cxn\Rpc\Exception\InvalidMessageException;
use Civi\Cxn\Rpc\Message;
use Civi\Cxn\Rpc\CxnStore\CxnStoreInterface;
use Civi\Cxn\Rpc\Constants;
class StdMessage extends Message {
const NAME = 'CXN-0.2-AES-CBC-HMAC';
protected $cxnId;
protected $secret;
/**
* @param string $cxnId
* @param string $secret
* Base64-encoded secret.
* @param mixed $data
* Serializable data.
*/
public function __construct($cxnId, $secret, $data) {
parent::__construct($data);
$this->cxnId = $cxnId;
$this->secret = $secret;
}
/**
* @return string
* @throws InvalidMessageException
*/
public function encode() {
list($body, $signature) = AesHelper::encryptThenSign($this->secret, json_encode($this->data));
return self::NAME // unsignable; determines decoder
. Constants::PROTOCOL_DELIM . $this->cxnId // unsignable; determines key
. Constants::PROTOCOL_DELIM . $signature
. Constants::PROTOCOL_DELIM . $body;
}
/**
* @param CxnStoreInterface $cxnStore
* A repository that contains shared secrets.
* @param string $message
* Ciphertext.
* @return static
* @throws InvalidMessageException
*/
public static function decode($cxnStore, $message) {
list ($parsedProt, $parsedCxnId, $parsedHmac, $parsedBody) = explode(Constants::PROTOCOL_DELIM, $message, 4);
if ($parsedProt != self::NAME) {
throw new InvalidMessageException('Incorrect coding. Expected: ' . self::NAME);
}
$cxn = $cxnStore->getByCxnId($parsedCxnId);
if (empty($cxn)) {
throw new InvalidMessageException('Unknown connection ID');
}
$jsonPlaintext = AesHelper::authenticateThenDecrypt($cxn['secret'], $parsedBody, $parsedHmac);
return new StdMessage($parsedCxnId, $cxn['secret'], json_decode($jsonPlaintext, TRUE));
}
/**
* @return string
*/
public function getCxnId() {
return $this->cxnId;
}
/**
* @param string $cxnId
*/
public function setCxnId($cxnId) {
$this->cxnId = $cxnId;
}
/**
* @return string
*/
public function getSecret() {
return $this->secret;
}
/**
* @param string $secret
*/
public function setSecret($secret) {
$this->secret = $secret;
}
}

View file

@ -0,0 +1,54 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\Exception\InvalidMessageException;
use Civi\Cxn\Rpc\Message\InsecureMessage;
use Civi\Cxn\Rpc\Message\RegistrationMessage;
use Civi\Cxn\Rpc\Message\StdMessage;
class Messages {
protected $appId, $appPrivKey, $cxnStore;
public function __construct($appId, $appPrivKey, $cxnStore) {
$this->appId = $appId;
$this->appPrivKey = $appPrivKey;
$this->cxnStore = $cxnStore;
}
public function decode($formats, $message) {
$prefixLen = 0;
foreach ($formats as $format) {
$prefixLen = max($prefixLen, strlen($format));
}
list($prefix) = explode(Constants::PROTOCOL_DELIM, substr($message, 0, $prefixLen + 1));
if (!in_array($prefix, $formats)) {
throw new InvalidMessageException("Unexpected message type.");
}
switch ($prefix) {
case StdMessage::NAME:
return StdMessage::decode($this->cxnStore, $message);
case InsecureMessage::NAME:
return InsecureMessage::decode($message);
case RegistrationMessage::NAME:
return RegistrationMessage::decode($this->appId, $this->appPrivKey, $message);
default:
throw new InvalidMessageException("Unrecognized message type");
}
}
}

View file

@ -0,0 +1,229 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\Exception\CxnException;
use Civi\Cxn\Rpc\Message\GarbledMessage;
use Civi\Cxn\Rpc\Message\InsecureMessage;
use Civi\Cxn\Rpc\Message\RegistrationMessage;
use Civi\Cxn\Rpc\Message\StdMessage;
class RegistrationClient extends Agent {
/**
* @var string
*/
protected $siteUrl;
/**
* @var string|NULL
* Ex: "123.123.123.123:456".
* Ex: "proxy.example.com:789"
* Ex: "dhcp123.isp.example.net:456"
*/
protected $viaPort;
/**
* @param CxnStore\CxnStoreInterface $cxnStore
* The place to store active connections.
* @param string $siteUrl
* The callback URL used when the app wishes to send an API call to the site.
* @param string|NULL $viaPort
* If $siteUrl is behind a firewall or otherwise unrouteable, you can
* specify a proxy for any callback messages.
* Ex: "123.123.123.123:456".
* Ex: "proxy.example.com:789"
* Ex: "dhcp123.isp.example.net:456"
*/
public function __construct($cxnStore, $siteUrl, $viaPort = NULL) {
parent::__construct(NULL, $cxnStore);
$this->siteUrl = $siteUrl;
$this->viaPort = $viaPort;
}
/**
* @param array $appMeta
* @return array
* Array($cxnId, $isOk).
*/
public function register($appMeta) {
AppMeta::validate($appMeta);
if ($this->certValidator) {
$this->certValidator->validateCert($appMeta['appCert']);
}
$cxn = $this->cxnStore->getByAppId($appMeta['appId']);
if (!$cxn) {
$cxn = array(
'cxnId' => Cxn::createId(),
'secret' => AesHelper::createSecret(),
'appId' => $appMeta['appId'],
);
}
$cxn['appUrl'] = $appMeta['appUrl'];
$cxn['siteUrl'] = $this->siteUrl;
$cxn['perm'] = $appMeta['perm'];
if (!empty($this->viaPort)) {
$cxn['viaPort'] = $this->viaPort;
}
Cxn::validate($cxn);
$this->cxnStore->add($cxn);
list($respCode, $respData) = $this->doCall($appMeta, 'Cxn', 'register', array(), $cxn);
$success = $respCode == 200 && $respData['is_error'] == 0;
$this->log->info($success ? 'Registered cxnId={cxnId} ({appId}, {appUrl})' : 'Failed to register cxnId={cxnId} ({appId}, {appUrl})', array(
'cxnId' => $cxn['cxnId'],
'appId' => $cxn['appId'],
'appUrl' => $cxn['appUrl'],
));
return array($cxn['cxnId'], $respData);
}
/**
* @param array $appMeta
* @return array
* Array($cxnId, $apiResult).
*/
public function unregister($appMeta, $force = FALSE) {
$cxn = $this->cxnStore->getByAppId($appMeta['appId']);
if (!$cxn) {
return array(
NULL,
array(
'is_error' => 1,
'error_message' => 'Unrecognized appId',
),
);
}
$this->log->info('Unregister cxnId={cxnId} ({appId}, {appUrl})', array(
'cxnId' => $cxn['cxnId'],
'appId' => $cxn['appId'],
'appUrl' => $cxn['appUrl'],
));
$e = NULL;
try {
if ($this->certValidator) {
$this->certValidator->validateCert($appMeta['appCert']);
}
list($respCode, $respData) = $this->doCall($appMeta, 'Cxn', 'unregister', array(), $cxn);
$success = $respCode == 200 && is_array($respData) && $respData['is_error'] == 0;
}
catch (\Exception $e2) {
// simulate try..finally..
$e = $e2;
$success = FALSE;
}
if ($success || $force) {
$this->cxnStore->remove($cxn['cxnId']);
}
if ($e) {
throw $e;
}
return array($cxn['cxnId'], $respData);
}
/**
* @param array $appMeta
* See AppMeta::validate.
* @param string $entity
* An entity name (usually "Cxn").
* @param string $action
* An action (eg "getlink").
* @param array $params
* Open-ended key-value params (depending on entity+action).
* @return mixed
* The response data.
* @throws Exception\ExpiredCertException
* @throws Exception\InvalidCertException
*/
public function call($appMeta, $entity, $action, $params) {
$cxn = $this->cxnStore->getByAppId($appMeta['appId']);
if (!$cxn) {
return array(
NULL,
array(
'is_error' => 1,
'error_message' => 'Unrecognized appId',
),
);
}
$this->log->info('Call {entity}.{action}: ({cxnId}, {appId}, {appUrl})', array(
'entity' => $entity,
'action' => $action,
'cxnId' => $cxn['cxnId'],
'appId' => $cxn['appId'],
'appUrl' => $cxn['appUrl'],
));
if ($this->certValidator) {
$this->certValidator->validateCert($appMeta['appCert']);
}
list($respCode, $respData) = $this->doCall($appMeta, $entity, $action, $params, $cxn);
return $respData;
}
/**
* @param $appMeta
* @param $entity
* @param $action
* @param $params
* @param $cxn
* @return array
* @throws Exception\InvalidMessageException
*/
protected function doCall($appMeta, $entity, $action, $params, $cxn) {
$appCert = new \File_X509();
$appCert->loadX509($appMeta['appCert']);
$req = new RegistrationMessage($cxn['appId'], $appCert->getPublicKey(), array(
'cxn' => $cxn,
'entity' => $entity,
'action' => $action,
'params' => $params,
));
list($respHeaders, $respCiphertext, $respCode) = $this->http->send('POST', $cxn['appUrl'], $req->encode());
$respMessage = $this->decode(array(StdMessage::NAME, InsecureMessage::NAME, GarbledMessage::NAME), $respCiphertext);
if ($respMessage instanceof GarbledMessage) {
return array(
$respCode,
array(
'is_error' => 1,
'error_message' => 'Received garbled message',
'original_message' => $respMessage->getData(),
),
);
}
elseif ($respMessage instanceof InsecureMessage) {
return array(
$respCode,
array(
'is_error' => 1,
'error_message' => 'Received insecure error message',
'original_message' => $respMessage->getData(),
),
);
}
if ($respMessage->getCxnId() != $cxn['cxnId']) {
// Tsk, tsk, Mallory!
throw new \RuntimeException('Received response from incorrect connection.');
}
return array($respCode, $respMessage->getData());
}
}

View file

@ -0,0 +1,188 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\AppStore\SingletonAppStore;
use Civi\Cxn\Rpc\Exception\CxnException;
use Civi\Cxn\Rpc\Exception\InvalidMessageException;
use Civi\Cxn\Rpc\Message\InsecureMessage;
use Civi\Cxn\Rpc\Message\RegistrationMessage;
use Civi\Cxn\Rpc\Message\StdMessage;
/**
* Class RegistrationServer
*
* A registration accepts registration messages and updates a list of
* active connections.
*
* @package Civi\Cxn\Rpc
*/
class RegistrationServer extends Agent {
/**
* @param array $appMeta
* @param array $keyPair
* @param CxnStore\CxnStoreInterface $cxnStore
*
* TODO Change contract, passing in AppStoreInterface instead of appMeta/keyPair.
* This will allow hosting multiple apps in the same endpoint.
*/
public function __construct($appMeta, $keyPair, $cxnStore) {
if (empty($keyPair)) {
throw new CxnException("Missing keyPair");
}
if (empty($keyPair)) {
throw new CxnException("Missing cxnStore");
}
parent::__construct(NULL, $cxnStore);
$this->appStore = new SingletonAppStore($appMeta['appId'], $appMeta, $keyPair['privatekey'], $keyPair['publickey']);
}
/**
* Parse the ciphertext, process it, and return the response.
*
* FIXME Catch exceptions and return in a nice format.
*
* @param string $blob
* POST'ed ciphertext.
* @return Message
*/
public function handle($blob) {
try {
$reqData = $this->decode(RegistrationMessage::NAME, $blob);
}
catch (InvalidMessageException $e) {
$this->log->warning('Received invalid message', array(
'exception' => $e,
));
$resp = new InsecureMessage(array(
'is_error' => 1,
'error_message' => 'Invalid message coding',
array(
$e->getMessage(),
$e->getTraceAsString(),
),
));
return $resp->setCode(400);
}
$this->log->debug('Received registration request', array(
'reqData' => $reqData,
));
$cxn = $reqData['cxn'];
$validation = Cxn::getValidationMessages($cxn);
if (!empty($validation)) {
// $cxn is not valid, so we can't use it for encoding.
$resp = new InsecureMessage(array(
'is_error' => 1,
'error_message' => 'Invalid cxn details: ' . implode(', ', array_keys($validation)),
));
return $resp->setCode(400);
}
$respData = $this->call($reqData);
$this->log->debug('Responding', array($cxn['cxnId'], $cxn['secret'], $respData));
return new StdMessage($cxn['cxnId'], $cxn['secret'], $respData);
}
/**
* Delegate handling of hte registration message to a callback function.
*
* @param $reqData
* @return array|mixed
*/
public function call($reqData) {
$respData = $this->createError('Unrecognized entity or action');
if ($reqData['entity'] == 'Cxn' && preg_match('/^[a-zA-Z]+$/', $reqData['action'])) {
$func = 'on' . $reqData['entity'] . strtoupper($reqData['action']{0}) . substr($reqData['action'], 1);
if (is_callable(array($this, $func))) {
$respData = call_user_func(array($this, $func), $reqData['cxn'], $reqData['params']);
}
}
return $respData;
}
/**
* Callback for Cxn.register.
*
* @param array $cxn
* The CXN record submitted by the client.
* @param array $params
* Additional parameters from the client.
* @return array
*/
public function onCxnRegister($cxn, $params) {
$storedCxn = $this->cxnStore->getByCxnId($cxn['cxnId']);
if (!$storedCxn || $storedCxn['secret'] == $cxn['secret']) {
$this->log->notice('Register cxnId="{cxnId}" siteUrl={siteUrl}: OK', array(
'cxnId' => $cxn['cxnId'],
'siteUrl' => $cxn['siteUrl'],
));
$this->cxnStore->add($cxn);
return $this->createSuccess(array(
'cxn_id' => $cxn['cxnId'],
));
}
else {
$this->log->warning('Register cxnId="{cxnId}" siteUrl="{siteUrl}": Secret does not match.', array(
'cxnId' => $cxn['cxnId'],
'siteUrl' => $cxn['siteUrl'],
));
$this->createError('Secret does not match previous registration.');
}
}
/**
* Callback for Cxn.unregister.
*
* @param array $cxn
* The CXN record submitted by the client.
* @param array $params
* Additional parameters from the client.
* @return array
*/
public function onCxnUnregister($cxn, $params) {
$storedCxn = $this->cxnStore->getByCxnId($cxn['cxnId']);
if (!$storedCxn) {
$this->log->warning('Unregister cxnId="{cxnId} siteUrl="{siteUrl}"": Non-existent', array(
'cxnId' => $cxn['cxnId'],
'siteUrl' => $cxn['siteUrl'],
));
return $this->createSuccess(array(
'cxn_id' => $cxn['cxnId'],
));
}
elseif ($storedCxn['secret'] == $cxn['secret']) {
$this->log->notice('Unregister cxnId="{cxnId} siteUrl="{siteUrl}": OK"', array(
'cxnId' => $cxn['cxnId'],
'siteUrl' => $cxn['siteUrl'],
));
$this->cxnStore->remove($cxn['cxnId']);
return $this->createSuccess(array(
'cxn_id' => $cxn['cxnId'],
));
}
else {
$this->log->warning('Unregister cxnId="{cxnId}" siteUrl="{siteUrl}": Secret does not match.', array(
'cxnId' => $cxn['cxnId'],
'siteUrl' => $cxn['siteUrl'],
));
$this->createError('Incorrect cxnId or secret.');
}
}
}

View file

@ -0,0 +1,63 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
class Time {
/**
* @var int, the seconds offset from the real world time
*/
static private $_delta = 0;
/**
* @return int
*/
public static function getTime() {
if (self::$_delta === 0) {
return time();
}
else {
return floor(microtime(1) + self::$_delta);
}
}
/**
* Set the given time.
*
* @param string $newDateTime
* A date formatted with strtotime.
*
* @return date
*
*/
public static function setTime($newDateTime) {
self::$_delta = strtotime($newDateTime) - microtime(1);
return self::getTime();
}
/**
* Remove any time overrides.
*/
public static function resetTime() {
self::$_delta = 0;
}
/**
* @return \DateTime
*/
public static function createDateTime() {
$d = new \DateTime();
$d->setTimestamp(self::getTime());
return $d;
}
}

View file

@ -0,0 +1,61 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
/**
* Class UserError
*
* phpseclib reports errors via user_error(). When running as a server, we
* often want to catch these so that we can send a well-formed response.
*
* @package Civi\Cxn\Rpc
*/
class UserError {
public static function adapt($class, $callable) {
$errors = array();
set_error_handler(function ($errno, $errstr, $errfile, $errline, $errcontext) use (&$errors) {
if (!(error_reporting() & $errno)) {
return;
}
if ($errno & (E_USER_ERROR | E_USER_NOTICE)) {
$errors[] = array($errno, $errstr, $errfile, $errline);
}
}, E_USER_ERROR | E_USER_NOTICE);
$e = NULL;
try {
$result = call_user_func($callable);
}
catch (\Exception $e2) {
$e = e2;
}
restore_error_handler();
if ($e) {
throw $e;
}
if (!empty($errors)) {
$msg = '';
foreach ($errors as $error) {
$msg .= $error[1] . "\n";
}
throw new $class($msg);
}
return $result;
}
}

View file

@ -0,0 +1,88 @@
<?php
/*
* This file is part of the civicrm-cxn-rpc package.
*
* Copyright (c) CiviCRM LLC <info@civicrm.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this package.
*/
namespace Civi\Cxn\Rpc;
use Civi\Cxn\Rpc\Exception\ExpiredCertException;
use Civi\Cxn\Rpc\Exception\InvalidCertException;
class X509Util {
/**
* @param string $certPem
* @param array $keyPairPems
* Pair of PEM-encoded keys.
* @param string $caCertPem
* @return \File_X509
*/
public static function loadCert($certPem, $keyPairPems = NULL, $caCertPem = NULL) {
$certObj = new \File_X509();
if (isset($caCertPem)) {
$certObj->loadCA($caCertPem);
}
if ($certPem) {
$certObj->loadX509($certPem);
}
if (isset($keyPairPems['privatekey'])) {
$privKey = new \Crypt_RSA();
$privKey->loadKey($keyPairPems['privatekey']);
$certObj->setPrivateKey($privKey);
}
if (isset($keyPairPems['publickey'])) {
$pubKey = new \Crypt_RSA();
$pubKey->loadKey($keyPairPems['publickey']);
$pubKey->setPublicKey();
$certObj->setPublicKey($pubKey);
}
return $certObj;
}
/**
* @param string $caCertPem
* PEM-encoded.
* @param array $keyPair
* Pair of PEM-encoded keys.
* @return \File_X509
* @throws InvalidCertException
*/
public static function loadCACert($caCertPem, $keyPair = NULL) {
$certObj = self::loadCert($caCertPem, $keyPair, $caCertPem);
$keyUsage = $certObj->getExtension('id-ce-keyUsage');
if (!$keyUsage || !in_array('keyCertSign', $keyUsage)) {
throw new InvalidCertException("CA certificate is not a CA certificate");
}
return $certObj;
}
/**
* @param string $crlCertPem
* PEM-encoded.
* @param array $keyPair
* Pair of PEM-encoded keys.
* @param string $caCertPem
* PEM-encoded.
* @return \File_X509
* @throws InvalidCertException
*/
public static function loadCrlDistCert($crlCertPem, $keyPair = NULL, $caCertPem = NULL) {
$certObj = self::loadCert($crlCertPem, $keyPair, $caCertPem);
$keyUsage = $certObj->getExtension('id-ce-keyUsage');
if (!$keyUsage || !in_array('cRLSign', $keyUsage)) {
throw new InvalidCertException("CRL-signing certificate is not a CRL-signing certificate");
}
return $certObj;
}
}

View file

@ -0,0 +1,415 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
if ('\\' == $class[0]) {
$class = substr($class, 1);
}
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}

View file

@ -0,0 +1,21 @@
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
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,148 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Callback' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'CallbackBody' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'CallbackParam' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'CallbackParameterToReference' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'CallbackReturnReference' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'CallbackReturnValue' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'Cpdf' => $vendorDir . '/dompdf/dompdf/lib/Cpdf.php',
'DOMDocumentWrapper' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/DOMDocumentWrapper.php',
'DOMEvent' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/DOMEvent.php',
'Datamatrix' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php',
'HTML5_Data' => $vendorDir . '/dompdf/dompdf/lib/html5lib/Data.php',
'HTML5_InputStream' => $vendorDir . '/dompdf/dompdf/lib/html5lib/InputStream.php',
'HTML5_Parser' => $vendorDir . '/dompdf/dompdf/lib/html5lib/Parser.php',
'HTML5_Tokenizer' => $vendorDir . '/dompdf/dompdf/lib/html5lib/Tokenizer.php',
'HTML5_TreeBuilder' => $vendorDir . '/dompdf/dompdf/lib/html5lib/TreeBuilder.php',
'ICallbackNamed' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'PDF417' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/pdf417.php',
'PclZip' => $vendorDir . '/pclzip/pclzip/pclzip.lib.php',
'QRcode' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/qrcode.php',
'TCPDF' => $vendorDir . '/tecnickcom/tcpdf/tcpdf.php',
'TCPDF2DBarcode' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_barcodes_2d.php',
'TCPDFBarcode' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_barcodes_1d.php',
'TCPDF_COLORS' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_colors.php',
'TCPDF_FILTERS' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_filters.php',
'TCPDF_FONTS' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_fonts.php',
'TCPDF_FONT_DATA' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_font_data.php',
'TCPDF_IMAGES' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_images.php',
'TCPDF_IMPORT' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_import.php',
'TCPDF_PARSER' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_parser.php',
'TCPDF_STATIC' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_static.php',
'ezcBase' => $vendorDir . '/zetacomponents/base/src/base.php',
'ezcBaseAutoloadException' => $vendorDir . '/zetacomponents/base/src/exceptions/autoload.php',
'ezcBaseAutoloadOptions' => $vendorDir . '/zetacomponents/base/src/options/autoload.php',
'ezcBaseConfigurationInitializer' => $vendorDir . '/zetacomponents/base/src/interfaces/configuration_initializer.php',
'ezcBaseDoubleClassRepositoryPrefixException' => $vendorDir . '/zetacomponents/base/src/exceptions/double_class_repository_prefix.php',
'ezcBaseException' => $vendorDir . '/zetacomponents/base/src/exceptions/exception.php',
'ezcBaseExtensionNotFoundException' => $vendorDir . '/zetacomponents/base/src/exceptions/extension_not_found.php',
'ezcBaseFeatures' => $vendorDir . '/zetacomponents/base/src/features.php',
'ezcBaseFile' => $vendorDir . '/zetacomponents/base/src/file.php',
'ezcBaseFileException' => $vendorDir . '/zetacomponents/base/src/exceptions/file_exception.php',
'ezcBaseFileFindContext' => $vendorDir . '/zetacomponents/base/src/structs/file_find_context.php',
'ezcBaseFileIoException' => $vendorDir . '/zetacomponents/base/src/exceptions/file_io.php',
'ezcBaseFileNotFoundException' => $vendorDir . '/zetacomponents/base/src/exceptions/file_not_found.php',
'ezcBaseFilePermissionException' => $vendorDir . '/zetacomponents/base/src/exceptions/file_permission.php',
'ezcBaseFunctionalityNotSupportedException' => $vendorDir . '/zetacomponents/base/src/exceptions/functionality_not_supported.php',
'ezcBaseInit' => $vendorDir . '/zetacomponents/base/src/init.php',
'ezcBaseInitCallbackConfiguredException' => $vendorDir . '/zetacomponents/base/src/exceptions/init_callback_configured.php',
'ezcBaseInitInvalidCallbackClassException' => $vendorDir . '/zetacomponents/base/src/exceptions/invalid_callback_class.php',
'ezcBaseInvalidParentClassException' => $vendorDir . '/zetacomponents/base/src/exceptions/invalid_parent_class.php',
'ezcBaseMetaData' => $vendorDir . '/zetacomponents/base/src/metadata.php',
'ezcBaseMetaDataPearReader' => $vendorDir . '/zetacomponents/base/src/metadata/pear.php',
'ezcBaseMetaDataTarballReader' => $vendorDir . '/zetacomponents/base/src/metadata/tarball.php',
'ezcBaseOptions' => $vendorDir . '/zetacomponents/base/src/options.php',
'ezcBasePersistable' => $vendorDir . '/zetacomponents/base/src/interfaces/persistable.php',
'ezcBasePropertyNotFoundException' => $vendorDir . '/zetacomponents/base/src/exceptions/property_not_found.php',
'ezcBasePropertyPermissionException' => $vendorDir . '/zetacomponents/base/src/exceptions/property_permission.php',
'ezcBaseRepositoryDirectory' => $vendorDir . '/zetacomponents/base/src/structs/repository_directory.php',
'ezcBaseSettingNotFoundException' => $vendorDir . '/zetacomponents/base/src/exceptions/setting_not_found.php',
'ezcBaseSettingValueException' => $vendorDir . '/zetacomponents/base/src/exceptions/setting_value.php',
'ezcBaseStruct' => $vendorDir . '/zetacomponents/base/src/struct.php',
'ezcBaseValueException' => $vendorDir . '/zetacomponents/base/src/exceptions/value.php',
'ezcBaseWhateverException' => $vendorDir . '/zetacomponents/base/src/exceptions/whatever.php',
'ezcMail' => $vendorDir . '/zetacomponents/mail/src/mail.php',
'ezcMailAddress' => $vendorDir . '/zetacomponents/mail/src/structs/mail_address.php',
'ezcMailCharsetConverter' => $vendorDir . '/zetacomponents/mail/src/internal/charset_convert.php',
'ezcMailComposer' => $vendorDir . '/zetacomponents/mail/src/composer.php',
'ezcMailComposerOptions' => $vendorDir . '/zetacomponents/mail/src/options/composer_options.php',
'ezcMailContentDispositionHeader' => $vendorDir . '/zetacomponents/mail/src/structs/content_disposition_header.php',
'ezcMailDeliveryStatus' => $vendorDir . '/zetacomponents/mail/src/parts/delivery_status.php',
'ezcMailDeliveryStatusParser' => $vendorDir . '/zetacomponents/mail/src/parser/parts/delivery_status_parser.php',
'ezcMailException' => $vendorDir . '/zetacomponents/mail/src/exceptions/mail_exception.php',
'ezcMailFile' => $vendorDir . '/zetacomponents/mail/src/parts/fileparts/disk_file.php',
'ezcMailFileParser' => $vendorDir . '/zetacomponents/mail/src/parser/parts/file_parser.php',
'ezcMailFilePart' => $vendorDir . '/zetacomponents/mail/src/parts/file.php',
'ezcMailFileSet' => $vendorDir . '/zetacomponents/mail/src/transports/file/file_set.php',
'ezcMailHeaderFolder' => $vendorDir . '/zetacomponents/mail/src/internal/header_folder.php',
'ezcMailHeadersHolder' => $vendorDir . '/zetacomponents/mail/src/parser/headers_holder.php',
'ezcMailImapSet' => $vendorDir . '/zetacomponents/mail/src/transports/imap/imap_set.php',
'ezcMailImapSetOptions' => $vendorDir . '/zetacomponents/mail/src/options/imap_set_options.php',
'ezcMailImapTransport' => $vendorDir . '/zetacomponents/mail/src/transports/imap/imap_transport.php',
'ezcMailImapTransportOptions' => $vendorDir . '/zetacomponents/mail/src/options/imap_options.php',
'ezcMailInvalidLimitException' => $vendorDir . '/zetacomponents/mail/src/exceptions/invalid_limit.php',
'ezcMailMboxSet' => $vendorDir . '/zetacomponents/mail/src/transports/mbox/mbox_set.php',
'ezcMailMboxTransport' => $vendorDir . '/zetacomponents/mail/src/transports/mbox/mbox_transport.php',
'ezcMailMtaTransport' => $vendorDir . '/zetacomponents/mail/src/transports/mta/mta_transport.php',
'ezcMailMultipart' => $vendorDir . '/zetacomponents/mail/src/parts/multipart.php',
'ezcMailMultipartAlternative' => $vendorDir . '/zetacomponents/mail/src/parts/multiparts/multipart_alternative.php',
'ezcMailMultipartAlternativeParser' => $vendorDir . '/zetacomponents/mail/src/parser/parts/multipart_alternative_parser.php',
'ezcMailMultipartDigest' => $vendorDir . '/zetacomponents/mail/src/parts/multiparts/multipart_digest.php',
'ezcMailMultipartDigestParser' => $vendorDir . '/zetacomponents/mail/src/parser/parts/multipart_digest_parser.php',
'ezcMailMultipartMixed' => $vendorDir . '/zetacomponents/mail/src/parts/multiparts/multipart_mixed.php',
'ezcMailMultipartMixedParser' => $vendorDir . '/zetacomponents/mail/src/parser/parts/multipart_mixed_parser.php',
'ezcMailMultipartParser' => $vendorDir . '/zetacomponents/mail/src/parser/parts/multipart_parser.php',
'ezcMailMultipartRelated' => $vendorDir . '/zetacomponents/mail/src/parts/multiparts/multipart_related.php',
'ezcMailMultipartRelatedParser' => $vendorDir . '/zetacomponents/mail/src/parser/parts/multipart_related_parser.php',
'ezcMailMultipartReport' => $vendorDir . '/zetacomponents/mail/src/parts/multiparts/multipart_report.php',
'ezcMailMultipartReportParser' => $vendorDir . '/zetacomponents/mail/src/parser/parts/multipart_report_parser.php',
'ezcMailNoSuchMessageException' => $vendorDir . '/zetacomponents/mail/src/exceptions/no_such_message.php',
'ezcMailOffsetOutOfRangeException' => $vendorDir . '/zetacomponents/mail/src/exceptions/offset_out_of_range.php',
'ezcMailParser' => $vendorDir . '/zetacomponents/mail/src/parser/parser.php',
'ezcMailParserOptions' => $vendorDir . '/zetacomponents/mail/src/options/parser_options.php',
'ezcMailParserSet' => $vendorDir . '/zetacomponents/mail/src/parser/interfaces/parser_set.php',
'ezcMailParserShutdownHandler' => $vendorDir . '/zetacomponents/mail/src/parser/shutdown_handler.php',
'ezcMailPart' => $vendorDir . '/zetacomponents/mail/src/interfaces/part.php',
'ezcMailPartParser' => $vendorDir . '/zetacomponents/mail/src/parser/interfaces/part_parser.php',
'ezcMailPartWalkContext' => $vendorDir . '/zetacomponents/mail/src/structs/walk_context.php',
'ezcMailPop3Set' => $vendorDir . '/zetacomponents/mail/src/transports/pop3/pop3_set.php',
'ezcMailPop3Transport' => $vendorDir . '/zetacomponents/mail/src/transports/pop3/pop3_transport.php',
'ezcMailPop3TransportOptions' => $vendorDir . '/zetacomponents/mail/src/options/pop3_options.php',
'ezcMailRfc2231Implementation' => $vendorDir . '/zetacomponents/mail/src/parser/rfc2231_implementation.php',
'ezcMailRfc822Digest' => $vendorDir . '/zetacomponents/mail/src/parts/rfc822_digest.php',
'ezcMailRfc822DigestParser' => $vendorDir . '/zetacomponents/mail/src/parser/parts/rfc822_digest_parser.php',
'ezcMailRfc822Parser' => $vendorDir . '/zetacomponents/mail/src/parser/parts/rfc822_parser.php',
'ezcMailSmtpTransport' => $vendorDir . '/zetacomponents/mail/src/transports/smtp/smtp_transport.php',
'ezcMailSmtpTransportOptions' => $vendorDir . '/zetacomponents/mail/src/options/smtp_options.php',
'ezcMailStorageSet' => $vendorDir . '/zetacomponents/mail/src/transports/storage/storage_set.php',
'ezcMailStreamFile' => $vendorDir . '/zetacomponents/mail/src/parts/fileparts/stream_file.php',
'ezcMailText' => $vendorDir . '/zetacomponents/mail/src/parts/text.php',
'ezcMailTextParser' => $vendorDir . '/zetacomponents/mail/src/parser/parts/text_parser.php',
'ezcMailTools' => $vendorDir . '/zetacomponents/mail/src/tools.php',
'ezcMailTransport' => $vendorDir . '/zetacomponents/mail/src/interfaces/transport.php',
'ezcMailTransportConnection' => $vendorDir . '/zetacomponents/mail/src/transports/transport_connection.php',
'ezcMailTransportException' => $vendorDir . '/zetacomponents/mail/src/exceptions/transport_exception.php',
'ezcMailTransportMta' => $vendorDir . '/zetacomponents/mail/src/transports/mta/transport_mta.php',
'ezcMailTransportOptions' => $vendorDir . '/zetacomponents/mail/src/options/transport_options.php',
'ezcMailTransportSmtp' => $vendorDir . '/zetacomponents/mail/src/transports/smtp/transport_smtp.php',
'ezcMailTransportSmtpException' => $vendorDir . '/zetacomponents/mail/src/exceptions/transport_smtp_exception.php',
'ezcMailVariableSet' => $vendorDir . '/zetacomponents/mail/src/transports/variable/var_set.php',
'ezcMailVirtualFile' => $vendorDir . '/zetacomponents/mail/src/parts/fileparts/virtual_file.php',
'phpQuery' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery.php',
'phpQueryEvents' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/phpQueryEvents.php',
'phpQueryObject' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/phpQueryObject.php',
'phpQueryObjectPlugin_Scripts' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/plugins/Scripts.php',
'phpQueryObjectPlugin_WebBrowser' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/plugins/WebBrowser.php',
'phpQueryObjectPlugin_example' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/plugins/example.php',
'phpQueryPlugin_Scripts' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/plugins/Scripts.php',
'phpQueryPlugin_WebBrowser' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/plugins/WebBrowser.php',
'phpQueryPlugin_example' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery/plugins/example.php',
'phpQueryPlugins' => $vendorDir . '/electrolinux/phpquery/phpQuery/phpQuery.php',
);

View file

@ -0,0 +1,11 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
'3919eeb97e98d4648304477f8ef734ba' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php',
);

View file

@ -0,0 +1,30 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Validate' => array($vendorDir . '/pear/validate_finance_creditcard'),
'System' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
'Symfony\\Component\\DependencyInjection\\' => array($vendorDir . '/symfony/dependency-injection'),
'Symfony\\Component\\Config\\' => array($vendorDir . '/symfony/config'),
'Svg\\' => array($vendorDir . '/phenx/php-svg-lib/src'),
'Sabberworm\\CSS' => array($vendorDir . '/sabberworm/php-css-parser/lib'),
'Psr\\Log\\' => array($vendorDir . '/psr/log'),
'PHPUnit_' => array($baseDir . '/packages'),
'PEAR' => array($vendorDir . '/pear/pear_exception'),
'Net' => array($vendorDir . '/phpseclib/phpseclib/phpseclib', $vendorDir . '/pear/net_socket', $vendorDir . '/pear/net_smtp'),
'Math' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
'File' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
'Crypt' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
'Civi\\' => array($baseDir . '/', $baseDir . '/tests/phpunit'),
'Civi' => array($baseDir . '/'),
'CA_Config' => array($vendorDir . '/totten/ca-config/src'),
'Auth' => array($vendorDir . '/pear/auth_sasl'),
);

View file

@ -0,0 +1,19 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Zend\\Validator\\' => array($vendorDir . '/zendframework/zend-validator/src'),
'Zend\\Stdlib\\' => array($vendorDir . '/zendframework/zend-stdlib/src'),
'Zend\\Escaper\\' => array($vendorDir . '/zendframework/zend-escaper/src'),
'PhpOffice\\PhpWord\\' => array($vendorDir . '/phpoffice/phpword/src/PhpWord'),
'PhpOffice\\Common\\' => array($vendorDir . '/phpoffice/common/src/Common'),
'MJS\\TopSort\\Tests\\' => array($vendorDir . '/marcj/topsort/tests/Tests'),
'MJS\\TopSort\\' => array($vendorDir . '/marcj/topsort/src'),
'FontLib\\' => array($vendorDir . '/phenx/php-font-lib/src/FontLib'),
'Dompdf\\' => array($vendorDir . '/dompdf/dompdf/src'),
'Civi\\Cxn\\Rpc\\' => array($vendorDir . '/civicrm/civicrm-cxn-rpc/src'),
);

View file

@ -0,0 +1,74 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit5cdee2268f29abd76073fe42de4e8d15
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit5cdee2268f29abd76073fe42de4e8d15', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit5cdee2268f29abd76073fe42de4e8d15', 'loadClassLoader'));
$includePaths = require __DIR__ . '/include_paths.php';
array_push($includePaths, get_include_path());
set_include_path(join(PATH_SEPARATOR, $includePaths));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit5cdee2268f29abd76073fe42de4e8d15::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit5cdee2268f29abd76073fe42de4e8d15::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire5cdee2268f29abd76073fe42de4e8d15($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire5cdee2268f29abd76073fe42de4e8d15($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}

View file

@ -0,0 +1,354 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit5cdee2268f29abd76073fe42de4e8d15
{
public static $files = array (
'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
'3919eeb97e98d4648304477f8ef734ba' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php',
);
public static $prefixLengthsPsr4 = array (
'Z' =>
array (
'Zend\\Validator\\' => 15,
'Zend\\Stdlib\\' => 12,
'Zend\\Escaper\\' => 13,
),
'P' =>
array (
'PhpOffice\\PhpWord\\' => 18,
'PhpOffice\\Common\\' => 17,
),
'M' =>
array (
'MJS\\TopSort\\Tests\\' => 18,
'MJS\\TopSort\\' => 12,
),
'F' =>
array (
'FontLib\\' => 8,
),
'D' =>
array (
'Dompdf\\' => 7,
),
'C' =>
array (
'Civi\\Cxn\\Rpc\\' => 13,
),
);
public static $prefixDirsPsr4 = array (
'Zend\\Validator\\' =>
array (
0 => __DIR__ . '/..' . '/zendframework/zend-validator/src',
),
'Zend\\Stdlib\\' =>
array (
0 => __DIR__ . '/..' . '/zendframework/zend-stdlib/src',
),
'Zend\\Escaper\\' =>
array (
0 => __DIR__ . '/..' . '/zendframework/zend-escaper/src',
),
'PhpOffice\\PhpWord\\' =>
array (
0 => __DIR__ . '/..' . '/phpoffice/phpword/src/PhpWord',
),
'PhpOffice\\Common\\' =>
array (
0 => __DIR__ . '/..' . '/phpoffice/common/src/Common',
),
'MJS\\TopSort\\Tests\\' =>
array (
0 => __DIR__ . '/..' . '/marcj/topsort/tests/Tests',
),
'MJS\\TopSort\\' =>
array (
0 => __DIR__ . '/..' . '/marcj/topsort/src',
),
'FontLib\\' =>
array (
0 => __DIR__ . '/..' . '/phenx/php-font-lib/src/FontLib',
),
'Dompdf\\' =>
array (
0 => __DIR__ . '/..' . '/dompdf/dompdf/src',
),
'Civi\\Cxn\\Rpc\\' =>
array (
0 => __DIR__ . '/..' . '/civicrm/civicrm-cxn-rpc/src',
),
);
public static $prefixesPsr0 = array (
'V' =>
array (
'Validate' =>
array (
0 => __DIR__ . '/..' . '/pear/validate_finance_creditcard',
),
),
'S' =>
array (
'System' =>
array (
0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib',
),
'Symfony\\Component\\Process\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/process',
),
'Symfony\\Component\\Finder\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/finder',
),
'Symfony\\Component\\Filesystem\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/filesystem',
),
'Symfony\\Component\\EventDispatcher\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/event-dispatcher',
),
'Symfony\\Component\\DependencyInjection\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/dependency-injection',
),
'Symfony\\Component\\Config\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/config',
),
'Svg\\' =>
array (
0 => __DIR__ . '/..' . '/phenx/php-svg-lib/src',
),
'Sabberworm\\CSS' =>
array (
0 => __DIR__ . '/..' . '/sabberworm/php-css-parser/lib',
),
),
'P' =>
array (
'Psr\\Log\\' =>
array (
0 => __DIR__ . '/..' . '/psr/log',
),
'PHPUnit_' =>
array (
0 => __DIR__ . '/../..' . '/packages',
),
'PEAR' =>
array (
0 => __DIR__ . '/..' . '/pear/pear_exception',
),
),
'N' =>
array (
'Net' =>
array (
0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib',
1 => __DIR__ . '/..' . '/pear/net_socket',
2 => __DIR__ . '/..' . '/pear/net_smtp',
),
),
'M' =>
array (
'Math' =>
array (
0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib',
),
),
'F' =>
array (
'File' =>
array (
0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib',
),
),
'C' =>
array (
'Crypt' =>
array (
0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib',
),
'Civi\\' =>
array (
0 => __DIR__ . '/../..' . '/',
1 => __DIR__ . '/../..' . '/tests/phpunit',
),
'Civi' =>
array (
0 => __DIR__ . '/../..' . '/',
),
'CA_Config' =>
array (
0 => __DIR__ . '/..' . '/totten/ca-config/src',
),
),
'A' =>
array (
'Auth' =>
array (
0 => __DIR__ . '/..' . '/pear/auth_sasl',
),
),
);
public static $classMap = array (
'Callback' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'CallbackBody' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'CallbackParam' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'CallbackParameterToReference' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'CallbackReturnReference' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'CallbackReturnValue' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'Cpdf' => __DIR__ . '/..' . '/dompdf/dompdf/lib/Cpdf.php',
'DOMDocumentWrapper' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/DOMDocumentWrapper.php',
'DOMEvent' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/DOMEvent.php',
'Datamatrix' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php',
'HTML5_Data' => __DIR__ . '/..' . '/dompdf/dompdf/lib/html5lib/Data.php',
'HTML5_InputStream' => __DIR__ . '/..' . '/dompdf/dompdf/lib/html5lib/InputStream.php',
'HTML5_Parser' => __DIR__ . '/..' . '/dompdf/dompdf/lib/html5lib/Parser.php',
'HTML5_Tokenizer' => __DIR__ . '/..' . '/dompdf/dompdf/lib/html5lib/Tokenizer.php',
'HTML5_TreeBuilder' => __DIR__ . '/..' . '/dompdf/dompdf/lib/html5lib/TreeBuilder.php',
'ICallbackNamed' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/Callback.php',
'PDF417' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/pdf417.php',
'PclZip' => __DIR__ . '/..' . '/pclzip/pclzip/pclzip.lib.php',
'QRcode' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/qrcode.php',
'TCPDF' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf.php',
'TCPDF2DBarcode' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_barcodes_2d.php',
'TCPDFBarcode' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_barcodes_1d.php',
'TCPDF_COLORS' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_colors.php',
'TCPDF_FILTERS' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_filters.php',
'TCPDF_FONTS' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_fonts.php',
'TCPDF_FONT_DATA' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_font_data.php',
'TCPDF_IMAGES' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_images.php',
'TCPDF_IMPORT' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_import.php',
'TCPDF_PARSER' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_parser.php',
'TCPDF_STATIC' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_static.php',
'ezcBase' => __DIR__ . '/..' . '/zetacomponents/base/src/base.php',
'ezcBaseAutoloadException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/autoload.php',
'ezcBaseAutoloadOptions' => __DIR__ . '/..' . '/zetacomponents/base/src/options/autoload.php',
'ezcBaseConfigurationInitializer' => __DIR__ . '/..' . '/zetacomponents/base/src/interfaces/configuration_initializer.php',
'ezcBaseDoubleClassRepositoryPrefixException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/double_class_repository_prefix.php',
'ezcBaseException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/exception.php',
'ezcBaseExtensionNotFoundException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/extension_not_found.php',
'ezcBaseFeatures' => __DIR__ . '/..' . '/zetacomponents/base/src/features.php',
'ezcBaseFile' => __DIR__ . '/..' . '/zetacomponents/base/src/file.php',
'ezcBaseFileException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/file_exception.php',
'ezcBaseFileFindContext' => __DIR__ . '/..' . '/zetacomponents/base/src/structs/file_find_context.php',
'ezcBaseFileIoException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/file_io.php',
'ezcBaseFileNotFoundException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/file_not_found.php',
'ezcBaseFilePermissionException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/file_permission.php',
'ezcBaseFunctionalityNotSupportedException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/functionality_not_supported.php',
'ezcBaseInit' => __DIR__ . '/..' . '/zetacomponents/base/src/init.php',
'ezcBaseInitCallbackConfiguredException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/init_callback_configured.php',
'ezcBaseInitInvalidCallbackClassException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/invalid_callback_class.php',
'ezcBaseInvalidParentClassException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/invalid_parent_class.php',
'ezcBaseMetaData' => __DIR__ . '/..' . '/zetacomponents/base/src/metadata.php',
'ezcBaseMetaDataPearReader' => __DIR__ . '/..' . '/zetacomponents/base/src/metadata/pear.php',
'ezcBaseMetaDataTarballReader' => __DIR__ . '/..' . '/zetacomponents/base/src/metadata/tarball.php',
'ezcBaseOptions' => __DIR__ . '/..' . '/zetacomponents/base/src/options.php',
'ezcBasePersistable' => __DIR__ . '/..' . '/zetacomponents/base/src/interfaces/persistable.php',
'ezcBasePropertyNotFoundException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/property_not_found.php',
'ezcBasePropertyPermissionException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/property_permission.php',
'ezcBaseRepositoryDirectory' => __DIR__ . '/..' . '/zetacomponents/base/src/structs/repository_directory.php',
'ezcBaseSettingNotFoundException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/setting_not_found.php',
'ezcBaseSettingValueException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/setting_value.php',
'ezcBaseStruct' => __DIR__ . '/..' . '/zetacomponents/base/src/struct.php',
'ezcBaseValueException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/value.php',
'ezcBaseWhateverException' => __DIR__ . '/..' . '/zetacomponents/base/src/exceptions/whatever.php',
'ezcMail' => __DIR__ . '/..' . '/zetacomponents/mail/src/mail.php',
'ezcMailAddress' => __DIR__ . '/..' . '/zetacomponents/mail/src/structs/mail_address.php',
'ezcMailCharsetConverter' => __DIR__ . '/..' . '/zetacomponents/mail/src/internal/charset_convert.php',
'ezcMailComposer' => __DIR__ . '/..' . '/zetacomponents/mail/src/composer.php',
'ezcMailComposerOptions' => __DIR__ . '/..' . '/zetacomponents/mail/src/options/composer_options.php',
'ezcMailContentDispositionHeader' => __DIR__ . '/..' . '/zetacomponents/mail/src/structs/content_disposition_header.php',
'ezcMailDeliveryStatus' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/delivery_status.php',
'ezcMailDeliveryStatusParser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/parts/delivery_status_parser.php',
'ezcMailException' => __DIR__ . '/..' . '/zetacomponents/mail/src/exceptions/mail_exception.php',
'ezcMailFile' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/fileparts/disk_file.php',
'ezcMailFileParser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/parts/file_parser.php',
'ezcMailFilePart' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/file.php',
'ezcMailFileSet' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/file/file_set.php',
'ezcMailHeaderFolder' => __DIR__ . '/..' . '/zetacomponents/mail/src/internal/header_folder.php',
'ezcMailHeadersHolder' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/headers_holder.php',
'ezcMailImapSet' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/imap/imap_set.php',
'ezcMailImapSetOptions' => __DIR__ . '/..' . '/zetacomponents/mail/src/options/imap_set_options.php',
'ezcMailImapTransport' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/imap/imap_transport.php',
'ezcMailImapTransportOptions' => __DIR__ . '/..' . '/zetacomponents/mail/src/options/imap_options.php',
'ezcMailInvalidLimitException' => __DIR__ . '/..' . '/zetacomponents/mail/src/exceptions/invalid_limit.php',
'ezcMailMboxSet' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/mbox/mbox_set.php',
'ezcMailMboxTransport' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/mbox/mbox_transport.php',
'ezcMailMtaTransport' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/mta/mta_transport.php',
'ezcMailMultipart' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/multipart.php',
'ezcMailMultipartAlternative' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/multiparts/multipart_alternative.php',
'ezcMailMultipartAlternativeParser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/parts/multipart_alternative_parser.php',
'ezcMailMultipartDigest' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/multiparts/multipart_digest.php',
'ezcMailMultipartDigestParser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/parts/multipart_digest_parser.php',
'ezcMailMultipartMixed' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/multiparts/multipart_mixed.php',
'ezcMailMultipartMixedParser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/parts/multipart_mixed_parser.php',
'ezcMailMultipartParser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/parts/multipart_parser.php',
'ezcMailMultipartRelated' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/multiparts/multipart_related.php',
'ezcMailMultipartRelatedParser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/parts/multipart_related_parser.php',
'ezcMailMultipartReport' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/multiparts/multipart_report.php',
'ezcMailMultipartReportParser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/parts/multipart_report_parser.php',
'ezcMailNoSuchMessageException' => __DIR__ . '/..' . '/zetacomponents/mail/src/exceptions/no_such_message.php',
'ezcMailOffsetOutOfRangeException' => __DIR__ . '/..' . '/zetacomponents/mail/src/exceptions/offset_out_of_range.php',
'ezcMailParser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/parser.php',
'ezcMailParserOptions' => __DIR__ . '/..' . '/zetacomponents/mail/src/options/parser_options.php',
'ezcMailParserSet' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/interfaces/parser_set.php',
'ezcMailParserShutdownHandler' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/shutdown_handler.php',
'ezcMailPart' => __DIR__ . '/..' . '/zetacomponents/mail/src/interfaces/part.php',
'ezcMailPartParser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/interfaces/part_parser.php',
'ezcMailPartWalkContext' => __DIR__ . '/..' . '/zetacomponents/mail/src/structs/walk_context.php',
'ezcMailPop3Set' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/pop3/pop3_set.php',
'ezcMailPop3Transport' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/pop3/pop3_transport.php',
'ezcMailPop3TransportOptions' => __DIR__ . '/..' . '/zetacomponents/mail/src/options/pop3_options.php',
'ezcMailRfc2231Implementation' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/rfc2231_implementation.php',
'ezcMailRfc822Digest' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/rfc822_digest.php',
'ezcMailRfc822DigestParser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/parts/rfc822_digest_parser.php',
'ezcMailRfc822Parser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/parts/rfc822_parser.php',
'ezcMailSmtpTransport' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/smtp/smtp_transport.php',
'ezcMailSmtpTransportOptions' => __DIR__ . '/..' . '/zetacomponents/mail/src/options/smtp_options.php',
'ezcMailStorageSet' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/storage/storage_set.php',
'ezcMailStreamFile' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/fileparts/stream_file.php',
'ezcMailText' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/text.php',
'ezcMailTextParser' => __DIR__ . '/..' . '/zetacomponents/mail/src/parser/parts/text_parser.php',
'ezcMailTools' => __DIR__ . '/..' . '/zetacomponents/mail/src/tools.php',
'ezcMailTransport' => __DIR__ . '/..' . '/zetacomponents/mail/src/interfaces/transport.php',
'ezcMailTransportConnection' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/transport_connection.php',
'ezcMailTransportException' => __DIR__ . '/..' . '/zetacomponents/mail/src/exceptions/transport_exception.php',
'ezcMailTransportMta' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/mta/transport_mta.php',
'ezcMailTransportOptions' => __DIR__ . '/..' . '/zetacomponents/mail/src/options/transport_options.php',
'ezcMailTransportSmtp' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/smtp/transport_smtp.php',
'ezcMailTransportSmtpException' => __DIR__ . '/..' . '/zetacomponents/mail/src/exceptions/transport_smtp_exception.php',
'ezcMailVariableSet' => __DIR__ . '/..' . '/zetacomponents/mail/src/transports/variable/var_set.php',
'ezcMailVirtualFile' => __DIR__ . '/..' . '/zetacomponents/mail/src/parts/fileparts/virtual_file.php',
'phpQuery' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery.php',
'phpQueryEvents' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/phpQueryEvents.php',
'phpQueryObject' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/phpQueryObject.php',
'phpQueryObjectPlugin_Scripts' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/plugins/Scripts.php',
'phpQueryObjectPlugin_WebBrowser' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/plugins/WebBrowser.php',
'phpQueryObjectPlugin_example' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/plugins/example.php',
'phpQueryPlugin_Scripts' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/plugins/Scripts.php',
'phpQueryPlugin_WebBrowser' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/plugins/WebBrowser.php',
'phpQueryPlugin_example' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery/plugins/example.php',
'phpQueryPlugins' => __DIR__ . '/..' . '/electrolinux/phpquery/phpQuery/phpQuery.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit5cdee2268f29abd76073fe42de4e8d15::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit5cdee2268f29abd76073fe42de4e8d15::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit5cdee2268f29abd76073fe42de4e8d15::$prefixesPsr0;
$loader->classMap = ComposerStaticInit5cdee2268f29abd76073fe42de4e8d15::$classMap;
}, null, ClassLoader::class);
}
}

View file

@ -0,0 +1,16 @@
<?php
// include_paths.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
$vendorDir . '/tecnickcom',
$vendorDir . '/phpseclib/phpseclib/phpseclib',
$vendorDir . '/pear/pear_exception',
$vendorDir . '/pear/auth_sasl',
$vendorDir . '/pear/net_socket',
$vendorDir . '/pear/net_smtp',
$vendorDir . '/pear/validate_finance_creditcard',
);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,65 @@
# How to contribute
- [Getting help](#getting-help)
- [Submitting bug reports](#submitting-bug-reports)
- [Contributing code](#contributing-code)
## Getting help
Community discussion, questions, and informal bug reporting is done on the
[dompdf Google group](http://groups.google.com/group/dompdf). You may also
seek help on
[StackOverflow](http://stackoverflow.com/questions/tagged/dompdf).
## Submitting bug reports
The preferred way to report bugs is to use the
[GitHub issue tracker](http://github.com/dompdf/dompdf/issues). Before
reporting a bug, read these pointers.
**Please search inside the bug tracker to see if the bug you found is not already reported.**
**Note:** The issue tracker is for *bugs* and *feature requests*, not requests for help.
Questions should be asked on the
[dompdf Google group](http://groups.google.com/group/dompdf) instead.
### Reporting bugs effectively
- dompdf is maintained by volunteers. They don't owe you anything, so be
polite. Reports with an indignant or belligerent tone tend to be moved to the
bottom of the pile.
- Include information about **the PHP version on which the problem occurred**. Even
if you tested several PHP version on different servers, and the problem occurred
in all of them, mention this fact in the bug report.
Also include the operating system it's installed on. PHP configuration can also help,
and server error logs (like Apache logs)
- Mention which release of dompdf you're using (the zip, the master branch, etc).
Preferably, try also with the current development snapshot, to ensure the
problem has not already been fixed.
- Mention very precisely what went wrong. "X is broken" is not a good bug
report. What did you expect to happen? What happened instead? Describe the
exact steps a maintainer has to take to make the problem occur. We can not
fix something that we can not observe.
- If the problem can not be reproduced in any of the demos included in the
dompdf distribution, please provide an HTML document that demonstrates
the problem. There are a few options to show us your code:
- [JS Fiddle](http://jsfiddle.net/)
- [dompdf debug helper](http://eclecticgeek.com/dompdf/debug.php) (provided by @bsweeney)
- Include the HTML/CSS inside the bug report, with
[code highlighting](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#wiki-code).
## Contributing code
- Make sure you have a [GitHub Account](https://github.com/signup/free)
- Fork [dompdf](https://github.com/dompdf/dompdf/)
([how to fork a repo](https://help.github.com/articles/fork-a-repo))
- *Make your changes on the dev branch* or the most appropriate feature branch. Please only patch
the master branch if you are attempting to address an urgent bug in the released code.
- Add a simple test file in `www/test/`, with a comprehensive name.
- Add a unit test in the ``test/Dompdf/Tests/`` directory.
- Submit a pull request
([how to create a pull request](https://help.github.com/articles/fork-a-repo))

View file

@ -0,0 +1,456 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.

View file

@ -0,0 +1,207 @@
Dompdf
======
[![Build Status](https://travis-ci.org/dompdf/dompdf.png?branch=master)](https://travis-ci.org/dompdf/dompdf)
[![Latest Stable Version](https://poser.pugx.org/dompdf/dompdf/v/stable.png)](https://packagist.org/packages/dompdf/dompdf)
[![Total Downloads](https://poser.pugx.org/dompdf/dompdf/downloads.png)](https://packagist.org/packages/dompdf/dompdf)
[![Latest Unstable Version](https://poser.pugx.org/dompdf/dompdf/v/unstable.png)](https://packagist.org/packages/dompdf/dompdf)
[![License](https://poser.pugx.org/dompdf/dompdf/license.png)](https://packagist.org/packages/dompdf/dompdf)
**Dompdf is an HTML to PDF converter**
At its heart, dompdf is (mostly) a [CSS 2.1](http://www.w3.org/TR/CSS2/) compliant
HTML layout and rendering engine written in PHP. It is a style-driven renderer:
it will download and read external stylesheets, inline style tags, and the style
attributes of individual HTML elements. It also supports most presentational
HTML attributes.
*This document applies to the latest stable code which may not reflect the current
release. For released code please
[navigate to the appropriate tag](https://github.com/dompdf/dompdf/tags).*
----
**Check out the [demo](http://pxd.me/dompdf/www/examples.php) and ask any
question on [StackOverflow](http://stackoverflow.com/questions/tagged/dompdf) or
on the [Google Groups](http://groups.google.com/group/dompdf).**
Follow us on [![Twitter](http://twitter-badges.s3.amazonaws.com/twitter-a.png)](http://www.twitter.com/dompdf) or
[![Follow us on Google+](https://ssl.gstatic.com/images/icons/gplus-16.png)](https://plus.google.com/108710008521858993320?prsrc=3).
---
## Features
* Handles most CSS 2.1 and a few CSS3 properties, including @import, @media &
@page rules
* Supports most presentational HTML 4.0 attributes
* Supports external stylesheets, either local or through http/ftp (via
fopen-wrappers)
* Supports complex tables, including row & column spans, separate & collapsed
border models, individual cell styling
* Image support (gif, png (8, 24 and 32 bit with alpha channel), bmp & jpeg)
* No dependencies on external PDF libraries, thanks to the R&OS PDF class
* Inline PHP support
* Basic SVG support
## Requirements
* PHP version 5.3.0 or higher
* DOM extension
* GD extension
* MBString extension
* php-font-lib
* php-svg-lib
### Recommendations
* OPcache (OPcache, XCache, APC, etc.): improves performance
* IMagick or GMagick extension: improves image processing performance
Visit the wiki for more information:
https://github.com/dompdf/dompdf/wiki/Requirements
## About Fonts & Character Encoding
PDF documents internally support the following fonts: Helvetica, Times-Roman,
Courier, Zapf-Dingbats, & Symbol. These fonts only support Windows ANSI
encoding. In order for a PDF to display characters that are not available in
Windows ANSI you must supply an external font. Dompdf will embed any referenced
font in the PDF so long as it has been pre-loaded or is accessible to dompdf and
reference in CSS @font-face rules. See the
[font overview](https://github.com/dompdf/dompdf/wiki/About-Fonts-and-Character-Encoding)
for more information on how to use fonts.
The [DejaVu TrueType fonts](http://dejavu-fonts.org) have been pre-installed
to give dompdf decent Unicode character coverage by default. To use the DejaVu
fonts reference the font in your stylesheet, e.g. `body { font-family: DejaVu
Sans; }` (for DejaVu Sans). The following DejaVu 2.34 fonts are available:
DejaVu Sans, DejaVu Serif, and DejaVu Sans Mono.
## Easy Installation
### Install with composer
To install with [Composer](https://getcomposer.org/), simply require the
latest version of this package.
```bash
composer require dompdf/dompdf
```
Make sure that the autoload file from Composer is loaded.
```php
// somewhere early in your project's loading, require the Composer autoloader
// see: http://getcomposer.org/doc/00-intro.md
require 'vendor/autoload.php';
```
### Download and install
Download an archive of dompdf and extract it into the directory where dompdf
will reside
* You can download stable copies of dompdf from
https://github.com/dompdf/dompdf/releases
* Or download a nightly (the latest, unreleased code) from
http://eclecticgeek.com/dompdf
Require dompdf, libraries, and helper functions in your PHP:
```php
// include autoloader
require_once 'dompdf/autoload.inc.php';
```
### Install with git
From the command line, switch to the directory where dompdf will reside and run
the following commands:
```sh
git clone https://github.com/dompdf/dompdf.git
cd dompdf
git clone https://github.com/PhenX/php-font-lib.git lib/php-font-lib
cd lib/php-font-lib
git checkout 0.4
cd ..
git clone https://github.com/PhenX/php-svg-lib.git php-svg-lib
cd php-svg-lib
git checkout v0.1
```
Require dompdf, libraries, and helper functions in your PHP:
```php
// include autoloader
require_once 'dompdf/autoload.inc.php';
```
## Quick Start
Just pass your HTML in to dompdf and stream the output:
```php
// reference the Dompdf namespace
use Dompdf\Dompdf;
// instantiate and use the dompdf class
$dompdf = new Dompdf();
$dompdf->loadHtml('hello world');
// (Optional) Setup the paper size and orientation
$dompdf->setPaper('A4', 'landscape');
// Render the HTML as PDF
$dompdf->render();
// Output the generated PDF to Browser
$dompdf->stream();
```
### Setting Options
Set options during dompdf instantiation:
```php
use Dompdf\Dompdf;
use Dompdf\Options;
$options = new Options();
$options->set('defaultFont', 'Courier');
$dompdf = new Dompdf($options);
```
or at run time
```php
use Dompdf\Dompdf;
$dompdf = new Dompdf();
$dompdf->set_option('defaultFont', 'Courier');
```
See [Dompdf\Options](src/Options.php) for a list of available options.
## Limitations (Known Issues)
* Dompdf is not particularly tolerant to poorly-formed HTML input. To avoid
any unexpected rendering issues you should either enable the built-in HTML5
parser at runtime (`$dompdf->set_option('isHtml5ParserEnabled', true);`)
or run your HTML through a HTML validator/cleaner (such as
[Tidy](http://tidy.sourceforge.net) or the
[W3C Markup Validation Service](http://validator.w3.org)).
* Large files or large tables can take a while to render.
* CSS float is in development and may not produce the desired result
---
[![Donate button](https://www.paypal.com/en_US/i/btn/btn_donate_SM.gif)](http://goo.gl/DSvWf)
*If you find this project useful, please consider making a donation. Any funds donated will be used to help further development on this project.)*

View file

@ -0,0 +1 @@
<0f418c6b>

View file

@ -0,0 +1,28 @@
<?php
/**
* @package dompdf
* @link http://dompdf.github.com/
* @author Benj Carson <benjcarson@digitaljunkies.ca>
* @author Fabien Ménager <fabien.menager@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
*/
/**
* Dompdf autoload function
*
* If you have an existing autoload function, add a call to this function
* from your existing __autoload() implementation.
*
* @param string $class
*/
require_once __DIR__ . '/lib/html5lib/Parser.php';
require_once __DIR__ . '/lib/php-font-lib/src/FontLib/Autoloader.php';
require_once __DIR__ . '/lib/php-svg-lib/src/autoload.php';
/*
* New PHP 5.3.0 namespaced autoloader
*/
require_once __DIR__ . '/src/Autoloader.php';
Dompdf\Autoloader::register();

View file

@ -0,0 +1,44 @@
{
"name": "dompdf/dompdf",
"type": "library",
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
"homepage": "https://github.com/dompdf/dompdf",
"license": "LGPL-2.1",
"authors": [
{
"name": "Fabien Ménager",
"email": "fabien.menager@gmail.com"
},
{
"name": "Brian Sweeney",
"email": "eclecticgeek@gmail.com"
},
{
"name": "Gabriel Bull",
"email": "me@gabrielbull.com"
}
],
"autoload": {
"psr-4" : {
"Dompdf\\" : "src/"
},
"classmap" : ["lib/"]
},
"require": {
"php": ">=5.3.0",
"ext-gd": "*",
"ext-dom": "*",
"ext-mbstring": "*",
"phenx/php-font-lib": "0.5.*",
"phenx/php-svg-lib": "0.2.*"
},
"require-dev": {
"phpunit/phpunit": "4.8.*",
"squizlabs/php_codesniffer": "2.*"
},
"extra": {
"branch-alias": {
"dev-develop": "0.7-dev"
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,344 @@
StartFontMetrics 4.1
Comment Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Mon Jun 23 16:28:00 0:00:00
Comment UniqueID 43048
Comment VMusage 41139 52164
FontName Courier-Bold
FullName Courier Bold
FamilyName Courier
Weight Bold
ItalicAngle 0
IsFixedPitch true
CharacterSet ExtendedRoman
FontBBox -113 -250 749 801
UnderlinePosition -100
UnderlineThickness 50
Version 003.000
Notice Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
EncodingScheme WinAnsiEncoding
CapHeight 562
XHeight 439
Ascender 629
Descender -157
StdHW 84
StdVW 106
StartCharMetrics 317
C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
C 160 ; WX 600 ; N space ; B 0 0 0 0 ;
C 33 ; WX 600 ; N exclam ; B 202 -15 398 572 ;
C 34 ; WX 600 ; N quotedbl ; B 135 277 465 562 ;
C 35 ; WX 600 ; N numbersign ; B 56 -45 544 651 ;
C 36 ; WX 600 ; N dollar ; B 82 -126 519 666 ;
C 37 ; WX 600 ; N percent ; B 5 -15 595 616 ;
C 38 ; WX 600 ; N ampersand ; B 36 -15 546 543 ;
C 146 ; WX 600 ; N quoteright ; B 171 277 423 562 ;
C 40 ; WX 600 ; N parenleft ; B 219 -102 461 616 ;
C 41 ; WX 600 ; N parenright ; B 139 -102 381 616 ;
C 42 ; WX 600 ; N asterisk ; B 91 219 509 601 ;
C 43 ; WX 600 ; N plus ; B 71 39 529 478 ;
C 44 ; WX 600 ; N comma ; B 123 -111 393 174 ;
C 45 ; WX 600 ; N hyphen ; B 100 203 500 313 ;
C 173 ; WX 600 ; N hyphen ; B 100 203 500 313 ;
C 46 ; WX 600 ; N period ; B 192 -15 408 171 ;
C 47 ; WX 600 ; N slash ; B 98 -77 502 626 ;
C 48 ; WX 600 ; N zero ; B 87 -15 513 616 ;
C 49 ; WX 600 ; N one ; B 81 0 539 616 ;
C 50 ; WX 600 ; N two ; B 61 0 499 616 ;
C 51 ; WX 600 ; N three ; B 63 -15 501 616 ;
C 52 ; WX 600 ; N four ; B 53 0 507 616 ;
C 53 ; WX 600 ; N five ; B 70 -15 521 601 ;
C 54 ; WX 600 ; N six ; B 90 -15 521 616 ;
C 55 ; WX 600 ; N seven ; B 55 0 494 601 ;
C 56 ; WX 600 ; N eight ; B 83 -15 517 616 ;
C 57 ; WX 600 ; N nine ; B 79 -15 510 616 ;
C 58 ; WX 600 ; N colon ; B 191 -15 407 425 ;
C 59 ; WX 600 ; N semicolon ; B 123 -111 408 425 ;
C 60 ; WX 600 ; N less ; B 66 15 523 501 ;
C 61 ; WX 600 ; N equal ; B 71 118 529 398 ;
C 62 ; WX 600 ; N greater ; B 77 15 534 501 ;
C 63 ; WX 600 ; N question ; B 98 -14 501 580 ;
C 64 ; WX 600 ; N at ; B 16 -15 584 616 ;
C 65 ; WX 600 ; N A ; B -9 0 609 562 ;
C 66 ; WX 600 ; N B ; B 30 0 573 562 ;
C 67 ; WX 600 ; N C ; B 22 -18 560 580 ;
C 68 ; WX 600 ; N D ; B 30 0 594 562 ;
C 69 ; WX 600 ; N E ; B 25 0 560 562 ;
C 70 ; WX 600 ; N F ; B 39 0 570 562 ;
C 71 ; WX 600 ; N G ; B 22 -18 594 580 ;
C 72 ; WX 600 ; N H ; B 20 0 580 562 ;
C 73 ; WX 600 ; N I ; B 77 0 523 562 ;
C 74 ; WX 600 ; N J ; B 37 -18 601 562 ;
C 75 ; WX 600 ; N K ; B 21 0 599 562 ;
C 76 ; WX 600 ; N L ; B 39 0 578 562 ;
C 77 ; WX 600 ; N M ; B -2 0 602 562 ;
C 78 ; WX 600 ; N N ; B 8 -12 610 562 ;
C 79 ; WX 600 ; N O ; B 22 -18 578 580 ;
C 80 ; WX 600 ; N P ; B 48 0 559 562 ;
C 81 ; WX 600 ; N Q ; B 32 -138 578 580 ;
C 82 ; WX 600 ; N R ; B 24 0 599 562 ;
C 83 ; WX 600 ; N S ; B 47 -22 553 582 ;
C 84 ; WX 600 ; N T ; B 21 0 579 562 ;
C 85 ; WX 600 ; N U ; B 4 -18 596 562 ;
C 86 ; WX 600 ; N V ; B -13 0 613 562 ;
C 87 ; WX 600 ; N W ; B -18 0 618 562 ;
C 88 ; WX 600 ; N X ; B 12 0 588 562 ;
C 89 ; WX 600 ; N Y ; B 12 0 589 562 ;
C 90 ; WX 600 ; N Z ; B 62 0 539 562 ;
C 91 ; WX 600 ; N bracketleft ; B 245 -102 475 616 ;
C 92 ; WX 600 ; N backslash ; B 99 -77 503 626 ;
C 93 ; WX 600 ; N bracketright ; B 125 -102 355 616 ;
C 94 ; WX 600 ; N asciicircum ; B 108 250 492 616 ;
C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ;
C 145 ; WX 600 ; N quoteleft ; B 178 277 428 562 ;
C 97 ; WX 600 ; N a ; B 35 -15 570 454 ;
C 98 ; WX 600 ; N b ; B 0 -15 584 626 ;
C 99 ; WX 600 ; N c ; B 40 -15 545 459 ;
C 100 ; WX 600 ; N d ; B 20 -15 591 626 ;
C 101 ; WX 600 ; N e ; B 40 -15 563 454 ;
C 102 ; WX 600 ; N f ; B 83 0 547 626 ; L i fi ; L l fl ;
C 103 ; WX 600 ; N g ; B 30 -146 580 454 ;
C 104 ; WX 600 ; N h ; B 5 0 592 626 ;
C 105 ; WX 600 ; N i ; B 77 0 523 658 ;
C 106 ; WX 600 ; N j ; B 63 -146 440 658 ;
C 107 ; WX 600 ; N k ; B 20 0 585 626 ;
C 108 ; WX 600 ; N l ; B 77 0 523 626 ;
C 109 ; WX 600 ; N m ; B -22 0 626 454 ;
C 110 ; WX 600 ; N n ; B 18 0 592 454 ;
C 111 ; WX 600 ; N o ; B 30 -15 570 454 ;
C 112 ; WX 600 ; N p ; B -1 -142 570 454 ;
C 113 ; WX 600 ; N q ; B 20 -142 591 454 ;
C 114 ; WX 600 ; N r ; B 47 0 580 454 ;
C 115 ; WX 600 ; N s ; B 68 -17 535 459 ;
C 116 ; WX 600 ; N t ; B 47 -15 532 562 ;
C 117 ; WX 600 ; N u ; B -1 -15 569 439 ;
C 118 ; WX 600 ; N v ; B -1 0 601 439 ;
C 119 ; WX 600 ; N w ; B -18 0 618 439 ;
C 120 ; WX 600 ; N x ; B 6 0 594 439 ;
C 121 ; WX 600 ; N y ; B -4 -142 601 439 ;
C 122 ; WX 600 ; N z ; B 81 0 520 439 ;
C 123 ; WX 600 ; N braceleft ; B 160 -102 464 616 ;
C 124 ; WX 600 ; N bar ; B 255 -250 345 750 ;
C 125 ; WX 600 ; N braceright ; B 136 -102 440 616 ;
C 126 ; WX 600 ; N asciitilde ; B 71 153 530 356 ;
C 161 ; WX 600 ; N exclamdown ; B 202 -146 398 449 ;
C 162 ; WX 600 ; N cent ; B 66 -49 518 614 ;
C 163 ; WX 600 ; N sterling ; B 72 -28 558 611 ;
C -1 ; WX 600 ; N fraction ; B 25 -60 576 661 ;
C 165 ; WX 600 ; N yen ; B 10 0 590 562 ;
C 131 ; WX 600 ; N florin ; B -30 -131 572 616 ;
C 167 ; WX 600 ; N section ; B 83 -70 517 580 ;
C 164 ; WX 600 ; N currency ; B 54 49 546 517 ;
C 39 ; WX 600 ; N quotesingle ; B 227 277 373 562 ;
C 147 ; WX 600 ; N quotedblleft ; B 71 277 535 562 ;
C 171 ; WX 600 ; N guillemotleft ; B 8 70 553 446 ;
C 139 ; WX 600 ; N guilsinglleft ; B 141 70 459 446 ;
C 155 ; WX 600 ; N guilsinglright ; B 141 70 459 446 ;
C -1 ; WX 600 ; N fi ; B 12 0 593 626 ;
C -1 ; WX 600 ; N fl ; B 12 0 593 626 ;
C 150 ; WX 600 ; N endash ; B 65 203 535 313 ;
C 134 ; WX 600 ; N dagger ; B 106 -70 494 580 ;
C 135 ; WX 600 ; N daggerdbl ; B 106 -70 494 580 ;
C 183 ; WX 600 ; N periodcentered ; B 196 165 404 351 ;
C 182 ; WX 600 ; N paragraph ; B 6 -70 576 580 ;
C 149 ; WX 600 ; N bullet ; B 140 132 460 430 ;
C 130 ; WX 600 ; N quotesinglbase ; B 175 -142 427 143 ;
C 132 ; WX 600 ; N quotedblbase ; B 65 -142 529 143 ;
C 148 ; WX 600 ; N quotedblright ; B 61 277 525 562 ;
C 187 ; WX 600 ; N guillemotright ; B 47 70 592 446 ;
C 133 ; WX 600 ; N ellipsis ; B 26 -15 574 116 ;
C 137 ; WX 600 ; N perthousand ; B -113 -15 713 616 ;
C 191 ; WX 600 ; N questiondown ; B 99 -146 502 449 ;
C 96 ; WX 600 ; N grave ; B 132 508 395 661 ;
C 180 ; WX 600 ; N acute ; B 205 508 468 661 ;
C 136 ; WX 600 ; N circumflex ; B 103 483 497 657 ;
C 152 ; WX 600 ; N tilde ; B 89 493 512 636 ;
C 175 ; WX 600 ; N macron ; B 88 505 512 585 ;
C -1 ; WX 600 ; N breve ; B 83 468 517 631 ;
C -1 ; WX 600 ; N dotaccent ; B 230 498 370 638 ;
C 168 ; WX 600 ; N dieresis ; B 128 498 472 638 ;
C -1 ; WX 600 ; N ring ; B 198 481 402 678 ;
C 184 ; WX 600 ; N cedilla ; B 205 -206 387 0 ;
C -1 ; WX 600 ; N hungarumlaut ; B 68 488 588 661 ;
C -1 ; WX 600 ; N ogonek ; B 169 -199 400 0 ;
C -1 ; WX 600 ; N caron ; B 103 493 497 667 ;
C 151 ; WX 600 ; N emdash ; B -10 203 610 313 ;
C 198 ; WX 600 ; N AE ; B -29 0 602 562 ;
C 170 ; WX 600 ; N ordfeminine ; B 147 196 453 580 ;
C -1 ; WX 600 ; N Lslash ; B 39 0 578 562 ;
C 216 ; WX 600 ; N Oslash ; B 22 -22 578 584 ;
C 140 ; WX 600 ; N OE ; B -25 0 595 562 ;
C 186 ; WX 600 ; N ordmasculine ; B 147 196 453 580 ;
C 230 ; WX 600 ; N ae ; B -4 -15 601 454 ;
C -1 ; WX 600 ; N dotlessi ; B 77 0 523 439 ;
C -1 ; WX 600 ; N lslash ; B 77 0 523 626 ;
C 248 ; WX 600 ; N oslash ; B 30 -24 570 463 ;
C 156 ; WX 600 ; N oe ; B -18 -15 611 454 ;
C 223 ; WX 600 ; N germandbls ; B 22 -15 596 626 ;
C 207 ; WX 600 ; N Idieresis ; B 77 0 523 761 ;
C 233 ; WX 600 ; N eacute ; B 40 -15 563 661 ;
C -1 ; WX 600 ; N abreve ; B 35 -15 570 661 ;
C -1 ; WX 600 ; N uhungarumlaut ; B -1 -15 628 661 ;
C -1 ; WX 600 ; N ecaron ; B 40 -15 563 667 ;
C 159 ; WX 600 ; N Ydieresis ; B 12 0 589 761 ;
C 247 ; WX 600 ; N divide ; B 71 16 529 500 ;
C 221 ; WX 600 ; N Yacute ; B 12 0 589 784 ;
C 194 ; WX 600 ; N Acircumflex ; B -9 0 609 780 ;
C 225 ; WX 600 ; N aacute ; B 35 -15 570 661 ;
C 219 ; WX 600 ; N Ucircumflex ; B 4 -18 596 780 ;
C 253 ; WX 600 ; N yacute ; B -4 -142 601 661 ;
C -1 ; WX 600 ; N scommaaccent ; B 68 -250 535 459 ;
C 234 ; WX 600 ; N ecircumflex ; B 40 -15 563 657 ;
C -1 ; WX 600 ; N Uring ; B 4 -18 596 801 ;
C 220 ; WX 600 ; N Udieresis ; B 4 -18 596 761 ;
C -1 ; WX 600 ; N aogonek ; B 35 -199 586 454 ;
C 218 ; WX 600 ; N Uacute ; B 4 -18 596 784 ;
C -1 ; WX 600 ; N uogonek ; B -1 -199 585 439 ;
C 203 ; WX 600 ; N Edieresis ; B 25 0 560 761 ;
C -1 ; WX 600 ; N Dcroat ; B 30 0 594 562 ;
C -1 ; WX 600 ; N commaaccent ; B 205 -250 397 -57 ;
C 169 ; WX 600 ; N copyright ; B 0 -18 600 580 ;
C -1 ; WX 600 ; N Emacron ; B 25 0 560 708 ;
C -1 ; WX 600 ; N ccaron ; B 40 -15 545 667 ;
C 229 ; WX 600 ; N aring ; B 35 -15 570 678 ;
C -1 ; WX 600 ; N Ncommaaccent ; B 8 -250 610 562 ;
C -1 ; WX 600 ; N lacute ; B 77 0 523 801 ;
C 224 ; WX 600 ; N agrave ; B 35 -15 570 661 ;
C -1 ; WX 600 ; N Tcommaaccent ; B 21 -250 579 562 ;
C -1 ; WX 600 ; N Cacute ; B 22 -18 560 784 ;
C 227 ; WX 600 ; N atilde ; B 35 -15 570 636 ;
C -1 ; WX 600 ; N Edotaccent ; B 25 0 560 761 ;
C 154 ; WX 600 ; N scaron ; B 68 -17 535 667 ;
C -1 ; WX 600 ; N scedilla ; B 68 -206 535 459 ;
C 237 ; WX 600 ; N iacute ; B 77 0 523 661 ;
C -1 ; WX 600 ; N lozenge ; B 66 0 534 740 ;
C -1 ; WX 600 ; N Rcaron ; B 24 0 599 790 ;
C -1 ; WX 600 ; N Gcommaaccent ; B 22 -250 594 580 ;
C 251 ; WX 600 ; N ucircumflex ; B -1 -15 569 657 ;
C 226 ; WX 600 ; N acircumflex ; B 35 -15 570 657 ;
C -1 ; WX 600 ; N Amacron ; B -9 0 609 708 ;
C -1 ; WX 600 ; N rcaron ; B 47 0 580 667 ;
C 231 ; WX 600 ; N ccedilla ; B 40 -206 545 459 ;
C -1 ; WX 600 ; N Zdotaccent ; B 62 0 539 761 ;
C 222 ; WX 600 ; N Thorn ; B 48 0 557 562 ;
C -1 ; WX 600 ; N Omacron ; B 22 -18 578 708 ;
C -1 ; WX 600 ; N Racute ; B 24 0 599 784 ;
C -1 ; WX 600 ; N Sacute ; B 47 -22 553 784 ;
C -1 ; WX 600 ; N dcaron ; B 20 -15 727 626 ;
C -1 ; WX 600 ; N Umacron ; B 4 -18 596 708 ;
C -1 ; WX 600 ; N uring ; B -1 -15 569 678 ;
C 179 ; WX 600 ; N threesuperior ; B 138 222 433 616 ;
C 210 ; WX 600 ; N Ograve ; B 22 -18 578 784 ;
C 192 ; WX 600 ; N Agrave ; B -9 0 609 784 ;
C -1 ; WX 600 ; N Abreve ; B -9 0 609 784 ;
C 215 ; WX 600 ; N multiply ; B 81 39 520 478 ;
C 250 ; WX 600 ; N uacute ; B -1 -15 569 661 ;
C -1 ; WX 600 ; N Tcaron ; B 21 0 579 790 ;
C -1 ; WX 600 ; N partialdiff ; B 63 -38 537 728 ;
C 255 ; WX 600 ; N ydieresis ; B -4 -142 601 638 ;
C -1 ; WX 600 ; N Nacute ; B 8 -12 610 784 ;
C 238 ; WX 600 ; N icircumflex ; B 73 0 523 657 ;
C 202 ; WX 600 ; N Ecircumflex ; B 25 0 560 780 ;
C 228 ; WX 600 ; N adieresis ; B 35 -15 570 638 ;
C 235 ; WX 600 ; N edieresis ; B 40 -15 563 638 ;
C -1 ; WX 600 ; N cacute ; B 40 -15 545 661 ;
C -1 ; WX 600 ; N nacute ; B 18 0 592 661 ;
C -1 ; WX 600 ; N umacron ; B -1 -15 569 585 ;
C -1 ; WX 600 ; N Ncaron ; B 8 -12 610 790 ;
C 205 ; WX 600 ; N Iacute ; B 77 0 523 784 ;
C 177 ; WX 600 ; N plusminus ; B 71 24 529 515 ;
C 166 ; WX 600 ; N brokenbar ; B 255 -175 345 675 ;
C 174 ; WX 600 ; N registered ; B 0 -18 600 580 ;
C -1 ; WX 600 ; N Gbreve ; B 22 -18 594 784 ;
C -1 ; WX 600 ; N Idotaccent ; B 77 0 523 761 ;
C -1 ; WX 600 ; N summation ; B 15 -10 586 706 ;
C 200 ; WX 600 ; N Egrave ; B 25 0 560 784 ;
C -1 ; WX 600 ; N racute ; B 47 0 580 661 ;
C -1 ; WX 600 ; N omacron ; B 30 -15 570 585 ;
C -1 ; WX 600 ; N Zacute ; B 62 0 539 784 ;
C 142 ; WX 600 ; N Zcaron ; B 62 0 539 790 ;
C -1 ; WX 600 ; N greaterequal ; B 26 0 523 696 ;
C 208 ; WX 600 ; N Eth ; B 30 0 594 562 ;
C 199 ; WX 600 ; N Ccedilla ; B 22 -206 560 580 ;
C -1 ; WX 600 ; N lcommaaccent ; B 77 -250 523 626 ;
C -1 ; WX 600 ; N tcaron ; B 47 -15 532 703 ;
C -1 ; WX 600 ; N eogonek ; B 40 -199 563 454 ;
C -1 ; WX 600 ; N Uogonek ; B 4 -199 596 562 ;
C 193 ; WX 600 ; N Aacute ; B -9 0 609 784 ;
C 196 ; WX 600 ; N Adieresis ; B -9 0 609 761 ;
C 232 ; WX 600 ; N egrave ; B 40 -15 563 661 ;
C -1 ; WX 600 ; N zacute ; B 81 0 520 661 ;
C -1 ; WX 600 ; N iogonek ; B 77 -199 523 658 ;
C 211 ; WX 600 ; N Oacute ; B 22 -18 578 784 ;
C 243 ; WX 600 ; N oacute ; B 30 -15 570 661 ;
C -1 ; WX 600 ; N amacron ; B 35 -15 570 585 ;
C -1 ; WX 600 ; N sacute ; B 68 -17 535 661 ;
C 239 ; WX 600 ; N idieresis ; B 77 0 523 618 ;
C 212 ; WX 600 ; N Ocircumflex ; B 22 -18 578 780 ;
C 217 ; WX 600 ; N Ugrave ; B 4 -18 596 784 ;
C -1 ; WX 600 ; N Delta ; B 6 0 594 688 ;
C 254 ; WX 600 ; N thorn ; B -14 -142 570 626 ;
C 178 ; WX 600 ; N twosuperior ; B 143 230 436 616 ;
C 214 ; WX 600 ; N Odieresis ; B 22 -18 578 761 ;
C 181 ; WX 600 ; N mu ; B -1 -142 569 439 ;
C 236 ; WX 600 ; N igrave ; B 77 0 523 661 ;
C -1 ; WX 600 ; N ohungarumlaut ; B 30 -15 668 661 ;
C -1 ; WX 600 ; N Eogonek ; B 25 -199 576 562 ;
C -1 ; WX 600 ; N dcroat ; B 20 -15 591 626 ;
C 190 ; WX 600 ; N threequarters ; B -47 -60 648 661 ;
C -1 ; WX 600 ; N Scedilla ; B 47 -206 553 582 ;
C -1 ; WX 600 ; N lcaron ; B 77 0 597 626 ;
C -1 ; WX 600 ; N Kcommaaccent ; B 21 -250 599 562 ;
C -1 ; WX 600 ; N Lacute ; B 39 0 578 784 ;
C 153 ; WX 600 ; N trademark ; B -9 230 749 562 ;
C -1 ; WX 600 ; N edotaccent ; B 40 -15 563 638 ;
C 204 ; WX 600 ; N Igrave ; B 77 0 523 784 ;
C -1 ; WX 600 ; N Imacron ; B 77 0 523 708 ;
C -1 ; WX 600 ; N Lcaron ; B 39 0 637 562 ;
C 189 ; WX 600 ; N onehalf ; B -47 -60 648 661 ;
C -1 ; WX 600 ; N lessequal ; B 26 0 523 696 ;
C 244 ; WX 600 ; N ocircumflex ; B 30 -15 570 657 ;
C 241 ; WX 600 ; N ntilde ; B 18 0 592 636 ;
C -1 ; WX 600 ; N Uhungarumlaut ; B 4 -18 638 784 ;
C 201 ; WX 600 ; N Eacute ; B 25 0 560 784 ;
C -1 ; WX 600 ; N emacron ; B 40 -15 563 585 ;
C -1 ; WX 600 ; N gbreve ; B 30 -146 580 661 ;
C 188 ; WX 600 ; N onequarter ; B -56 -60 656 661 ;
C 138 ; WX 600 ; N Scaron ; B 47 -22 553 790 ;
C -1 ; WX 600 ; N Scommaaccent ; B 47 -250 553 582 ;
C -1 ; WX 600 ; N Ohungarumlaut ; B 22 -18 628 784 ;
C 176 ; WX 600 ; N degree ; B 86 243 474 616 ;
C 242 ; WX 600 ; N ograve ; B 30 -15 570 661 ;
C -1 ; WX 600 ; N Ccaron ; B 22 -18 560 790 ;
C 249 ; WX 600 ; N ugrave ; B -1 -15 569 661 ;
C -1 ; WX 600 ; N radical ; B -19 -104 473 778 ;
C -1 ; WX 600 ; N Dcaron ; B 30 0 594 790 ;
C -1 ; WX 600 ; N rcommaaccent ; B 47 -250 580 454 ;
C 209 ; WX 600 ; N Ntilde ; B 8 -12 610 759 ;
C 245 ; WX 600 ; N otilde ; B 30 -15 570 636 ;
C -1 ; WX 600 ; N Rcommaaccent ; B 24 -250 599 562 ;
C -1 ; WX 600 ; N Lcommaaccent ; B 39 -250 578 562 ;
C 195 ; WX 600 ; N Atilde ; B -9 0 609 759 ;
C -1 ; WX 600 ; N Aogonek ; B -9 -199 625 562 ;
C 197 ; WX 600 ; N Aring ; B -9 0 609 801 ;
C 213 ; WX 600 ; N Otilde ; B 22 -18 578 759 ;
C -1 ; WX 600 ; N zdotaccent ; B 81 0 520 638 ;
C -1 ; WX 600 ; N Ecaron ; B 25 0 560 790 ;
C -1 ; WX 600 ; N Iogonek ; B 77 -199 523 562 ;
C -1 ; WX 600 ; N kcommaaccent ; B 20 -250 585 626 ;
C -1 ; WX 600 ; N minus ; B 71 203 529 313 ;
C 206 ; WX 600 ; N Icircumflex ; B 77 0 523 780 ;
C -1 ; WX 600 ; N ncaron ; B 18 0 592 667 ;
C -1 ; WX 600 ; N tcommaaccent ; B 47 -250 532 562 ;
C 172 ; WX 600 ; N logicalnot ; B 71 103 529 413 ;
C 246 ; WX 600 ; N odieresis ; B 30 -15 570 638 ;
C 252 ; WX 600 ; N udieresis ; B -1 -15 569 638 ;
C -1 ; WX 600 ; N notequal ; B 12 -47 537 563 ;
C -1 ; WX 600 ; N gcommaaccent ; B 30 -146 580 714 ;
C 240 ; WX 600 ; N eth ; B 58 -27 543 626 ;
C 158 ; WX 600 ; N zcaron ; B 81 0 520 667 ;
C -1 ; WX 600 ; N ncommaaccent ; B 18 -250 592 454 ;
C 185 ; WX 600 ; N onesuperior ; B 153 230 447 616 ;
C -1 ; WX 600 ; N imacron ; B 77 0 523 585 ;
C 128 ; WX 600 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
EndFontMetrics

View file

@ -0,0 +1,344 @@
StartFontMetrics 4.1
Comment Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Mon Jun 23 16:28:46 0:00:00
Comment UniqueID 43049
Comment VMusage 17529 79244
FontName Courier-BoldOblique
FullName Courier Bold Oblique
FamilyName Courier
Weight Bold
ItalicAngle -12
IsFixedPitch true
CharacterSet ExtendedRoman
FontBBox -57 -250 869 801
UnderlinePosition -100
UnderlineThickness 50
Version 3
Notice Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
EncodingScheme WinAnsiEncoding
CapHeight 562
XHeight 439
Ascender 629
Descender -157
StdHW 84
StdVW 106
StartCharMetrics 317
C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
C 160 ; WX 600 ; N space ; B 0 0 0 0 ;
C 33 ; WX 600 ; N exclam ; B 215 -15 495 572 ;
C 34 ; WX 600 ; N quotedbl ; B 211 277 585 562 ;
C 35 ; WX 600 ; N numbersign ; B 88 -45 641 651 ;
C 36 ; WX 600 ; N dollar ; B 87 -126 630 666 ;
C 37 ; WX 600 ; N percent ; B 101 -15 625 616 ;
C 38 ; WX 600 ; N ampersand ; B 61 -15 595 543 ;
C 146 ; WX 600 ; N quoteright ; B 229 277 543 562 ;
C 40 ; WX 600 ; N parenleft ; B 265 -102 592 616 ;
C 41 ; WX 600 ; N parenright ; B 117 -102 444 616 ;
C 42 ; WX 600 ; N asterisk ; B 179 219 598 601 ;
C 43 ; WX 600 ; N plus ; B 114 39 596 478 ;
C 44 ; WX 600 ; N comma ; B 99 -111 430 174 ;
C 45 ; WX 600 ; N hyphen ; B 143 203 567 313 ;
C 173 ; WX 600 ; N hyphen ; B 143 203 567 313 ;
C 46 ; WX 600 ; N period ; B 206 -15 427 171 ;
C 47 ; WX 600 ; N slash ; B 90 -77 626 626 ;
C 48 ; WX 600 ; N zero ; B 135 -15 593 616 ;
C 49 ; WX 600 ; N one ; B 93 0 562 616 ;
C 50 ; WX 600 ; N two ; B 61 0 594 616 ;
C 51 ; WX 600 ; N three ; B 71 -15 571 616 ;
C 52 ; WX 600 ; N four ; B 81 0 559 616 ;
C 53 ; WX 600 ; N five ; B 77 -15 621 601 ;
C 54 ; WX 600 ; N six ; B 135 -15 652 616 ;
C 55 ; WX 600 ; N seven ; B 147 0 622 601 ;
C 56 ; WX 600 ; N eight ; B 115 -15 604 616 ;
C 57 ; WX 600 ; N nine ; B 75 -15 592 616 ;
C 58 ; WX 600 ; N colon ; B 205 -15 480 425 ;
C 59 ; WX 600 ; N semicolon ; B 99 -111 481 425 ;
C 60 ; WX 600 ; N less ; B 120 15 613 501 ;
C 61 ; WX 600 ; N equal ; B 96 118 614 398 ;
C 62 ; WX 600 ; N greater ; B 97 15 589 501 ;
C 63 ; WX 600 ; N question ; B 183 -14 592 580 ;
C 64 ; WX 600 ; N at ; B 65 -15 642 616 ;
C 65 ; WX 600 ; N A ; B -9 0 632 562 ;
C 66 ; WX 600 ; N B ; B 30 0 630 562 ;
C 67 ; WX 600 ; N C ; B 74 -18 675 580 ;
C 68 ; WX 600 ; N D ; B 30 0 664 562 ;
C 69 ; WX 600 ; N E ; B 25 0 670 562 ;
C 70 ; WX 600 ; N F ; B 39 0 684 562 ;
C 71 ; WX 600 ; N G ; B 74 -18 675 580 ;
C 72 ; WX 600 ; N H ; B 20 0 700 562 ;
C 73 ; WX 600 ; N I ; B 77 0 643 562 ;
C 74 ; WX 600 ; N J ; B 58 -18 721 562 ;
C 75 ; WX 600 ; N K ; B 21 0 692 562 ;
C 76 ; WX 600 ; N L ; B 39 0 636 562 ;
C 77 ; WX 600 ; N M ; B -2 0 722 562 ;
C 78 ; WX 600 ; N N ; B 8 -12 730 562 ;
C 79 ; WX 600 ; N O ; B 74 -18 645 580 ;
C 80 ; WX 600 ; N P ; B 48 0 643 562 ;
C 81 ; WX 600 ; N Q ; B 83 -138 636 580 ;
C 82 ; WX 600 ; N R ; B 24 0 617 562 ;
C 83 ; WX 600 ; N S ; B 54 -22 673 582 ;
C 84 ; WX 600 ; N T ; B 86 0 679 562 ;
C 85 ; WX 600 ; N U ; B 101 -18 716 562 ;
C 86 ; WX 600 ; N V ; B 84 0 733 562 ;
C 87 ; WX 600 ; N W ; B 79 0 738 562 ;
C 88 ; WX 600 ; N X ; B 12 0 690 562 ;
C 89 ; WX 600 ; N Y ; B 109 0 709 562 ;
C 90 ; WX 600 ; N Z ; B 62 0 637 562 ;
C 91 ; WX 600 ; N bracketleft ; B 223 -102 606 616 ;
C 92 ; WX 600 ; N backslash ; B 222 -77 496 626 ;
C 93 ; WX 600 ; N bracketright ; B 103 -102 486 616 ;
C 94 ; WX 600 ; N asciicircum ; B 171 250 556 616 ;
C 95 ; WX 600 ; N underscore ; B -27 -125 585 -75 ;
C 145 ; WX 600 ; N quoteleft ; B 297 277 487 562 ;
C 97 ; WX 600 ; N a ; B 61 -15 593 454 ;
C 98 ; WX 600 ; N b ; B 13 -15 636 626 ;
C 99 ; WX 600 ; N c ; B 81 -15 631 459 ;
C 100 ; WX 600 ; N d ; B 60 -15 645 626 ;
C 101 ; WX 600 ; N e ; B 81 -15 605 454 ;
C 102 ; WX 600 ; N f ; B 83 0 677 626 ; L i fi ; L l fl ;
C 103 ; WX 600 ; N g ; B 40 -146 674 454 ;
C 104 ; WX 600 ; N h ; B 18 0 615 626 ;
C 105 ; WX 600 ; N i ; B 77 0 546 658 ;
C 106 ; WX 600 ; N j ; B 36 -146 580 658 ;
C 107 ; WX 600 ; N k ; B 33 0 643 626 ;
C 108 ; WX 600 ; N l ; B 77 0 546 626 ;
C 109 ; WX 600 ; N m ; B -22 0 649 454 ;
C 110 ; WX 600 ; N n ; B 18 0 615 454 ;
C 111 ; WX 600 ; N o ; B 71 -15 622 454 ;
C 112 ; WX 600 ; N p ; B -32 -142 622 454 ;
C 113 ; WX 600 ; N q ; B 60 -142 685 454 ;
C 114 ; WX 600 ; N r ; B 47 0 655 454 ;
C 115 ; WX 600 ; N s ; B 66 -17 608 459 ;
C 116 ; WX 600 ; N t ; B 118 -15 567 562 ;
C 117 ; WX 600 ; N u ; B 70 -15 592 439 ;
C 118 ; WX 600 ; N v ; B 70 0 695 439 ;
C 119 ; WX 600 ; N w ; B 53 0 712 439 ;
C 120 ; WX 600 ; N x ; B 6 0 671 439 ;
C 121 ; WX 600 ; N y ; B -21 -142 695 439 ;
C 122 ; WX 600 ; N z ; B 81 0 614 439 ;
C 123 ; WX 600 ; N braceleft ; B 203 -102 595 616 ;
C 124 ; WX 600 ; N bar ; B 201 -250 505 750 ;
C 125 ; WX 600 ; N braceright ; B 114 -102 506 616 ;
C 126 ; WX 600 ; N asciitilde ; B 120 153 590 356 ;
C 161 ; WX 600 ; N exclamdown ; B 196 -146 477 449 ;
C 162 ; WX 600 ; N cent ; B 121 -49 605 614 ;
C 163 ; WX 600 ; N sterling ; B 106 -28 650 611 ;
C -1 ; WX 600 ; N fraction ; B 22 -60 708 661 ;
C 165 ; WX 600 ; N yen ; B 98 0 710 562 ;
C 131 ; WX 600 ; N florin ; B -57 -131 702 616 ;
C 167 ; WX 600 ; N section ; B 74 -70 620 580 ;
C 164 ; WX 600 ; N currency ; B 77 49 644 517 ;
C 39 ; WX 600 ; N quotesingle ; B 303 277 493 562 ;
C 147 ; WX 600 ; N quotedblleft ; B 190 277 594 562 ;
C 171 ; WX 600 ; N guillemotleft ; B 62 70 639 446 ;
C 139 ; WX 600 ; N guilsinglleft ; B 195 70 545 446 ;
C 155 ; WX 600 ; N guilsinglright ; B 165 70 514 446 ;
C -1 ; WX 600 ; N fi ; B 12 0 644 626 ;
C -1 ; WX 600 ; N fl ; B 12 0 644 626 ;
C 150 ; WX 600 ; N endash ; B 108 203 602 313 ;
C 134 ; WX 600 ; N dagger ; B 175 -70 586 580 ;
C 135 ; WX 600 ; N daggerdbl ; B 121 -70 587 580 ;
C 183 ; WX 600 ; N periodcentered ; B 248 165 461 351 ;
C 182 ; WX 600 ; N paragraph ; B 61 -70 700 580 ;
C 149 ; WX 600 ; N bullet ; B 196 132 523 430 ;
C 130 ; WX 600 ; N quotesinglbase ; B 144 -142 458 143 ;
C 132 ; WX 600 ; N quotedblbase ; B 34 -142 560 143 ;
C 148 ; WX 600 ; N quotedblright ; B 119 277 645 562 ;
C 187 ; WX 600 ; N guillemotright ; B 71 70 647 446 ;
C 133 ; WX 600 ; N ellipsis ; B 35 -15 587 116 ;
C 137 ; WX 600 ; N perthousand ; B -45 -15 743 616 ;
C 191 ; WX 600 ; N questiondown ; B 100 -146 509 449 ;
C 96 ; WX 600 ; N grave ; B 272 508 503 661 ;
C 180 ; WX 600 ; N acute ; B 312 508 609 661 ;
C 136 ; WX 600 ; N circumflex ; B 212 483 607 657 ;
C 152 ; WX 600 ; N tilde ; B 199 493 643 636 ;
C 175 ; WX 600 ; N macron ; B 195 505 637 585 ;
C -1 ; WX 600 ; N breve ; B 217 468 652 631 ;
C -1 ; WX 600 ; N dotaccent ; B 348 498 493 638 ;
C 168 ; WX 600 ; N dieresis ; B 246 498 595 638 ;
C -1 ; WX 600 ; N ring ; B 319 481 528 678 ;
C 184 ; WX 600 ; N cedilla ; B 168 -206 368 0 ;
C -1 ; WX 600 ; N hungarumlaut ; B 171 488 729 661 ;
C -1 ; WX 600 ; N ogonek ; B 143 -199 367 0 ;
C -1 ; WX 600 ; N caron ; B 238 493 633 667 ;
C 151 ; WX 600 ; N emdash ; B 33 203 677 313 ;
C 198 ; WX 600 ; N AE ; B -29 0 708 562 ;
C 170 ; WX 600 ; N ordfeminine ; B 188 196 526 580 ;
C -1 ; WX 600 ; N Lslash ; B 39 0 636 562 ;
C 216 ; WX 600 ; N Oslash ; B 48 -22 673 584 ;
C 140 ; WX 600 ; N OE ; B 26 0 701 562 ;
C 186 ; WX 600 ; N ordmasculine ; B 188 196 543 580 ;
C 230 ; WX 600 ; N ae ; B 21 -15 652 454 ;
C -1 ; WX 600 ; N dotlessi ; B 77 0 546 439 ;
C -1 ; WX 600 ; N lslash ; B 77 0 587 626 ;
C 248 ; WX 600 ; N oslash ; B 54 -24 638 463 ;
C 156 ; WX 600 ; N oe ; B 18 -15 662 454 ;
C 223 ; WX 600 ; N germandbls ; B 22 -15 629 626 ;
C 207 ; WX 600 ; N Idieresis ; B 77 0 643 761 ;
C 233 ; WX 600 ; N eacute ; B 81 -15 609 661 ;
C -1 ; WX 600 ; N abreve ; B 61 -15 658 661 ;
C -1 ; WX 600 ; N uhungarumlaut ; B 70 -15 769 661 ;
C -1 ; WX 600 ; N ecaron ; B 81 -15 633 667 ;
C 159 ; WX 600 ; N Ydieresis ; B 109 0 709 761 ;
C 247 ; WX 600 ; N divide ; B 114 16 596 500 ;
C 221 ; WX 600 ; N Yacute ; B 109 0 709 784 ;
C 194 ; WX 600 ; N Acircumflex ; B -9 0 632 780 ;
C 225 ; WX 600 ; N aacute ; B 61 -15 609 661 ;
C 219 ; WX 600 ; N Ucircumflex ; B 101 -18 716 780 ;
C 253 ; WX 600 ; N yacute ; B -21 -142 695 661 ;
C -1 ; WX 600 ; N scommaaccent ; B 66 -250 608 459 ;
C 234 ; WX 600 ; N ecircumflex ; B 81 -15 607 657 ;
C -1 ; WX 600 ; N Uring ; B 101 -18 716 801 ;
C 220 ; WX 600 ; N Udieresis ; B 101 -18 716 761 ;
C -1 ; WX 600 ; N aogonek ; B 61 -199 593 454 ;
C 218 ; WX 600 ; N Uacute ; B 101 -18 716 784 ;
C -1 ; WX 600 ; N uogonek ; B 70 -199 592 439 ;
C 203 ; WX 600 ; N Edieresis ; B 25 0 670 761 ;
C -1 ; WX 600 ; N Dcroat ; B 30 0 664 562 ;
C -1 ; WX 600 ; N commaaccent ; B 151 -250 385 -57 ;
C 169 ; WX 600 ; N copyright ; B 53 -18 667 580 ;
C -1 ; WX 600 ; N Emacron ; B 25 0 670 708 ;
C -1 ; WX 600 ; N ccaron ; B 81 -15 633 667 ;
C 229 ; WX 600 ; N aring ; B 61 -15 593 678 ;
C -1 ; WX 600 ; N Ncommaaccent ; B 8 -250 730 562 ;
C -1 ; WX 600 ; N lacute ; B 77 0 639 801 ;
C 224 ; WX 600 ; N agrave ; B 61 -15 593 661 ;
C -1 ; WX 600 ; N Tcommaaccent ; B 86 -250 679 562 ;
C -1 ; WX 600 ; N Cacute ; B 74 -18 675 784 ;
C 227 ; WX 600 ; N atilde ; B 61 -15 643 636 ;
C -1 ; WX 600 ; N Edotaccent ; B 25 0 670 761 ;
C 154 ; WX 600 ; N scaron ; B 66 -17 633 667 ;
C -1 ; WX 600 ; N scedilla ; B 66 -206 608 459 ;
C 237 ; WX 600 ; N iacute ; B 77 0 609 661 ;
C -1 ; WX 600 ; N lozenge ; B 145 0 614 740 ;
C -1 ; WX 600 ; N Rcaron ; B 24 0 659 790 ;
C -1 ; WX 600 ; N Gcommaaccent ; B 74 -250 675 580 ;
C 251 ; WX 600 ; N ucircumflex ; B 70 -15 597 657 ;
C 226 ; WX 600 ; N acircumflex ; B 61 -15 607 657 ;
C -1 ; WX 600 ; N Amacron ; B -9 0 633 708 ;
C -1 ; WX 600 ; N rcaron ; B 47 0 655 667 ;
C 231 ; WX 600 ; N ccedilla ; B 81 -206 631 459 ;
C -1 ; WX 600 ; N Zdotaccent ; B 62 0 637 761 ;
C 222 ; WX 600 ; N Thorn ; B 48 0 620 562 ;
C -1 ; WX 600 ; N Omacron ; B 74 -18 663 708 ;
C -1 ; WX 600 ; N Racute ; B 24 0 665 784 ;
C -1 ; WX 600 ; N Sacute ; B 54 -22 673 784 ;
C -1 ; WX 600 ; N dcaron ; B 60 -15 861 626 ;
C -1 ; WX 600 ; N Umacron ; B 101 -18 716 708 ;
C -1 ; WX 600 ; N uring ; B 70 -15 592 678 ;
C 179 ; WX 600 ; N threesuperior ; B 193 222 526 616 ;
C 210 ; WX 600 ; N Ograve ; B 74 -18 645 784 ;
C 192 ; WX 600 ; N Agrave ; B -9 0 632 784 ;
C -1 ; WX 600 ; N Abreve ; B -9 0 684 784 ;
C 215 ; WX 600 ; N multiply ; B 104 39 606 478 ;
C 250 ; WX 600 ; N uacute ; B 70 -15 599 661 ;
C -1 ; WX 600 ; N Tcaron ; B 86 0 679 790 ;
C -1 ; WX 600 ; N partialdiff ; B 91 -38 627 728 ;
C 255 ; WX 600 ; N ydieresis ; B -21 -142 695 638 ;
C -1 ; WX 600 ; N Nacute ; B 8 -12 730 784 ;
C 238 ; WX 600 ; N icircumflex ; B 77 0 577 657 ;
C 202 ; WX 600 ; N Ecircumflex ; B 25 0 670 780 ;
C 228 ; WX 600 ; N adieresis ; B 61 -15 595 638 ;
C 235 ; WX 600 ; N edieresis ; B 81 -15 605 638 ;
C -1 ; WX 600 ; N cacute ; B 81 -15 649 661 ;
C -1 ; WX 600 ; N nacute ; B 18 0 639 661 ;
C -1 ; WX 600 ; N umacron ; B 70 -15 637 585 ;
C -1 ; WX 600 ; N Ncaron ; B 8 -12 730 790 ;
C 205 ; WX 600 ; N Iacute ; B 77 0 643 784 ;
C 177 ; WX 600 ; N plusminus ; B 76 24 614 515 ;
C 166 ; WX 600 ; N brokenbar ; B 217 -175 489 675 ;
C 174 ; WX 600 ; N registered ; B 53 -18 667 580 ;
C -1 ; WX 600 ; N Gbreve ; B 74 -18 684 784 ;
C -1 ; WX 600 ; N Idotaccent ; B 77 0 643 761 ;
C -1 ; WX 600 ; N summation ; B 15 -10 672 706 ;
C 200 ; WX 600 ; N Egrave ; B 25 0 670 784 ;
C -1 ; WX 600 ; N racute ; B 47 0 655 661 ;
C -1 ; WX 600 ; N omacron ; B 71 -15 637 585 ;
C -1 ; WX 600 ; N Zacute ; B 62 0 665 784 ;
C 142 ; WX 600 ; N Zcaron ; B 62 0 659 790 ;
C -1 ; WX 600 ; N greaterequal ; B 26 0 627 696 ;
C 208 ; WX 600 ; N Eth ; B 30 0 664 562 ;
C 199 ; WX 600 ; N Ccedilla ; B 74 -206 675 580 ;
C -1 ; WX 600 ; N lcommaaccent ; B 77 -250 546 626 ;
C -1 ; WX 600 ; N tcaron ; B 118 -15 627 703 ;
C -1 ; WX 600 ; N eogonek ; B 81 -199 605 454 ;
C -1 ; WX 600 ; N Uogonek ; B 101 -199 716 562 ;
C 193 ; WX 600 ; N Aacute ; B -9 0 655 784 ;
C 196 ; WX 600 ; N Adieresis ; B -9 0 632 761 ;
C 232 ; WX 600 ; N egrave ; B 81 -15 605 661 ;
C -1 ; WX 600 ; N zacute ; B 81 0 614 661 ;
C -1 ; WX 600 ; N iogonek ; B 77 -199 546 658 ;
C 211 ; WX 600 ; N Oacute ; B 74 -18 645 784 ;
C 243 ; WX 600 ; N oacute ; B 71 -15 649 661 ;
C -1 ; WX 600 ; N amacron ; B 61 -15 637 585 ;
C -1 ; WX 600 ; N sacute ; B 66 -17 609 661 ;
C 239 ; WX 600 ; N idieresis ; B 77 0 561 618 ;
C 212 ; WX 600 ; N Ocircumflex ; B 74 -18 645 780 ;
C 217 ; WX 600 ; N Ugrave ; B 101 -18 716 784 ;
C -1 ; WX 600 ; N Delta ; B 6 0 594 688 ;
C 254 ; WX 600 ; N thorn ; B -32 -142 622 626 ;
C 178 ; WX 600 ; N twosuperior ; B 191 230 542 616 ;
C 214 ; WX 600 ; N Odieresis ; B 74 -18 645 761 ;
C 181 ; WX 600 ; N mu ; B 49 -142 592 439 ;
C 236 ; WX 600 ; N igrave ; B 77 0 546 661 ;
C -1 ; WX 600 ; N ohungarumlaut ; B 71 -15 809 661 ;
C -1 ; WX 600 ; N Eogonek ; B 25 -199 670 562 ;
C -1 ; WX 600 ; N dcroat ; B 60 -15 712 626 ;
C 190 ; WX 600 ; N threequarters ; B 8 -60 699 661 ;
C -1 ; WX 600 ; N Scedilla ; B 54 -206 673 582 ;
C -1 ; WX 600 ; N lcaron ; B 77 0 731 626 ;
C -1 ; WX 600 ; N Kcommaaccent ; B 21 -250 692 562 ;
C -1 ; WX 600 ; N Lacute ; B 39 0 636 784 ;
C 153 ; WX 600 ; N trademark ; B 86 230 869 562 ;
C -1 ; WX 600 ; N edotaccent ; B 81 -15 605 638 ;
C 204 ; WX 600 ; N Igrave ; B 77 0 643 784 ;
C -1 ; WX 600 ; N Imacron ; B 77 0 663 708 ;
C -1 ; WX 600 ; N Lcaron ; B 39 0 757 562 ;
C 189 ; WX 600 ; N onehalf ; B 22 -60 716 661 ;
C -1 ; WX 600 ; N lessequal ; B 26 0 671 696 ;
C 244 ; WX 600 ; N ocircumflex ; B 71 -15 622 657 ;
C 241 ; WX 600 ; N ntilde ; B 18 0 643 636 ;
C -1 ; WX 600 ; N Uhungarumlaut ; B 101 -18 805 784 ;
C 201 ; WX 600 ; N Eacute ; B 25 0 670 784 ;
C -1 ; WX 600 ; N emacron ; B 81 -15 637 585 ;
C -1 ; WX 600 ; N gbreve ; B 40 -146 674 661 ;
C 188 ; WX 600 ; N onequarter ; B 13 -60 707 661 ;
C 138 ; WX 600 ; N Scaron ; B 54 -22 689 790 ;
C -1 ; WX 600 ; N Scommaaccent ; B 54 -250 673 582 ;
C -1 ; WX 600 ; N Ohungarumlaut ; B 74 -18 795 784 ;
C 176 ; WX 600 ; N degree ; B 173 243 570 616 ;
C 242 ; WX 600 ; N ograve ; B 71 -15 622 661 ;
C -1 ; WX 600 ; N Ccaron ; B 74 -18 689 790 ;
C 249 ; WX 600 ; N ugrave ; B 70 -15 592 661 ;
C -1 ; WX 600 ; N radical ; B 67 -104 635 778 ;
C -1 ; WX 600 ; N Dcaron ; B 30 0 664 790 ;
C -1 ; WX 600 ; N rcommaaccent ; B 47 -250 655 454 ;
C 209 ; WX 600 ; N Ntilde ; B 8 -12 730 759 ;
C 245 ; WX 600 ; N otilde ; B 71 -15 643 636 ;
C -1 ; WX 600 ; N Rcommaaccent ; B 24 -250 617 562 ;
C -1 ; WX 600 ; N Lcommaaccent ; B 39 -250 636 562 ;
C 195 ; WX 600 ; N Atilde ; B -9 0 669 759 ;
C -1 ; WX 600 ; N Aogonek ; B -9 -199 632 562 ;
C 197 ; WX 600 ; N Aring ; B -9 0 632 801 ;
C 213 ; WX 600 ; N Otilde ; B 74 -18 669 759 ;
C -1 ; WX 600 ; N zdotaccent ; B 81 0 614 638 ;
C -1 ; WX 600 ; N Ecaron ; B 25 0 670 790 ;
C -1 ; WX 600 ; N Iogonek ; B 77 -199 643 562 ;
C -1 ; WX 600 ; N kcommaaccent ; B 33 -250 643 626 ;
C -1 ; WX 600 ; N minus ; B 114 203 596 313 ;
C 206 ; WX 600 ; N Icircumflex ; B 77 0 643 780 ;
C -1 ; WX 600 ; N ncaron ; B 18 0 633 667 ;
C -1 ; WX 600 ; N tcommaaccent ; B 118 -250 567 562 ;
C 172 ; WX 600 ; N logicalnot ; B 135 103 617 413 ;
C 246 ; WX 600 ; N odieresis ; B 71 -15 622 638 ;
C 252 ; WX 600 ; N udieresis ; B 70 -15 595 638 ;
C -1 ; WX 600 ; N notequal ; B 30 -47 626 563 ;
C -1 ; WX 600 ; N gcommaaccent ; B 40 -146 674 714 ;
C 240 ; WX 600 ; N eth ; B 93 -27 661 626 ;
C 158 ; WX 600 ; N zcaron ; B 81 0 643 667 ;
C -1 ; WX 600 ; N ncommaaccent ; B 18 -250 615 454 ;
C 185 ; WX 600 ; N onesuperior ; B 212 230 514 616 ;
C -1 ; WX 600 ; N imacron ; B 77 0 575 585 ;
C 128 ; WX 600 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
EndFontMetrics

View file

@ -0,0 +1,344 @@
StartFontMetrics 4.1
Comment Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 0:00:00 17:37:52 1997
Comment UniqueID 43051
Comment VMusage 16248 75829
FontName Courier-Oblique
FullName Courier Oblique
FamilyName Courier
Weight Medium
ItalicAngle -12
IsFixedPitch true
CharacterSet ExtendedRoman
FontBBox -27 -250 849 805
UnderlinePosition -100
UnderlineThickness 50
Version 003.000
Notice Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
EncodingScheme WinAnsiEncoding
CapHeight 562
XHeight 426
Ascender 629
Descender -157
StdHW 51
StdVW 51
StartCharMetrics 317
C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
C 160 ; WX 600 ; N space ; B 0 0 0 0 ;
C 33 ; WX 600 ; N exclam ; B 243 -15 464 572 ;
C 34 ; WX 600 ; N quotedbl ; B 273 328 532 562 ;
C 35 ; WX 600 ; N numbersign ; B 133 -32 596 639 ;
C 36 ; WX 600 ; N dollar ; B 108 -126 596 662 ;
C 37 ; WX 600 ; N percent ; B 134 -15 599 622 ;
C 38 ; WX 600 ; N ampersand ; B 87 -15 580 543 ;
C 146 ; WX 600 ; N quoteright ; B 283 328 495 562 ;
C 40 ; WX 600 ; N parenleft ; B 313 -108 572 622 ;
C 41 ; WX 600 ; N parenright ; B 137 -108 396 622 ;
C 42 ; WX 600 ; N asterisk ; B 212 257 580 607 ;
C 43 ; WX 600 ; N plus ; B 129 44 580 470 ;
C 44 ; WX 600 ; N comma ; B 157 -112 370 122 ;
C 45 ; WX 600 ; N hyphen ; B 152 231 558 285 ;
C 173 ; WX 600 ; N hyphen ; B 152 231 558 285 ;
C 46 ; WX 600 ; N period ; B 238 -15 382 109 ;
C 47 ; WX 600 ; N slash ; B 112 -80 604 629 ;
C 48 ; WX 600 ; N zero ; B 154 -15 575 622 ;
C 49 ; WX 600 ; N one ; B 98 0 515 622 ;
C 50 ; WX 600 ; N two ; B 70 0 568 622 ;
C 51 ; WX 600 ; N three ; B 82 -15 538 622 ;
C 52 ; WX 600 ; N four ; B 108 0 541 622 ;
C 53 ; WX 600 ; N five ; B 99 -15 589 607 ;
C 54 ; WX 600 ; N six ; B 155 -15 629 622 ;
C 55 ; WX 600 ; N seven ; B 182 0 612 607 ;
C 56 ; WX 600 ; N eight ; B 132 -15 588 622 ;
C 57 ; WX 600 ; N nine ; B 93 -15 574 622 ;
C 58 ; WX 600 ; N colon ; B 238 -15 441 385 ;
C 59 ; WX 600 ; N semicolon ; B 157 -112 441 385 ;
C 60 ; WX 600 ; N less ; B 96 42 610 472 ;
C 61 ; WX 600 ; N equal ; B 109 138 600 376 ;
C 62 ; WX 600 ; N greater ; B 85 42 599 472 ;
C 63 ; WX 600 ; N question ; B 222 -15 583 572 ;
C 64 ; WX 600 ; N at ; B 127 -15 582 622 ;
C 65 ; WX 600 ; N A ; B 3 0 607 562 ;
C 66 ; WX 600 ; N B ; B 43 0 616 562 ;
C 67 ; WX 600 ; N C ; B 93 -18 655 580 ;
C 68 ; WX 600 ; N D ; B 43 0 645 562 ;
C 69 ; WX 600 ; N E ; B 53 0 660 562 ;
C 70 ; WX 600 ; N F ; B 53 0 660 562 ;
C 71 ; WX 600 ; N G ; B 83 -18 645 580 ;
C 72 ; WX 600 ; N H ; B 32 0 687 562 ;
C 73 ; WX 600 ; N I ; B 96 0 623 562 ;
C 74 ; WX 600 ; N J ; B 52 -18 685 562 ;
C 75 ; WX 600 ; N K ; B 38 0 671 562 ;
C 76 ; WX 600 ; N L ; B 47 0 607 562 ;
C 77 ; WX 600 ; N M ; B 4 0 715 562 ;
C 78 ; WX 600 ; N N ; B 7 -13 712 562 ;
C 79 ; WX 600 ; N O ; B 94 -18 625 580 ;
C 80 ; WX 600 ; N P ; B 79 0 644 562 ;
C 81 ; WX 600 ; N Q ; B 95 -138 625 580 ;
C 82 ; WX 600 ; N R ; B 38 0 598 562 ;
C 83 ; WX 600 ; N S ; B 76 -20 650 580 ;
C 84 ; WX 600 ; N T ; B 108 0 665 562 ;
C 85 ; WX 600 ; N U ; B 125 -18 702 562 ;
C 86 ; WX 600 ; N V ; B 105 -13 723 562 ;
C 87 ; WX 600 ; N W ; B 106 -13 722 562 ;
C 88 ; WX 600 ; N X ; B 23 0 675 562 ;
C 89 ; WX 600 ; N Y ; B 133 0 695 562 ;
C 90 ; WX 600 ; N Z ; B 86 0 610 562 ;
C 91 ; WX 600 ; N bracketleft ; B 246 -108 574 622 ;
C 92 ; WX 600 ; N backslash ; B 249 -80 468 629 ;
C 93 ; WX 600 ; N bracketright ; B 135 -108 463 622 ;
C 94 ; WX 600 ; N asciicircum ; B 175 354 587 622 ;
C 95 ; WX 600 ; N underscore ; B -27 -125 584 -75 ;
C 145 ; WX 600 ; N quoteleft ; B 343 328 457 562 ;
C 97 ; WX 600 ; N a ; B 76 -15 569 441 ;
C 98 ; WX 600 ; N b ; B 29 -15 625 629 ;
C 99 ; WX 600 ; N c ; B 106 -15 608 441 ;
C 100 ; WX 600 ; N d ; B 85 -15 640 629 ;
C 101 ; WX 600 ; N e ; B 106 -15 598 441 ;
C 102 ; WX 600 ; N f ; B 114 0 662 629 ; L i fi ; L l fl ;
C 103 ; WX 600 ; N g ; B 61 -157 657 441 ;
C 104 ; WX 600 ; N h ; B 33 0 592 629 ;
C 105 ; WX 600 ; N i ; B 95 0 515 657 ;
C 106 ; WX 600 ; N j ; B 52 -157 550 657 ;
C 107 ; WX 600 ; N k ; B 58 0 633 629 ;
C 108 ; WX 600 ; N l ; B 95 0 515 629 ;
C 109 ; WX 600 ; N m ; B -5 0 615 441 ;
C 110 ; WX 600 ; N n ; B 26 0 585 441 ;
C 111 ; WX 600 ; N o ; B 102 -15 588 441 ;
C 112 ; WX 600 ; N p ; B -24 -157 605 441 ;
C 113 ; WX 600 ; N q ; B 85 -157 682 441 ;
C 114 ; WX 600 ; N r ; B 60 0 636 441 ;
C 115 ; WX 600 ; N s ; B 78 -15 584 441 ;
C 116 ; WX 600 ; N t ; B 167 -15 561 561 ;
C 117 ; WX 600 ; N u ; B 101 -15 572 426 ;
C 118 ; WX 600 ; N v ; B 90 -10 681 426 ;
C 119 ; WX 600 ; N w ; B 76 -10 695 426 ;
C 120 ; WX 600 ; N x ; B 20 0 655 426 ;
C 121 ; WX 600 ; N y ; B -4 -157 683 426 ;
C 122 ; WX 600 ; N z ; B 99 0 593 426 ;
C 123 ; WX 600 ; N braceleft ; B 233 -108 569 622 ;
C 124 ; WX 600 ; N bar ; B 222 -250 485 750 ;
C 125 ; WX 600 ; N braceright ; B 140 -108 477 622 ;
C 126 ; WX 600 ; N asciitilde ; B 116 197 600 320 ;
C 161 ; WX 600 ; N exclamdown ; B 225 -157 445 430 ;
C 162 ; WX 600 ; N cent ; B 151 -49 588 614 ;
C 163 ; WX 600 ; N sterling ; B 124 -21 621 611 ;
C -1 ; WX 600 ; N fraction ; B 84 -57 646 665 ;
C 165 ; WX 600 ; N yen ; B 120 0 693 562 ;
C 131 ; WX 600 ; N florin ; B -26 -143 671 622 ;
C 167 ; WX 600 ; N section ; B 104 -78 590 580 ;
C 164 ; WX 600 ; N currency ; B 94 58 628 506 ;
C 39 ; WX 600 ; N quotesingle ; B 345 328 460 562 ;
C 147 ; WX 600 ; N quotedblleft ; B 262 328 541 562 ;
C 171 ; WX 600 ; N guillemotleft ; B 92 70 652 446 ;
C 139 ; WX 600 ; N guilsinglleft ; B 204 70 540 446 ;
C 155 ; WX 600 ; N guilsinglright ; B 170 70 506 446 ;
C -1 ; WX 600 ; N fi ; B 3 0 619 629 ;
C -1 ; WX 600 ; N fl ; B 3 0 619 629 ;
C 150 ; WX 600 ; N endash ; B 124 231 586 285 ;
C 134 ; WX 600 ; N dagger ; B 217 -78 546 580 ;
C 135 ; WX 600 ; N daggerdbl ; B 163 -78 546 580 ;
C 183 ; WX 600 ; N periodcentered ; B 275 189 434 327 ;
C 182 ; WX 600 ; N paragraph ; B 100 -78 630 562 ;
C 149 ; WX 600 ; N bullet ; B 224 130 485 383 ;
C 130 ; WX 600 ; N quotesinglbase ; B 185 -134 397 100 ;
C 132 ; WX 600 ; N quotedblbase ; B 115 -134 478 100 ;
C 148 ; WX 600 ; N quotedblright ; B 213 328 576 562 ;
C 187 ; WX 600 ; N guillemotright ; B 58 70 618 446 ;
C 133 ; WX 600 ; N ellipsis ; B 46 -15 575 111 ;
C 137 ; WX 600 ; N perthousand ; B 59 -15 627 622 ;
C 191 ; WX 600 ; N questiondown ; B 105 -157 466 430 ;
C 96 ; WX 600 ; N grave ; B 294 497 484 672 ;
C 180 ; WX 600 ; N acute ; B 348 497 612 672 ;
C 136 ; WX 600 ; N circumflex ; B 229 477 581 654 ;
C 152 ; WX 600 ; N tilde ; B 212 489 629 606 ;
C 175 ; WX 600 ; N macron ; B 232 525 600 565 ;
C -1 ; WX 600 ; N breve ; B 279 501 576 609 ;
C -1 ; WX 600 ; N dotaccent ; B 373 537 478 640 ;
C 168 ; WX 600 ; N dieresis ; B 272 537 579 640 ;
C -1 ; WX 600 ; N ring ; B 332 463 500 627 ;
C 184 ; WX 600 ; N cedilla ; B 197 -151 344 10 ;
C -1 ; WX 600 ; N hungarumlaut ; B 239 497 683 672 ;
C -1 ; WX 600 ; N ogonek ; B 189 -172 377 4 ;
C -1 ; WX 600 ; N caron ; B 262 492 614 669 ;
C 151 ; WX 600 ; N emdash ; B 49 231 661 285 ;
C 198 ; WX 600 ; N AE ; B 3 0 655 562 ;
C 170 ; WX 600 ; N ordfeminine ; B 209 249 512 580 ;
C -1 ; WX 600 ; N Lslash ; B 47 0 607 562 ;
C 216 ; WX 600 ; N Oslash ; B 94 -80 625 629 ;
C 140 ; WX 600 ; N OE ; B 59 0 672 562 ;
C 186 ; WX 600 ; N ordmasculine ; B 210 249 535 580 ;
C 230 ; WX 600 ; N ae ; B 41 -15 626 441 ;
C -1 ; WX 600 ; N dotlessi ; B 95 0 515 426 ;
C -1 ; WX 600 ; N lslash ; B 95 0 587 629 ;
C 248 ; WX 600 ; N oslash ; B 102 -80 588 506 ;
C 156 ; WX 600 ; N oe ; B 54 -15 615 441 ;
C 223 ; WX 600 ; N germandbls ; B 48 -15 617 629 ;
C 207 ; WX 600 ; N Idieresis ; B 96 0 623 753 ;
C 233 ; WX 600 ; N eacute ; B 106 -15 612 672 ;
C -1 ; WX 600 ; N abreve ; B 76 -15 576 609 ;
C -1 ; WX 600 ; N uhungarumlaut ; B 101 -15 723 672 ;
C -1 ; WX 600 ; N ecaron ; B 106 -15 614 669 ;
C 159 ; WX 600 ; N Ydieresis ; B 133 0 695 753 ;
C 247 ; WX 600 ; N divide ; B 136 48 573 467 ;
C 221 ; WX 600 ; N Yacute ; B 133 0 695 805 ;
C 194 ; WX 600 ; N Acircumflex ; B 3 0 607 787 ;
C 225 ; WX 600 ; N aacute ; B 76 -15 612 672 ;
C 219 ; WX 600 ; N Ucircumflex ; B 125 -18 702 787 ;
C 253 ; WX 600 ; N yacute ; B -4 -157 683 672 ;
C -1 ; WX 600 ; N scommaaccent ; B 78 -250 584 441 ;
C 234 ; WX 600 ; N ecircumflex ; B 106 -15 598 654 ;
C -1 ; WX 600 ; N Uring ; B 125 -18 702 760 ;
C 220 ; WX 600 ; N Udieresis ; B 125 -18 702 753 ;
C -1 ; WX 600 ; N aogonek ; B 76 -172 569 441 ;
C 218 ; WX 600 ; N Uacute ; B 125 -18 702 805 ;
C -1 ; WX 600 ; N uogonek ; B 101 -172 572 426 ;
C 203 ; WX 600 ; N Edieresis ; B 53 0 660 753 ;
C -1 ; WX 600 ; N Dcroat ; B 43 0 645 562 ;
C -1 ; WX 600 ; N commaaccent ; B 145 -250 323 -58 ;
C 169 ; WX 600 ; N copyright ; B 53 -18 667 580 ;
C -1 ; WX 600 ; N Emacron ; B 53 0 660 698 ;
C -1 ; WX 600 ; N ccaron ; B 106 -15 614 669 ;
C 229 ; WX 600 ; N aring ; B 76 -15 569 627 ;
C -1 ; WX 600 ; N Ncommaaccent ; B 7 -250 712 562 ;
C -1 ; WX 600 ; N lacute ; B 95 0 640 805 ;
C 224 ; WX 600 ; N agrave ; B 76 -15 569 672 ;
C -1 ; WX 600 ; N Tcommaaccent ; B 108 -250 665 562 ;
C -1 ; WX 600 ; N Cacute ; B 93 -18 655 805 ;
C 227 ; WX 600 ; N atilde ; B 76 -15 629 606 ;
C -1 ; WX 600 ; N Edotaccent ; B 53 0 660 753 ;
C 154 ; WX 600 ; N scaron ; B 78 -15 614 669 ;
C -1 ; WX 600 ; N scedilla ; B 78 -151 584 441 ;
C 237 ; WX 600 ; N iacute ; B 95 0 612 672 ;
C -1 ; WX 600 ; N lozenge ; B 94 0 519 706 ;
C -1 ; WX 600 ; N Rcaron ; B 38 0 642 802 ;
C -1 ; WX 600 ; N Gcommaaccent ; B 83 -250 645 580 ;
C 251 ; WX 600 ; N ucircumflex ; B 101 -15 572 654 ;
C 226 ; WX 600 ; N acircumflex ; B 76 -15 581 654 ;
C -1 ; WX 600 ; N Amacron ; B 3 0 607 698 ;
C -1 ; WX 600 ; N rcaron ; B 60 0 636 669 ;
C 231 ; WX 600 ; N ccedilla ; B 106 -151 614 441 ;
C -1 ; WX 600 ; N Zdotaccent ; B 86 0 610 753 ;
C 222 ; WX 600 ; N Thorn ; B 79 0 606 562 ;
C -1 ; WX 600 ; N Omacron ; B 94 -18 628 698 ;
C -1 ; WX 600 ; N Racute ; B 38 0 670 805 ;
C -1 ; WX 600 ; N Sacute ; B 76 -20 650 805 ;
C -1 ; WX 600 ; N dcaron ; B 85 -15 849 629 ;
C -1 ; WX 600 ; N Umacron ; B 125 -18 702 698 ;
C -1 ; WX 600 ; N uring ; B 101 -15 572 627 ;
C 179 ; WX 600 ; N threesuperior ; B 213 240 501 622 ;
C 210 ; WX 600 ; N Ograve ; B 94 -18 625 805 ;
C 192 ; WX 600 ; N Agrave ; B 3 0 607 805 ;
C -1 ; WX 600 ; N Abreve ; B 3 0 607 732 ;
C 215 ; WX 600 ; N multiply ; B 103 43 607 470 ;
C 250 ; WX 600 ; N uacute ; B 101 -15 602 672 ;
C -1 ; WX 600 ; N Tcaron ; B 108 0 665 802 ;
C -1 ; WX 600 ; N partialdiff ; B 45 -38 546 710 ;
C 255 ; WX 600 ; N ydieresis ; B -4 -157 683 620 ;
C -1 ; WX 600 ; N Nacute ; B 7 -13 712 805 ;
C 238 ; WX 600 ; N icircumflex ; B 95 0 551 654 ;
C 202 ; WX 600 ; N Ecircumflex ; B 53 0 660 787 ;
C 228 ; WX 600 ; N adieresis ; B 76 -15 575 620 ;
C 235 ; WX 600 ; N edieresis ; B 106 -15 598 620 ;
C -1 ; WX 600 ; N cacute ; B 106 -15 612 672 ;
C -1 ; WX 600 ; N nacute ; B 26 0 602 672 ;
C -1 ; WX 600 ; N umacron ; B 101 -15 600 565 ;
C -1 ; WX 600 ; N Ncaron ; B 7 -13 712 802 ;
C 205 ; WX 600 ; N Iacute ; B 96 0 640 805 ;
C 177 ; WX 600 ; N plusminus ; B 96 44 594 558 ;
C 166 ; WX 600 ; N brokenbar ; B 238 -175 469 675 ;
C 174 ; WX 600 ; N registered ; B 53 -18 667 580 ;
C -1 ; WX 600 ; N Gbreve ; B 83 -18 645 732 ;
C -1 ; WX 600 ; N Idotaccent ; B 96 0 623 753 ;
C -1 ; WX 600 ; N summation ; B 15 -10 670 706 ;
C 200 ; WX 600 ; N Egrave ; B 53 0 660 805 ;
C -1 ; WX 600 ; N racute ; B 60 0 636 672 ;
C -1 ; WX 600 ; N omacron ; B 102 -15 600 565 ;
C -1 ; WX 600 ; N Zacute ; B 86 0 670 805 ;
C 142 ; WX 600 ; N Zcaron ; B 86 0 642 802 ;
C -1 ; WX 600 ; N greaterequal ; B 98 0 594 710 ;
C 208 ; WX 600 ; N Eth ; B 43 0 645 562 ;
C 199 ; WX 600 ; N Ccedilla ; B 93 -151 658 580 ;
C -1 ; WX 600 ; N lcommaaccent ; B 95 -250 515 629 ;
C -1 ; WX 600 ; N tcaron ; B 167 -15 587 717 ;
C -1 ; WX 600 ; N eogonek ; B 106 -172 598 441 ;
C -1 ; WX 600 ; N Uogonek ; B 124 -172 702 562 ;
C 193 ; WX 600 ; N Aacute ; B 3 0 660 805 ;
C 196 ; WX 600 ; N Adieresis ; B 3 0 607 753 ;
C 232 ; WX 600 ; N egrave ; B 106 -15 598 672 ;
C -1 ; WX 600 ; N zacute ; B 99 0 612 672 ;
C -1 ; WX 600 ; N iogonek ; B 95 -172 515 657 ;
C 211 ; WX 600 ; N Oacute ; B 94 -18 640 805 ;
C 243 ; WX 600 ; N oacute ; B 102 -15 612 672 ;
C -1 ; WX 600 ; N amacron ; B 76 -15 600 565 ;
C -1 ; WX 600 ; N sacute ; B 78 -15 612 672 ;
C 239 ; WX 600 ; N idieresis ; B 95 0 545 620 ;
C 212 ; WX 600 ; N Ocircumflex ; B 94 -18 625 787 ;
C 217 ; WX 600 ; N Ugrave ; B 125 -18 702 805 ;
C -1 ; WX 600 ; N Delta ; B 6 0 598 688 ;
C 254 ; WX 600 ; N thorn ; B -24 -157 605 629 ;
C 178 ; WX 600 ; N twosuperior ; B 230 249 535 622 ;
C 214 ; WX 600 ; N Odieresis ; B 94 -18 625 753 ;
C 181 ; WX 600 ; N mu ; B 72 -157 572 426 ;
C 236 ; WX 600 ; N igrave ; B 95 0 515 672 ;
C -1 ; WX 600 ; N ohungarumlaut ; B 102 -15 723 672 ;
C -1 ; WX 600 ; N Eogonek ; B 53 -172 660 562 ;
C -1 ; WX 600 ; N dcroat ; B 85 -15 704 629 ;
C 190 ; WX 600 ; N threequarters ; B 73 -56 659 666 ;
C -1 ; WX 600 ; N Scedilla ; B 76 -151 650 580 ;
C -1 ; WX 600 ; N lcaron ; B 95 0 667 629 ;
C -1 ; WX 600 ; N Kcommaaccent ; B 38 -250 671 562 ;
C -1 ; WX 600 ; N Lacute ; B 47 0 607 805 ;
C 153 ; WX 600 ; N trademark ; B 75 263 742 562 ;
C -1 ; WX 600 ; N edotaccent ; B 106 -15 598 620 ;
C 204 ; WX 600 ; N Igrave ; B 96 0 623 805 ;
C -1 ; WX 600 ; N Imacron ; B 96 0 628 698 ;
C -1 ; WX 600 ; N Lcaron ; B 47 0 632 562 ;
C 189 ; WX 600 ; N onehalf ; B 65 -57 669 665 ;
C -1 ; WX 600 ; N lessequal ; B 98 0 645 710 ;
C 244 ; WX 600 ; N ocircumflex ; B 102 -15 588 654 ;
C 241 ; WX 600 ; N ntilde ; B 26 0 629 606 ;
C -1 ; WX 600 ; N Uhungarumlaut ; B 125 -18 761 805 ;
C 201 ; WX 600 ; N Eacute ; B 53 0 670 805 ;
C -1 ; WX 600 ; N emacron ; B 106 -15 600 565 ;
C -1 ; WX 600 ; N gbreve ; B 61 -157 657 609 ;
C 188 ; WX 600 ; N onequarter ; B 65 -57 674 665 ;
C 138 ; WX 600 ; N Scaron ; B 76 -20 672 802 ;
C -1 ; WX 600 ; N Scommaaccent ; B 76 -250 650 580 ;
C -1 ; WX 600 ; N Ohungarumlaut ; B 94 -18 751 805 ;
C 176 ; WX 600 ; N degree ; B 214 269 576 622 ;
C 242 ; WX 600 ; N ograve ; B 102 -15 588 672 ;
C -1 ; WX 600 ; N Ccaron ; B 93 -18 672 802 ;
C 249 ; WX 600 ; N ugrave ; B 101 -15 572 672 ;
C -1 ; WX 600 ; N radical ; B 85 -15 765 792 ;
C -1 ; WX 600 ; N Dcaron ; B 43 0 645 802 ;
C -1 ; WX 600 ; N rcommaaccent ; B 60 -250 636 441 ;
C 209 ; WX 600 ; N Ntilde ; B 7 -13 712 729 ;
C 245 ; WX 600 ; N otilde ; B 102 -15 629 606 ;
C -1 ; WX 600 ; N Rcommaaccent ; B 38 -250 598 562 ;
C -1 ; WX 600 ; N Lcommaaccent ; B 47 -250 607 562 ;
C 195 ; WX 600 ; N Atilde ; B 3 0 655 729 ;
C -1 ; WX 600 ; N Aogonek ; B 3 -172 607 562 ;
C 197 ; WX 600 ; N Aring ; B 3 0 607 750 ;
C 213 ; WX 600 ; N Otilde ; B 94 -18 655 729 ;
C -1 ; WX 600 ; N zdotaccent ; B 99 0 593 620 ;
C -1 ; WX 600 ; N Ecaron ; B 53 0 660 802 ;
C -1 ; WX 600 ; N Iogonek ; B 96 -172 623 562 ;
C -1 ; WX 600 ; N kcommaaccent ; B 58 -250 633 629 ;
C -1 ; WX 600 ; N minus ; B 129 232 580 283 ;
C 206 ; WX 600 ; N Icircumflex ; B 96 0 623 787 ;
C -1 ; WX 600 ; N ncaron ; B 26 0 614 669 ;
C -1 ; WX 600 ; N tcommaaccent ; B 165 -250 561 561 ;
C 172 ; WX 600 ; N logicalnot ; B 155 108 591 369 ;
C 246 ; WX 600 ; N odieresis ; B 102 -15 588 620 ;
C 252 ; WX 600 ; N udieresis ; B 101 -15 575 620 ;
C -1 ; WX 600 ; N notequal ; B 43 -16 621 529 ;
C -1 ; WX 600 ; N gcommaaccent ; B 61 -157 657 708 ;
C 240 ; WX 600 ; N eth ; B 102 -15 639 629 ;
C 158 ; WX 600 ; N zcaron ; B 99 0 624 669 ;
C -1 ; WX 600 ; N ncommaaccent ; B 26 -250 585 441 ;
C 185 ; WX 600 ; N onesuperior ; B 231 249 491 622 ;
C -1 ; WX 600 ; N imacron ; B 95 0 543 565 ;
C 128 ; WX 600 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
EndFontMetrics

View file

@ -0,0 +1,344 @@
StartFontMetrics 4.1
Comment Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 1 17:27:09 1997
Comment UniqueID 43050
Comment VMusage 39754 50779
FontName Courier
FullName Courier
FamilyName Courier
Weight Medium
ItalicAngle 0
IsFixedPitch true
CharacterSet ExtendedRoman
FontBBox -23 -250 715 805
UnderlinePosition -100
UnderlineThickness 50
Version 003.000
Notice Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
EncodingScheme WinAnsiEncoding
CapHeight 562
XHeight 426
Ascender 629
Descender -157
StdHW 51
StdVW 51
StartCharMetrics 317
C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
C 160 ; WX 600 ; N space ; B 0 0 0 0 ;
C 33 ; WX 600 ; N exclam ; B 236 -15 364 572 ;
C 34 ; WX 600 ; N quotedbl ; B 187 328 413 562 ;
C 35 ; WX 600 ; N numbersign ; B 93 -32 507 639 ;
C 36 ; WX 600 ; N dollar ; B 105 -126 496 662 ;
C 37 ; WX 600 ; N percent ; B 81 -15 518 622 ;
C 38 ; WX 600 ; N ampersand ; B 63 -15 538 543 ;
C 146 ; WX 600 ; N quoteright ; B 213 328 376 562 ;
C 40 ; WX 600 ; N parenleft ; B 269 -108 440 622 ;
C 41 ; WX 600 ; N parenright ; B 160 -108 331 622 ;
C 42 ; WX 600 ; N asterisk ; B 116 257 484 607 ;
C 43 ; WX 600 ; N plus ; B 80 44 520 470 ;
C 44 ; WX 600 ; N comma ; B 181 -112 344 122 ;
C 45 ; WX 600 ; N hyphen ; B 103 231 497 285 ;
C 173 ; WX 600 ; N hyphen ; B 103 231 497 285 ;
C 46 ; WX 600 ; N period ; B 229 -15 371 109 ;
C 47 ; WX 600 ; N slash ; B 125 -80 475 629 ;
C 48 ; WX 600 ; N zero ; B 106 -15 494 622 ;
C 49 ; WX 600 ; N one ; B 96 0 505 622 ;
C 50 ; WX 600 ; N two ; B 70 0 471 622 ;
C 51 ; WX 600 ; N three ; B 75 -15 466 622 ;
C 52 ; WX 600 ; N four ; B 78 0 500 622 ;
C 53 ; WX 600 ; N five ; B 92 -15 497 607 ;
C 54 ; WX 600 ; N six ; B 111 -15 497 622 ;
C 55 ; WX 600 ; N seven ; B 82 0 483 607 ;
C 56 ; WX 600 ; N eight ; B 102 -15 498 622 ;
C 57 ; WX 600 ; N nine ; B 96 -15 489 622 ;
C 58 ; WX 600 ; N colon ; B 229 -15 371 385 ;
C 59 ; WX 600 ; N semicolon ; B 181 -112 371 385 ;
C 60 ; WX 600 ; N less ; B 41 42 519 472 ;
C 61 ; WX 600 ; N equal ; B 80 138 520 376 ;
C 62 ; WX 600 ; N greater ; B 66 42 544 472 ;
C 63 ; WX 600 ; N question ; B 129 -15 492 572 ;
C 64 ; WX 600 ; N at ; B 77 -15 533 622 ;
C 65 ; WX 600 ; N A ; B 3 0 597 562 ;
C 66 ; WX 600 ; N B ; B 43 0 559 562 ;
C 67 ; WX 600 ; N C ; B 41 -18 540 580 ;
C 68 ; WX 600 ; N D ; B 43 0 574 562 ;
C 69 ; WX 600 ; N E ; B 53 0 550 562 ;
C 70 ; WX 600 ; N F ; B 53 0 545 562 ;
C 71 ; WX 600 ; N G ; B 31 -18 575 580 ;
C 72 ; WX 600 ; N H ; B 32 0 568 562 ;
C 73 ; WX 600 ; N I ; B 96 0 504 562 ;
C 74 ; WX 600 ; N J ; B 34 -18 566 562 ;
C 75 ; WX 600 ; N K ; B 38 0 582 562 ;
C 76 ; WX 600 ; N L ; B 47 0 554 562 ;
C 77 ; WX 600 ; N M ; B 4 0 596 562 ;
C 78 ; WX 600 ; N N ; B 7 -13 593 562 ;
C 79 ; WX 600 ; N O ; B 43 -18 557 580 ;
C 80 ; WX 600 ; N P ; B 79 0 558 562 ;
C 81 ; WX 600 ; N Q ; B 43 -138 557 580 ;
C 82 ; WX 600 ; N R ; B 38 0 588 562 ;
C 83 ; WX 600 ; N S ; B 72 -20 529 580 ;
C 84 ; WX 600 ; N T ; B 38 0 563 562 ;
C 85 ; WX 600 ; N U ; B 17 -18 583 562 ;
C 86 ; WX 600 ; N V ; B -4 -13 604 562 ;
C 87 ; WX 600 ; N W ; B -3 -13 603 562 ;
C 88 ; WX 600 ; N X ; B 23 0 577 562 ;
C 89 ; WX 600 ; N Y ; B 24 0 576 562 ;
C 90 ; WX 600 ; N Z ; B 86 0 514 562 ;
C 91 ; WX 600 ; N bracketleft ; B 269 -108 442 622 ;
C 92 ; WX 600 ; N backslash ; B 118 -80 482 629 ;
C 93 ; WX 600 ; N bracketright ; B 158 -108 331 622 ;
C 94 ; WX 600 ; N asciicircum ; B 94 354 506 622 ;
C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ;
C 145 ; WX 600 ; N quoteleft ; B 224 328 387 562 ;
C 97 ; WX 600 ; N a ; B 53 -15 559 441 ;
C 98 ; WX 600 ; N b ; B 14 -15 575 629 ;
C 99 ; WX 600 ; N c ; B 66 -15 529 441 ;
C 100 ; WX 600 ; N d ; B 45 -15 591 629 ;
C 101 ; WX 600 ; N e ; B 66 -15 548 441 ;
C 102 ; WX 600 ; N f ; B 114 0 531 629 ; L i fi ; L l fl ;
C 103 ; WX 600 ; N g ; B 45 -157 566 441 ;
C 104 ; WX 600 ; N h ; B 18 0 582 629 ;
C 105 ; WX 600 ; N i ; B 95 0 505 657 ;
C 106 ; WX 600 ; N j ; B 82 -157 410 657 ;
C 107 ; WX 600 ; N k ; B 43 0 580 629 ;
C 108 ; WX 600 ; N l ; B 95 0 505 629 ;
C 109 ; WX 600 ; N m ; B -5 0 605 441 ;
C 110 ; WX 600 ; N n ; B 26 0 575 441 ;
C 111 ; WX 600 ; N o ; B 62 -15 538 441 ;
C 112 ; WX 600 ; N p ; B 9 -157 555 441 ;
C 113 ; WX 600 ; N q ; B 45 -157 591 441 ;
C 114 ; WX 600 ; N r ; B 60 0 559 441 ;
C 115 ; WX 600 ; N s ; B 80 -15 513 441 ;
C 116 ; WX 600 ; N t ; B 87 -15 530 561 ;
C 117 ; WX 600 ; N u ; B 21 -15 562 426 ;
C 118 ; WX 600 ; N v ; B 10 -10 590 426 ;
C 119 ; WX 600 ; N w ; B -4 -10 604 426 ;
C 120 ; WX 600 ; N x ; B 20 0 580 426 ;
C 121 ; WX 600 ; N y ; B 7 -157 592 426 ;
C 122 ; WX 600 ; N z ; B 99 0 502 426 ;
C 123 ; WX 600 ; N braceleft ; B 182 -108 437 622 ;
C 124 ; WX 600 ; N bar ; B 275 -250 326 750 ;
C 125 ; WX 600 ; N braceright ; B 163 -108 418 622 ;
C 126 ; WX 600 ; N asciitilde ; B 63 197 540 320 ;
C 161 ; WX 600 ; N exclamdown ; B 236 -157 364 430 ;
C 162 ; WX 600 ; N cent ; B 96 -49 500 614 ;
C 163 ; WX 600 ; N sterling ; B 84 -21 521 611 ;
C -1 ; WX 600 ; N fraction ; B 92 -57 509 665 ;
C 165 ; WX 600 ; N yen ; B 26 0 574 562 ;
C 131 ; WX 600 ; N florin ; B 4 -143 539 622 ;
C 167 ; WX 600 ; N section ; B 113 -78 488 580 ;
C 164 ; WX 600 ; N currency ; B 73 58 527 506 ;
C 39 ; WX 600 ; N quotesingle ; B 259 328 341 562 ;
C 147 ; WX 600 ; N quotedblleft ; B 143 328 471 562 ;
C 171 ; WX 600 ; N guillemotleft ; B 37 70 563 446 ;
C 139 ; WX 600 ; N guilsinglleft ; B 149 70 451 446 ;
C 155 ; WX 600 ; N guilsinglright ; B 149 70 451 446 ;
C -1 ; WX 600 ; N fi ; B 3 0 597 629 ;
C -1 ; WX 600 ; N fl ; B 3 0 597 629 ;
C 150 ; WX 600 ; N endash ; B 75 231 525 285 ;
C 134 ; WX 600 ; N dagger ; B 141 -78 459 580 ;
C 135 ; WX 600 ; N daggerdbl ; B 141 -78 459 580 ;
C 183 ; WX 600 ; N periodcentered ; B 222 189 378 327 ;
C 182 ; WX 600 ; N paragraph ; B 50 -78 511 562 ;
C 149 ; WX 600 ; N bullet ; B 172 130 428 383 ;
C 130 ; WX 600 ; N quotesinglbase ; B 213 -134 376 100 ;
C 132 ; WX 600 ; N quotedblbase ; B 143 -134 457 100 ;
C 148 ; WX 600 ; N quotedblright ; B 143 328 457 562 ;
C 187 ; WX 600 ; N guillemotright ; B 37 70 563 446 ;
C 133 ; WX 600 ; N ellipsis ; B 37 -15 563 111 ;
C 137 ; WX 600 ; N perthousand ; B 3 -15 600 622 ;
C 191 ; WX 600 ; N questiondown ; B 108 -157 471 430 ;
C 96 ; WX 600 ; N grave ; B 151 497 378 672 ;
C 180 ; WX 600 ; N acute ; B 242 497 469 672 ;
C 136 ; WX 600 ; N circumflex ; B 124 477 476 654 ;
C 152 ; WX 600 ; N tilde ; B 105 489 503 606 ;
C 175 ; WX 600 ; N macron ; B 120 525 480 565 ;
C -1 ; WX 600 ; N breve ; B 153 501 447 609 ;
C -1 ; WX 600 ; N dotaccent ; B 249 537 352 640 ;
C 168 ; WX 600 ; N dieresis ; B 148 537 453 640 ;
C -1 ; WX 600 ; N ring ; B 218 463 382 627 ;
C 184 ; WX 600 ; N cedilla ; B 224 -151 362 10 ;
C -1 ; WX 600 ; N hungarumlaut ; B 133 497 540 672 ;
C -1 ; WX 600 ; N ogonek ; B 211 -172 407 4 ;
C -1 ; WX 600 ; N caron ; B 124 492 476 669 ;
C 151 ; WX 600 ; N emdash ; B 0 231 600 285 ;
C 198 ; WX 600 ; N AE ; B 3 0 550 562 ;
C 170 ; WX 600 ; N ordfeminine ; B 156 249 442 580 ;
C -1 ; WX 600 ; N Lslash ; B 47 0 554 562 ;
C 216 ; WX 600 ; N Oslash ; B 43 -80 557 629 ;
C 140 ; WX 600 ; N OE ; B 7 0 567 562 ;
C 186 ; WX 600 ; N ordmasculine ; B 157 249 443 580 ;
C 230 ; WX 600 ; N ae ; B 19 -15 570 441 ;
C -1 ; WX 600 ; N dotlessi ; B 95 0 505 426 ;
C -1 ; WX 600 ; N lslash ; B 95 0 505 629 ;
C 248 ; WX 600 ; N oslash ; B 62 -80 538 506 ;
C 156 ; WX 600 ; N oe ; B 19 -15 559 441 ;
C 223 ; WX 600 ; N germandbls ; B 48 -15 588 629 ;
C 207 ; WX 600 ; N Idieresis ; B 96 0 504 753 ;
C 233 ; WX 600 ; N eacute ; B 66 -15 548 672 ;
C -1 ; WX 600 ; N abreve ; B 53 -15 559 609 ;
C -1 ; WX 600 ; N uhungarumlaut ; B 21 -15 580 672 ;
C -1 ; WX 600 ; N ecaron ; B 66 -15 548 669 ;
C 159 ; WX 600 ; N Ydieresis ; B 24 0 576 753 ;
C 247 ; WX 600 ; N divide ; B 87 48 513 467 ;
C 221 ; WX 600 ; N Yacute ; B 24 0 576 805 ;
C 194 ; WX 600 ; N Acircumflex ; B 3 0 597 787 ;
C 225 ; WX 600 ; N aacute ; B 53 -15 559 672 ;
C 219 ; WX 600 ; N Ucircumflex ; B 17 -18 583 787 ;
C 253 ; WX 600 ; N yacute ; B 7 -157 592 672 ;
C -1 ; WX 600 ; N scommaaccent ; B 80 -250 513 441 ;
C 234 ; WX 600 ; N ecircumflex ; B 66 -15 548 654 ;
C -1 ; WX 600 ; N Uring ; B 17 -18 583 760 ;
C 220 ; WX 600 ; N Udieresis ; B 17 -18 583 753 ;
C -1 ; WX 600 ; N aogonek ; B 53 -172 587 441 ;
C 218 ; WX 600 ; N Uacute ; B 17 -18 583 805 ;
C -1 ; WX 600 ; N uogonek ; B 21 -172 590 426 ;
C 203 ; WX 600 ; N Edieresis ; B 53 0 550 753 ;
C -1 ; WX 600 ; N Dcroat ; B 30 0 574 562 ;
C -1 ; WX 600 ; N commaaccent ; B 198 -250 335 -58 ;
C 169 ; WX 600 ; N copyright ; B 0 -18 600 580 ;
C -1 ; WX 600 ; N Emacron ; B 53 0 550 698 ;
C -1 ; WX 600 ; N ccaron ; B 66 -15 529 669 ;
C 229 ; WX 600 ; N aring ; B 53 -15 559 627 ;
C -1 ; WX 600 ; N Ncommaaccent ; B 7 -250 593 562 ;
C -1 ; WX 600 ; N lacute ; B 95 0 505 805 ;
C 224 ; WX 600 ; N agrave ; B 53 -15 559 672 ;
C -1 ; WX 600 ; N Tcommaaccent ; B 38 -250 563 562 ;
C -1 ; WX 600 ; N Cacute ; B 41 -18 540 805 ;
C 227 ; WX 600 ; N atilde ; B 53 -15 559 606 ;
C -1 ; WX 600 ; N Edotaccent ; B 53 0 550 753 ;
C 154 ; WX 600 ; N scaron ; B 80 -15 513 669 ;
C -1 ; WX 600 ; N scedilla ; B 80 -151 513 441 ;
C 237 ; WX 600 ; N iacute ; B 95 0 505 672 ;
C -1 ; WX 600 ; N lozenge ; B 18 0 443 706 ;
C -1 ; WX 600 ; N Rcaron ; B 38 0 588 802 ;
C -1 ; WX 600 ; N Gcommaaccent ; B 31 -250 575 580 ;
C 251 ; WX 600 ; N ucircumflex ; B 21 -15 562 654 ;
C 226 ; WX 600 ; N acircumflex ; B 53 -15 559 654 ;
C -1 ; WX 600 ; N Amacron ; B 3 0 597 698 ;
C -1 ; WX 600 ; N rcaron ; B 60 0 559 669 ;
C 231 ; WX 600 ; N ccedilla ; B 66 -151 529 441 ;
C -1 ; WX 600 ; N Zdotaccent ; B 86 0 514 753 ;
C 222 ; WX 600 ; N Thorn ; B 79 0 538 562 ;
C -1 ; WX 600 ; N Omacron ; B 43 -18 557 698 ;
C -1 ; WX 600 ; N Racute ; B 38 0 588 805 ;
C -1 ; WX 600 ; N Sacute ; B 72 -20 529 805 ;
C -1 ; WX 600 ; N dcaron ; B 45 -15 715 629 ;
C -1 ; WX 600 ; N Umacron ; B 17 -18 583 698 ;
C -1 ; WX 600 ; N uring ; B 21 -15 562 627 ;
C 179 ; WX 600 ; N threesuperior ; B 155 240 406 622 ;
C 210 ; WX 600 ; N Ograve ; B 43 -18 557 805 ;
C 192 ; WX 600 ; N Agrave ; B 3 0 597 805 ;
C -1 ; WX 600 ; N Abreve ; B 3 0 597 732 ;
C 215 ; WX 600 ; N multiply ; B 87 43 515 470 ;
C 250 ; WX 600 ; N uacute ; B 21 -15 562 672 ;
C -1 ; WX 600 ; N Tcaron ; B 38 0 563 802 ;
C -1 ; WX 600 ; N partialdiff ; B 17 -38 459 710 ;
C 255 ; WX 600 ; N ydieresis ; B 7 -157 592 620 ;
C -1 ; WX 600 ; N Nacute ; B 7 -13 593 805 ;
C 238 ; WX 600 ; N icircumflex ; B 94 0 505 654 ;
C 202 ; WX 600 ; N Ecircumflex ; B 53 0 550 787 ;
C 228 ; WX 600 ; N adieresis ; B 53 -15 559 620 ;
C 235 ; WX 600 ; N edieresis ; B 66 -15 548 620 ;
C -1 ; WX 600 ; N cacute ; B 66 -15 529 672 ;
C -1 ; WX 600 ; N nacute ; B 26 0 575 672 ;
C -1 ; WX 600 ; N umacron ; B 21 -15 562 565 ;
C -1 ; WX 600 ; N Ncaron ; B 7 -13 593 802 ;
C 205 ; WX 600 ; N Iacute ; B 96 0 504 805 ;
C 177 ; WX 600 ; N plusminus ; B 87 44 513 558 ;
C 166 ; WX 600 ; N brokenbar ; B 275 -175 326 675 ;
C 174 ; WX 600 ; N registered ; B 0 -18 600 580 ;
C -1 ; WX 600 ; N Gbreve ; B 31 -18 575 732 ;
C -1 ; WX 600 ; N Idotaccent ; B 96 0 504 753 ;
C -1 ; WX 600 ; N summation ; B 15 -10 585 706 ;
C 200 ; WX 600 ; N Egrave ; B 53 0 550 805 ;
C -1 ; WX 600 ; N racute ; B 60 0 559 672 ;
C -1 ; WX 600 ; N omacron ; B 62 -15 538 565 ;
C -1 ; WX 600 ; N Zacute ; B 86 0 514 805 ;
C 142 ; WX 600 ; N Zcaron ; B 86 0 514 802 ;
C -1 ; WX 600 ; N greaterequal ; B 98 0 502 710 ;
C 208 ; WX 600 ; N Eth ; B 30 0 574 562 ;
C 199 ; WX 600 ; N Ccedilla ; B 41 -151 540 580 ;
C -1 ; WX 600 ; N lcommaaccent ; B 95 -250 505 629 ;
C -1 ; WX 600 ; N tcaron ; B 87 -15 530 717 ;
C -1 ; WX 600 ; N eogonek ; B 66 -172 548 441 ;
C -1 ; WX 600 ; N Uogonek ; B 17 -172 583 562 ;
C 193 ; WX 600 ; N Aacute ; B 3 0 597 805 ;
C 196 ; WX 600 ; N Adieresis ; B 3 0 597 753 ;
C 232 ; WX 600 ; N egrave ; B 66 -15 548 672 ;
C -1 ; WX 600 ; N zacute ; B 99 0 502 672 ;
C -1 ; WX 600 ; N iogonek ; B 95 -172 505 657 ;
C 211 ; WX 600 ; N Oacute ; B 43 -18 557 805 ;
C 243 ; WX 600 ; N oacute ; B 62 -15 538 672 ;
C -1 ; WX 600 ; N amacron ; B 53 -15 559 565 ;
C -1 ; WX 600 ; N sacute ; B 80 -15 513 672 ;
C 239 ; WX 600 ; N idieresis ; B 95 0 505 620 ;
C 212 ; WX 600 ; N Ocircumflex ; B 43 -18 557 787 ;
C 217 ; WX 600 ; N Ugrave ; B 17 -18 583 805 ;
C -1 ; WX 600 ; N Delta ; B 6 0 598 688 ;
C 254 ; WX 600 ; N thorn ; B -6 -157 555 629 ;
C 178 ; WX 600 ; N twosuperior ; B 177 249 424 622 ;
C 214 ; WX 600 ; N Odieresis ; B 43 -18 557 753 ;
C 181 ; WX 600 ; N mu ; B 21 -157 562 426 ;
C 236 ; WX 600 ; N igrave ; B 95 0 505 672 ;
C -1 ; WX 600 ; N ohungarumlaut ; B 62 -15 580 672 ;
C -1 ; WX 600 ; N Eogonek ; B 53 -172 561 562 ;
C -1 ; WX 600 ; N dcroat ; B 45 -15 591 629 ;
C 190 ; WX 600 ; N threequarters ; B 8 -56 593 666 ;
C -1 ; WX 600 ; N Scedilla ; B 72 -151 529 580 ;
C -1 ; WX 600 ; N lcaron ; B 95 0 533 629 ;
C -1 ; WX 600 ; N Kcommaaccent ; B 38 -250 582 562 ;
C -1 ; WX 600 ; N Lacute ; B 47 0 554 805 ;
C 153 ; WX 600 ; N trademark ; B -23 263 623 562 ;
C -1 ; WX 600 ; N edotaccent ; B 66 -15 548 620 ;
C 204 ; WX 600 ; N Igrave ; B 96 0 504 805 ;
C -1 ; WX 600 ; N Imacron ; B 96 0 504 698 ;
C -1 ; WX 600 ; N Lcaron ; B 47 0 554 562 ;
C 189 ; WX 600 ; N onehalf ; B 0 -57 611 665 ;
C -1 ; WX 600 ; N lessequal ; B 98 0 502 710 ;
C 244 ; WX 600 ; N ocircumflex ; B 62 -15 538 654 ;
C 241 ; WX 600 ; N ntilde ; B 26 0 575 606 ;
C -1 ; WX 600 ; N Uhungarumlaut ; B 17 -18 590 805 ;
C 201 ; WX 600 ; N Eacute ; B 53 0 550 805 ;
C -1 ; WX 600 ; N emacron ; B 66 -15 548 565 ;
C -1 ; WX 600 ; N gbreve ; B 45 -157 566 609 ;
C 188 ; WX 600 ; N onequarter ; B 0 -57 600 665 ;
C 138 ; WX 600 ; N Scaron ; B 72 -20 529 802 ;
C -1 ; WX 600 ; N Scommaaccent ; B 72 -250 529 580 ;
C -1 ; WX 600 ; N Ohungarumlaut ; B 43 -18 580 805 ;
C 176 ; WX 600 ; N degree ; B 123 269 477 622 ;
C 242 ; WX 600 ; N ograve ; B 62 -15 538 672 ;
C -1 ; WX 600 ; N Ccaron ; B 41 -18 540 802 ;
C 249 ; WX 600 ; N ugrave ; B 21 -15 562 672 ;
C -1 ; WX 600 ; N radical ; B 3 -15 597 792 ;
C -1 ; WX 600 ; N Dcaron ; B 43 0 574 802 ;
C -1 ; WX 600 ; N rcommaaccent ; B 60 -250 559 441 ;
C 209 ; WX 600 ; N Ntilde ; B 7 -13 593 729 ;
C 245 ; WX 600 ; N otilde ; B 62 -15 538 606 ;
C -1 ; WX 600 ; N Rcommaaccent ; B 38 -250 588 562 ;
C -1 ; WX 600 ; N Lcommaaccent ; B 47 -250 554 562 ;
C 195 ; WX 600 ; N Atilde ; B 3 0 597 729 ;
C -1 ; WX 600 ; N Aogonek ; B 3 -172 608 562 ;
C 197 ; WX 600 ; N Aring ; B 3 0 597 750 ;
C 213 ; WX 600 ; N Otilde ; B 43 -18 557 729 ;
C -1 ; WX 600 ; N zdotaccent ; B 99 0 502 620 ;
C -1 ; WX 600 ; N Ecaron ; B 53 0 550 802 ;
C -1 ; WX 600 ; N Iogonek ; B 96 -172 504 562 ;
C -1 ; WX 600 ; N kcommaaccent ; B 43 -250 580 629 ;
C -1 ; WX 600 ; N minus ; B 80 232 520 283 ;
C 206 ; WX 600 ; N Icircumflex ; B 96 0 504 787 ;
C -1 ; WX 600 ; N ncaron ; B 26 0 575 669 ;
C -1 ; WX 600 ; N tcommaaccent ; B 87 -250 530 561 ;
C 172 ; WX 600 ; N logicalnot ; B 87 108 513 369 ;
C 246 ; WX 600 ; N odieresis ; B 62 -15 538 620 ;
C 252 ; WX 600 ; N udieresis ; B 21 -15 562 620 ;
C -1 ; WX 600 ; N notequal ; B 15 -16 540 529 ;
C -1 ; WX 600 ; N gcommaaccent ; B 45 -157 566 708 ;
C 240 ; WX 600 ; N eth ; B 62 -15 538 629 ;
C 158 ; WX 600 ; N zcaron ; B 99 0 502 669 ;
C -1 ; WX 600 ; N ncommaaccent ; B 26 -250 575 441 ;
C 185 ; WX 600 ; N onesuperior ; B 172 249 428 622 ;
C -1 ; WX 600 ; N imacron ; B 95 0 505 565 ;
C 128 ; WX 600 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
EndFontMetrics

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,5 @@
To save space in the final distribution we have not included the DejaVu family of fonts. You can get these fonts from:
http://code.google.com/p/dompdf/
Download the latest version and copy the font files from the lib/fonts directories to this directory.

View file

@ -0,0 +1,213 @@
StartFontMetrics 4.1
Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All rights reserved.
Comment Creation Date: Thu May 1 15:12:25 1997
Comment UniqueID 43064
Comment VMusage 30820 39997
FontName Symbol
FullName Symbol
FamilyName Symbol
Weight Medium
ItalicAngle 0
IsFixedPitch false
CharacterSet Special
FontBBox -180 -293 1090 1010
UnderlinePosition -100
UnderlineThickness 50
Version 001.008
Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All rights reserved.
EncodingScheme FontSpecific
StdHW 92
StdVW 85
StartCharMetrics 190
C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
C 33 ; WX 333 ; N exclam ; B 128 -17 240 672 ;
C 34 ; WX 713 ; N universal ; B 31 0 681 705 ;
C 35 ; WX 500 ; N numbersign ; B 20 -16 481 673 ;
C 36 ; WX 549 ; N existential ; B 25 0 478 707 ;
C 37 ; WX 833 ; N percent ; B 63 -36 771 655 ;
C 38 ; WX 778 ; N ampersand ; B 41 -18 750 661 ;
C 39 ; WX 439 ; N suchthat ; B 48 -17 414 500 ;
C 40 ; WX 333 ; N parenleft ; B 53 -191 300 673 ;
C 41 ; WX 333 ; N parenright ; B 30 -191 277 673 ;
C 42 ; WX 500 ; N asteriskmath ; B 65 134 427 551 ;
C 43 ; WX 549 ; N plus ; B 10 0 539 533 ;
C 44 ; WX 250 ; N comma ; B 56 -152 194 104 ;
C 45 ; WX 549 ; N minus ; B 11 233 535 288 ;
C 46 ; WX 250 ; N period ; B 69 -17 181 95 ;
C 47 ; WX 278 ; N slash ; B 0 -18 254 646 ;
C 48 ; WX 500 ; N zero ; B 24 -14 476 685 ;
C 49 ; WX 500 ; N one ; B 117 0 390 673 ;
C 50 ; WX 500 ; N two ; B 25 0 475 685 ;
C 51 ; WX 500 ; N three ; B 43 -14 435 685 ;
C 52 ; WX 500 ; N four ; B 15 0 469 685 ;
C 53 ; WX 500 ; N five ; B 32 -14 445 690 ;
C 54 ; WX 500 ; N six ; B 34 -14 468 685 ;
C 55 ; WX 500 ; N seven ; B 24 -16 448 673 ;
C 56 ; WX 500 ; N eight ; B 56 -14 445 685 ;
C 57 ; WX 500 ; N nine ; B 30 -18 459 685 ;
C 58 ; WX 278 ; N colon ; B 81 -17 193 460 ;
C 59 ; WX 278 ; N semicolon ; B 83 -152 221 460 ;
C 60 ; WX 549 ; N less ; B 26 0 523 522 ;
C 61 ; WX 549 ; N equal ; B 11 141 537 390 ;
C 62 ; WX 549 ; N greater ; B 26 0 523 522 ;
C 63 ; WX 444 ; N question ; B 70 -17 412 686 ;
C 64 ; WX 549 ; N congruent ; B 11 0 537 475 ;
C 65 ; WX 722 ; N Alpha ; B 4 0 684 673 ;
C 66 ; WX 667 ; N Beta ; B 29 0 592 673 ;
C 67 ; WX 722 ; N Chi ; B -9 0 704 673 ;
C 68 ; WX 612 ; N Delta ; B 6 0 608 688 ;
C 69 ; WX 611 ; N Epsilon ; B 32 0 617 673 ;
C 70 ; WX 763 ; N Phi ; B 26 0 741 673 ;
C 71 ; WX 603 ; N Gamma ; B 24 0 609 673 ;
C 72 ; WX 722 ; N Eta ; B 39 0 729 673 ;
C 73 ; WX 333 ; N Iota ; B 32 0 316 673 ;
C 74 ; WX 631 ; N theta1 ; B 18 -18 623 689 ;
C 75 ; WX 722 ; N Kappa ; B 35 0 722 673 ;
C 76 ; WX 686 ; N Lambda ; B 6 0 680 688 ;
C 77 ; WX 889 ; N Mu ; B 28 0 887 673 ;
C 78 ; WX 722 ; N Nu ; B 29 -8 720 673 ;
C 79 ; WX 722 ; N Omicron ; B 41 -17 715 685 ;
C 80 ; WX 768 ; N Pi ; B 25 0 745 673 ;
C 81 ; WX 741 ; N Theta ; B 41 -17 715 685 ;
C 82 ; WX 556 ; N Rho ; B 28 0 563 673 ;
C 83 ; WX 592 ; N Sigma ; B 5 0 589 673 ;
C 84 ; WX 611 ; N Tau ; B 33 0 607 673 ;
C 85 ; WX 690 ; N Upsilon ; B -8 0 694 673 ;
C 86 ; WX 439 ; N sigma1 ; B 40 -233 436 500 ;
C 87 ; WX 768 ; N Omega ; B 34 0 736 688 ;
C 88 ; WX 645 ; N Xi ; B 40 0 599 673 ;
C 89 ; WX 795 ; N Psi ; B 15 0 781 684 ;
C 90 ; WX 611 ; N Zeta ; B 44 0 636 673 ;
C 91 ; WX 333 ; N bracketleft ; B 86 -155 299 674 ;
C 92 ; WX 863 ; N therefore ; B 163 0 701 487 ;
C 93 ; WX 333 ; N bracketright ; B 33 -155 246 674 ;
C 94 ; WX 658 ; N perpendicular ; B 15 0 652 674 ;
C 95 ; WX 500 ; N underscore ; B -2 -125 502 -75 ;
C 96 ; WX 500 ; N radicalex ; B 480 881 1090 917 ;
C 97 ; WX 631 ; N alpha ; B 41 -18 622 500 ;
C 98 ; WX 549 ; N beta ; B 61 -223 515 741 ;
C 99 ; WX 549 ; N chi ; B 12 -231 522 499 ;
C 100 ; WX 494 ; N delta ; B 40 -19 481 740 ;
C 101 ; WX 439 ; N epsilon ; B 22 -19 427 502 ;
C 102 ; WX 521 ; N phi ; B 28 -224 492 673 ;
C 103 ; WX 411 ; N gamma ; B 5 -225 484 499 ;
C 104 ; WX 603 ; N eta ; B 0 -202 527 514 ;
C 105 ; WX 329 ; N iota ; B 0 -17 301 503 ;
C 106 ; WX 603 ; N phi1 ; B 36 -224 587 499 ;
C 107 ; WX 549 ; N kappa ; B 33 0 558 501 ;
C 108 ; WX 549 ; N lambda ; B 24 -17 548 739 ;
C 109 ; WX 576 ; N mu ; B 33 -223 567 500 ;
C 110 ; WX 521 ; N nu ; B -9 -16 475 507 ;
C 111 ; WX 549 ; N omicron ; B 35 -19 501 499 ;
C 112 ; WX 549 ; N pi ; B 10 -19 530 487 ;
C 113 ; WX 521 ; N theta ; B 43 -17 485 690 ;
C 114 ; WX 549 ; N rho ; B 50 -230 490 499 ;
C 115 ; WX 603 ; N sigma ; B 30 -21 588 500 ;
C 116 ; WX 439 ; N tau ; B 10 -19 418 500 ;
C 117 ; WX 576 ; N upsilon ; B 7 -18 535 507 ;
C 118 ; WX 713 ; N omega1 ; B 12 -18 671 583 ;
C 119 ; WX 686 ; N omega ; B 42 -17 684 500 ;
C 120 ; WX 493 ; N xi ; B 27 -224 469 766 ;
C 121 ; WX 686 ; N psi ; B 12 -228 701 500 ;
C 122 ; WX 494 ; N zeta ; B 60 -225 467 756 ;
C 123 ; WX 480 ; N braceleft ; B 58 -183 397 673 ;
C 124 ; WX 200 ; N bar ; B 65 -293 135 707 ;
C 125 ; WX 480 ; N braceright ; B 79 -183 418 673 ;
C 126 ; WX 549 ; N similar ; B 17 203 529 307 ;
C 160 ; WX 750 ; N Euro ; B 20 -12 714 685 ;
C 161 ; WX 620 ; N Upsilon1 ; B -2 0 610 685 ;
C 162 ; WX 247 ; N minute ; B 27 459 228 735 ;
C 163 ; WX 549 ; N lessequal ; B 29 0 526 639 ;
C 164 ; WX 167 ; N fraction ; B -180 -12 340 677 ;
C 165 ; WX 713 ; N infinity ; B 26 124 688 404 ;
C 166 ; WX 500 ; N florin ; B 2 -193 494 686 ;
C 167 ; WX 753 ; N club ; B 86 -26 660 533 ;
C 168 ; WX 753 ; N diamond ; B 142 -36 600 550 ;
C 169 ; WX 753 ; N heart ; B 117 -33 631 532 ;
C 170 ; WX 753 ; N spade ; B 113 -36 629 548 ;
C 171 ; WX 1042 ; N arrowboth ; B 24 -15 1024 511 ;
C 172 ; WX 987 ; N arrowleft ; B 32 -15 942 511 ;
C 173 ; WX 603 ; N arrowup ; B 45 0 571 910 ;
C 174 ; WX 987 ; N arrowright ; B 49 -15 959 511 ;
C 175 ; WX 603 ; N arrowdown ; B 45 -22 571 888 ;
C 176 ; WX 400 ; N degree ; B 50 385 350 685 ;
C 177 ; WX 549 ; N plusminus ; B 10 0 539 645 ;
C 178 ; WX 411 ; N second ; B 20 459 413 737 ;
C 179 ; WX 549 ; N greaterequal ; B 29 0 526 639 ;
C 180 ; WX 549 ; N multiply ; B 17 8 533 524 ;
C 181 ; WX 713 ; N proportional ; B 27 123 639 404 ;
C 182 ; WX 494 ; N partialdiff ; B 26 -20 462 746 ;
C 183 ; WX 460 ; N bullet ; B 50 113 410 473 ;
C 184 ; WX 549 ; N divide ; B 10 71 536 456 ;
C 185 ; WX 549 ; N notequal ; B 15 -25 540 549 ;
C 186 ; WX 549 ; N equivalence ; B 14 82 538 443 ;
C 187 ; WX 549 ; N approxequal ; B 14 135 527 394 ;
C 188 ; WX 1000 ; N ellipsis ; B 111 -17 889 95 ;
C 189 ; WX 603 ; N arrowvertex ; B 280 -120 336 1010 ;
C 190 ; WX 1000 ; N arrowhorizex ; B -60 220 1050 276 ;
C 191 ; WX 658 ; N carriagereturn ; B 15 -16 602 629 ;
C 192 ; WX 823 ; N aleph ; B 175 -18 661 658 ;
C 193 ; WX 686 ; N Ifraktur ; B 10 -53 578 740 ;
C 194 ; WX 795 ; N Rfraktur ; B 26 -15 759 734 ;
C 195 ; WX 987 ; N weierstrass ; B 159 -211 870 573 ;
C 196 ; WX 768 ; N circlemultiply ; B 43 -17 733 673 ;
C 197 ; WX 768 ; N circleplus ; B 43 -15 733 675 ;
C 198 ; WX 823 ; N emptyset ; B 39 -24 781 719 ;
C 199 ; WX 768 ; N intersection ; B 40 0 732 509 ;
C 200 ; WX 768 ; N union ; B 40 -17 732 492 ;
C 201 ; WX 713 ; N propersuperset ; B 20 0 673 470 ;
C 202 ; WX 713 ; N reflexsuperset ; B 20 -125 673 470 ;
C 203 ; WX 713 ; N notsubset ; B 36 -70 690 540 ;
C 204 ; WX 713 ; N propersubset ; B 37 0 690 470 ;
C 205 ; WX 713 ; N reflexsubset ; B 37 -125 690 470 ;
C 206 ; WX 713 ; N element ; B 45 0 505 468 ;
C 207 ; WX 713 ; N notelement ; B 45 -58 505 555 ;
C 208 ; WX 768 ; N angle ; B 26 0 738 673 ;
C 209 ; WX 713 ; N gradient ; B 36 -19 681 718 ;
C 210 ; WX 790 ; N registerserif ; B 50 -17 740 673 ;
C 211 ; WX 790 ; N copyrightserif ; B 51 -15 741 675 ;
C 212 ; WX 890 ; N trademarkserif ; B 18 293 855 673 ;
C 213 ; WX 823 ; N product ; B 25 -101 803 751 ;
C 214 ; WX 549 ; N radical ; B 10 -38 515 917 ;
C 215 ; WX 250 ; N dotmath ; B 69 210 169 310 ;
C 216 ; WX 713 ; N logicalnot ; B 15 0 680 288 ;
C 217 ; WX 603 ; N logicaland ; B 23 0 583 454 ;
C 218 ; WX 603 ; N logicalor ; B 30 0 578 477 ;
C 219 ; WX 1042 ; N arrowdblboth ; B 27 -20 1023 510 ;
C 220 ; WX 987 ; N arrowdblleft ; B 30 -15 939 513 ;
C 221 ; WX 603 ; N arrowdblup ; B 39 2 567 911 ;
C 222 ; WX 987 ; N arrowdblright ; B 45 -20 954 508 ;
C 223 ; WX 603 ; N arrowdbldown ; B 44 -19 572 890 ;
C 224 ; WX 494 ; N lozenge ; B 18 0 466 745 ;
C 225 ; WX 329 ; N angleleft ; B 25 -198 306 746 ;
C 226 ; WX 790 ; N registersans ; B 50 -20 740 670 ;
C 227 ; WX 790 ; N copyrightsans ; B 49 -15 739 675 ;
C 228 ; WX 786 ; N trademarksans ; B 5 293 725 673 ;
C 229 ; WX 713 ; N summation ; B 14 -108 695 752 ;
C 230 ; WX 384 ; N parenlefttp ; B 24 -293 436 926 ;
C 231 ; WX 384 ; N parenleftex ; B 24 -85 108 925 ;
C 232 ; WX 384 ; N parenleftbt ; B 24 -293 436 926 ;
C 233 ; WX 384 ; N bracketlefttp ; B 0 -80 349 926 ;
C 234 ; WX 384 ; N bracketleftex ; B 0 -79 77 925 ;
C 235 ; WX 384 ; N bracketleftbt ; B 0 -80 349 926 ;
C 236 ; WX 494 ; N bracelefttp ; B 209 -85 445 925 ;
C 237 ; WX 494 ; N braceleftmid ; B 20 -85 284 935 ;
C 238 ; WX 494 ; N braceleftbt ; B 209 -75 445 935 ;
C 239 ; WX 494 ; N braceex ; B 209 -85 284 935 ;
C 241 ; WX 329 ; N angleright ; B 21 -198 302 746 ;
C 242 ; WX 274 ; N integral ; B 2 -107 291 916 ;
C 243 ; WX 686 ; N integraltp ; B 308 -88 675 920 ;
C 244 ; WX 686 ; N integralex ; B 308 -88 378 975 ;
C 245 ; WX 686 ; N integralbt ; B 11 -87 378 921 ;
C 246 ; WX 384 ; N parenrighttp ; B 54 -293 466 926 ;
C 247 ; WX 384 ; N parenrightex ; B 382 -85 466 925 ;
C 248 ; WX 384 ; N parenrightbt ; B 54 -293 466 926 ;
C 249 ; WX 384 ; N bracketrighttp ; B 22 -80 371 926 ;
C 250 ; WX 384 ; N bracketrightex ; B 294 -79 371 925 ;
C 251 ; WX 384 ; N bracketrightbt ; B 22 -80 371 926 ;
C 252 ; WX 494 ; N bracerighttp ; B 48 -85 284 925 ;
C 253 ; WX 494 ; N bracerightmid ; B 209 -85 473 935 ;
C 254 ; WX 494 ; N bracerightbt ; B 48 -75 284 935 ;
C -1 ; WX 790 ; N apple ; B 56 -3 733 808 ;
EndCharMetrics
EndFontMetrics

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,225 @@
StartFontMetrics 4.1
Comment Copyright (c) 1985, 1987, 1988, 1989, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 1 15:14:13 1997
Comment UniqueID 43082
Comment VMusage 45775 55535
FontName ZapfDingbats
FullName ITC Zapf Dingbats
FamilyName ZapfDingbats
Weight Medium
ItalicAngle 0
IsFixedPitch false
CharacterSet Special
FontBBox -1 -143 981 820
UnderlinePosition -100
UnderlineThickness 50
Version 002.000
Notice Copyright (c) 1985, 1987, 1988, 1989, 1997 Adobe Systems Incorporated. All Rights Reserved.ITC Zapf Dingbats is a registered trademark of International Typeface Corporation.
EncodingScheme FontSpecific
StdHW 28
StdVW 90
StartCharMetrics 202
C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
C 33 ; WX 974 ; N a1 ; B 35 72 939 621 ;
C 34 ; WX 961 ; N a2 ; B 35 81 927 611 ;
C 35 ; WX 974 ; N a202 ; B 35 72 939 621 ;
C 36 ; WX 980 ; N a3 ; B 35 0 945 692 ;
C 37 ; WX 719 ; N a4 ; B 34 139 685 566 ;
C 38 ; WX 789 ; N a5 ; B 35 -14 755 705 ;
C 39 ; WX 790 ; N a119 ; B 35 -14 755 705 ;
C 40 ; WX 791 ; N a118 ; B 35 -13 761 705 ;
C 41 ; WX 690 ; N a117 ; B 34 138 655 553 ;
C 42 ; WX 960 ; N a11 ; B 35 123 925 568 ;
C 43 ; WX 939 ; N a12 ; B 35 134 904 559 ;
C 44 ; WX 549 ; N a13 ; B 29 -11 516 705 ;
C 45 ; WX 855 ; N a14 ; B 34 59 820 632 ;
C 46 ; WX 911 ; N a15 ; B 35 50 876 642 ;
C 47 ; WX 933 ; N a16 ; B 35 139 899 550 ;
C 48 ; WX 911 ; N a105 ; B 35 50 876 642 ;
C 49 ; WX 945 ; N a17 ; B 35 139 909 553 ;
C 50 ; WX 974 ; N a18 ; B 35 104 938 587 ;
C 51 ; WX 755 ; N a19 ; B 34 -13 721 705 ;
C 52 ; WX 846 ; N a20 ; B 36 -14 811 705 ;
C 53 ; WX 762 ; N a21 ; B 35 0 727 692 ;
C 54 ; WX 761 ; N a22 ; B 35 0 727 692 ;
C 55 ; WX 571 ; N a23 ; B -1 -68 571 661 ;
C 56 ; WX 677 ; N a24 ; B 36 -13 642 705 ;
C 57 ; WX 763 ; N a25 ; B 35 0 728 692 ;
C 58 ; WX 760 ; N a26 ; B 35 0 726 692 ;
C 59 ; WX 759 ; N a27 ; B 35 0 725 692 ;
C 60 ; WX 754 ; N a28 ; B 35 0 720 692 ;
C 61 ; WX 494 ; N a6 ; B 35 0 460 692 ;
C 62 ; WX 552 ; N a7 ; B 35 0 517 692 ;
C 63 ; WX 537 ; N a8 ; B 35 0 503 692 ;
C 64 ; WX 577 ; N a9 ; B 35 96 542 596 ;
C 65 ; WX 692 ; N a10 ; B 35 -14 657 705 ;
C 66 ; WX 786 ; N a29 ; B 35 -14 751 705 ;
C 67 ; WX 788 ; N a30 ; B 35 -14 752 705 ;
C 68 ; WX 788 ; N a31 ; B 35 -14 753 705 ;
C 69 ; WX 790 ; N a32 ; B 35 -14 756 705 ;
C 70 ; WX 793 ; N a33 ; B 35 -13 759 705 ;
C 71 ; WX 794 ; N a34 ; B 35 -13 759 705 ;
C 72 ; WX 816 ; N a35 ; B 35 -14 782 705 ;
C 73 ; WX 823 ; N a36 ; B 35 -14 787 705 ;
C 74 ; WX 789 ; N a37 ; B 35 -14 754 705 ;
C 75 ; WX 841 ; N a38 ; B 35 -14 807 705 ;
C 76 ; WX 823 ; N a39 ; B 35 -14 789 705 ;
C 77 ; WX 833 ; N a40 ; B 35 -14 798 705 ;
C 78 ; WX 816 ; N a41 ; B 35 -13 782 705 ;
C 79 ; WX 831 ; N a42 ; B 35 -14 796 705 ;
C 80 ; WX 923 ; N a43 ; B 35 -14 888 705 ;
C 81 ; WX 744 ; N a44 ; B 35 0 710 692 ;
C 82 ; WX 723 ; N a45 ; B 35 0 688 692 ;
C 83 ; WX 749 ; N a46 ; B 35 0 714 692 ;
C 84 ; WX 790 ; N a47 ; B 34 -14 756 705 ;
C 85 ; WX 792 ; N a48 ; B 35 -14 758 705 ;
C 86 ; WX 695 ; N a49 ; B 35 -14 661 706 ;
C 87 ; WX 776 ; N a50 ; B 35 -6 741 699 ;
C 88 ; WX 768 ; N a51 ; B 35 -7 734 699 ;
C 89 ; WX 792 ; N a52 ; B 35 -14 757 705 ;
C 90 ; WX 759 ; N a53 ; B 35 0 725 692 ;
C 91 ; WX 707 ; N a54 ; B 35 -13 672 704 ;
C 92 ; WX 708 ; N a55 ; B 35 -14 672 705 ;
C 93 ; WX 682 ; N a56 ; B 35 -14 647 705 ;
C 94 ; WX 701 ; N a57 ; B 35 -14 666 705 ;
C 95 ; WX 826 ; N a58 ; B 35 -14 791 705 ;
C 96 ; WX 815 ; N a59 ; B 35 -14 780 705 ;
C 97 ; WX 789 ; N a60 ; B 35 -14 754 705 ;
C 98 ; WX 789 ; N a61 ; B 35 -14 754 705 ;
C 99 ; WX 707 ; N a62 ; B 34 -14 673 705 ;
C 100 ; WX 687 ; N a63 ; B 36 0 651 692 ;
C 101 ; WX 696 ; N a64 ; B 35 0 661 691 ;
C 102 ; WX 689 ; N a65 ; B 35 0 655 692 ;
C 103 ; WX 786 ; N a66 ; B 34 -14 751 705 ;
C 104 ; WX 787 ; N a67 ; B 35 -14 752 705 ;
C 105 ; WX 713 ; N a68 ; B 35 -14 678 705 ;
C 106 ; WX 791 ; N a69 ; B 35 -14 756 705 ;
C 107 ; WX 785 ; N a70 ; B 36 -14 751 705 ;
C 108 ; WX 791 ; N a71 ; B 35 -14 757 705 ;
C 109 ; WX 873 ; N a72 ; B 35 -14 838 705 ;
C 110 ; WX 761 ; N a73 ; B 35 0 726 692 ;
C 111 ; WX 762 ; N a74 ; B 35 0 727 692 ;
C 112 ; WX 762 ; N a203 ; B 35 0 727 692 ;
C 113 ; WX 759 ; N a75 ; B 35 0 725 692 ;
C 114 ; WX 759 ; N a204 ; B 35 0 725 692 ;
C 115 ; WX 892 ; N a76 ; B 35 0 858 705 ;
C 116 ; WX 892 ; N a77 ; B 35 -14 858 692 ;
C 117 ; WX 788 ; N a78 ; B 35 -14 754 705 ;
C 118 ; WX 784 ; N a79 ; B 35 -14 749 705 ;
C 119 ; WX 438 ; N a81 ; B 35 -14 403 705 ;
C 120 ; WX 138 ; N a82 ; B 35 0 104 692 ;
C 121 ; WX 277 ; N a83 ; B 35 0 242 692 ;
C 122 ; WX 415 ; N a84 ; B 35 0 380 692 ;
C 123 ; WX 392 ; N a97 ; B 35 263 357 705 ;
C 124 ; WX 392 ; N a98 ; B 34 263 357 705 ;
C 125 ; WX 668 ; N a99 ; B 35 263 633 705 ;
C 126 ; WX 668 ; N a100 ; B 36 263 634 705 ;
C 128 ; WX 390 ; N a89 ; B 35 -14 356 705 ;
C 129 ; WX 390 ; N a90 ; B 35 -14 355 705 ;
C 130 ; WX 317 ; N a93 ; B 35 0 283 692 ;
C 131 ; WX 317 ; N a94 ; B 35 0 283 692 ;
C 132 ; WX 276 ; N a91 ; B 35 0 242 692 ;
C 133 ; WX 276 ; N a92 ; B 35 0 242 692 ;
C 134 ; WX 509 ; N a205 ; B 35 0 475 692 ;
C 135 ; WX 509 ; N a85 ; B 35 0 475 692 ;
C 136 ; WX 410 ; N a206 ; B 35 0 375 692 ;
C 137 ; WX 410 ; N a86 ; B 35 0 375 692 ;
C 138 ; WX 234 ; N a87 ; B 35 -14 199 705 ;
C 139 ; WX 234 ; N a88 ; B 35 -14 199 705 ;
C 140 ; WX 334 ; N a95 ; B 35 0 299 692 ;
C 141 ; WX 334 ; N a96 ; B 35 0 299 692 ;
C 161 ; WX 732 ; N a101 ; B 35 -143 697 806 ;
C 162 ; WX 544 ; N a102 ; B 56 -14 488 706 ;
C 163 ; WX 544 ; N a103 ; B 34 -14 508 705 ;
C 164 ; WX 910 ; N a104 ; B 35 40 875 651 ;
C 165 ; WX 667 ; N a106 ; B 35 -14 633 705 ;
C 166 ; WX 760 ; N a107 ; B 35 -14 726 705 ;
C 167 ; WX 760 ; N a108 ; B 0 121 758 569 ;
C 168 ; WX 776 ; N a112 ; B 35 0 741 705 ;
C 169 ; WX 595 ; N a111 ; B 34 -14 560 705 ;
C 170 ; WX 694 ; N a110 ; B 35 -14 659 705 ;
C 171 ; WX 626 ; N a109 ; B 34 0 591 705 ;
C 172 ; WX 788 ; N a120 ; B 35 -14 754 705 ;
C 173 ; WX 788 ; N a121 ; B 35 -14 754 705 ;
C 174 ; WX 788 ; N a122 ; B 35 -14 754 705 ;
C 175 ; WX 788 ; N a123 ; B 35 -14 754 705 ;
C 176 ; WX 788 ; N a124 ; B 35 -14 754 705 ;
C 177 ; WX 788 ; N a125 ; B 35 -14 754 705 ;
C 178 ; WX 788 ; N a126 ; B 35 -14 754 705 ;
C 179 ; WX 788 ; N a127 ; B 35 -14 754 705 ;
C 180 ; WX 788 ; N a128 ; B 35 -14 754 705 ;
C 181 ; WX 788 ; N a129 ; B 35 -14 754 705 ;
C 182 ; WX 788 ; N a130 ; B 35 -14 754 705 ;
C 183 ; WX 788 ; N a131 ; B 35 -14 754 705 ;
C 184 ; WX 788 ; N a132 ; B 35 -14 754 705 ;
C 185 ; WX 788 ; N a133 ; B 35 -14 754 705 ;
C 186 ; WX 788 ; N a134 ; B 35 -14 754 705 ;
C 187 ; WX 788 ; N a135 ; B 35 -14 754 705 ;
C 188 ; WX 788 ; N a136 ; B 35 -14 754 705 ;
C 189 ; WX 788 ; N a137 ; B 35 -14 754 705 ;
C 190 ; WX 788 ; N a138 ; B 35 -14 754 705 ;
C 191 ; WX 788 ; N a139 ; B 35 -14 754 705 ;
C 192 ; WX 788 ; N a140 ; B 35 -14 754 705 ;
C 193 ; WX 788 ; N a141 ; B 35 -14 754 705 ;
C 194 ; WX 788 ; N a142 ; B 35 -14 754 705 ;
C 195 ; WX 788 ; N a143 ; B 35 -14 754 705 ;
C 196 ; WX 788 ; N a144 ; B 35 -14 754 705 ;
C 197 ; WX 788 ; N a145 ; B 35 -14 754 705 ;
C 198 ; WX 788 ; N a146 ; B 35 -14 754 705 ;
C 199 ; WX 788 ; N a147 ; B 35 -14 754 705 ;
C 200 ; WX 788 ; N a148 ; B 35 -14 754 705 ;
C 201 ; WX 788 ; N a149 ; B 35 -14 754 705 ;
C 202 ; WX 788 ; N a150 ; B 35 -14 754 705 ;
C 203 ; WX 788 ; N a151 ; B 35 -14 754 705 ;
C 204 ; WX 788 ; N a152 ; B 35 -14 754 705 ;
C 205 ; WX 788 ; N a153 ; B 35 -14 754 705 ;
C 206 ; WX 788 ; N a154 ; B 35 -14 754 705 ;
C 207 ; WX 788 ; N a155 ; B 35 -14 754 705 ;
C 208 ; WX 788 ; N a156 ; B 35 -14 754 705 ;
C 209 ; WX 788 ; N a157 ; B 35 -14 754 705 ;
C 210 ; WX 788 ; N a158 ; B 35 -14 754 705 ;
C 211 ; WX 788 ; N a159 ; B 35 -14 754 705 ;
C 212 ; WX 894 ; N a160 ; B 35 58 860 634 ;
C 213 ; WX 838 ; N a161 ; B 35 152 803 540 ;
C 214 ; WX 1016 ; N a163 ; B 34 152 981 540 ;
C 215 ; WX 458 ; N a164 ; B 35 -127 422 820 ;
C 216 ; WX 748 ; N a196 ; B 35 94 698 597 ;
C 217 ; WX 924 ; N a165 ; B 35 140 890 552 ;
C 218 ; WX 748 ; N a192 ; B 35 94 698 597 ;
C 219 ; WX 918 ; N a166 ; B 35 166 884 526 ;
C 220 ; WX 927 ; N a167 ; B 35 32 892 660 ;
C 221 ; WX 928 ; N a168 ; B 35 129 891 562 ;
C 222 ; WX 928 ; N a169 ; B 35 128 893 563 ;
C 223 ; WX 834 ; N a170 ; B 35 155 799 537 ;
C 224 ; WX 873 ; N a171 ; B 35 93 838 599 ;
C 225 ; WX 828 ; N a172 ; B 35 104 791 588 ;
C 226 ; WX 924 ; N a173 ; B 35 98 889 594 ;
C 227 ; WX 924 ; N a162 ; B 35 98 889 594 ;
C 228 ; WX 917 ; N a174 ; B 35 0 882 692 ;
C 229 ; WX 930 ; N a175 ; B 35 84 896 608 ;
C 230 ; WX 931 ; N a176 ; B 35 84 896 608 ;
C 231 ; WX 463 ; N a177 ; B 35 -99 429 791 ;
C 232 ; WX 883 ; N a178 ; B 35 71 848 623 ;
C 233 ; WX 836 ; N a179 ; B 35 44 802 648 ;
C 234 ; WX 836 ; N a193 ; B 35 44 802 648 ;
C 235 ; WX 867 ; N a180 ; B 35 101 832 591 ;
C 236 ; WX 867 ; N a199 ; B 35 101 832 591 ;
C 237 ; WX 696 ; N a181 ; B 35 44 661 648 ;
C 238 ; WX 696 ; N a200 ; B 35 44 661 648 ;
C 239 ; WX 874 ; N a182 ; B 35 77 840 619 ;
C 241 ; WX 874 ; N a201 ; B 35 73 840 615 ;
C 242 ; WX 760 ; N a183 ; B 35 0 725 692 ;
C 243 ; WX 946 ; N a184 ; B 35 160 911 533 ;
C 244 ; WX 771 ; N a197 ; B 34 37 736 655 ;
C 245 ; WX 865 ; N a185 ; B 35 207 830 481 ;
C 246 ; WX 771 ; N a194 ; B 34 37 736 655 ;
C 247 ; WX 888 ; N a198 ; B 34 -19 853 712 ;
C 248 ; WX 967 ; N a186 ; B 35 124 932 568 ;
C 249 ; WX 888 ; N a195 ; B 34 -19 853 712 ;
C 250 ; WX 831 ; N a187 ; B 35 113 796 579 ;
C 251 ; WX 873 ; N a188 ; B 36 118 838 578 ;
C 252 ; WX 927 ; N a189 ; B 35 150 891 542 ;
C 253 ; WX 970 ; N a190 ; B 35 76 931 616 ;
C 254 ; WX 918 ; N a191 ; B 34 99 884 593 ;
EndCharMetrics
EndFontMetrics

View file

@ -0,0 +1,72 @@
<?php return array (
'sans-serif' =>
array (
'normal' => DOMPDF_DIR . '/lib/fonts/Helvetica',
'bold' => DOMPDF_DIR . '/lib/fonts/Helvetica-Bold',
'italic' => DOMPDF_DIR . '/lib/fonts/Helvetica-Oblique',
'bold_italic' => DOMPDF_DIR . '/lib/fonts/Helvetica-BoldOblique',
),
'times' =>
array (
'normal' => DOMPDF_DIR . '/lib/fonts/Times-Roman',
'bold' => DOMPDF_DIR . '/lib/fonts/Times-Bold',
'italic' => DOMPDF_DIR . '/lib/fonts/Times-Italic',
'bold_italic' => DOMPDF_DIR . '/lib/fonts/Times-BoldItalic',
),
'times-roman' =>
array (
'normal' => DOMPDF_DIR . '/lib/fonts/Times-Roman',
'bold' => DOMPDF_DIR . '/lib/fonts/Times-Bold',
'italic' => DOMPDF_DIR . '/lib/fonts/Times-Italic',
'bold_italic' => DOMPDF_DIR . '/lib/fonts/Times-BoldItalic',
),
'courier' =>
array (
'normal' => DOMPDF_DIR . '/lib/fonts/Courier',
'bold' => DOMPDF_DIR . '/lib/fonts/Courier-Bold',
'italic' => DOMPDF_DIR . '/lib/fonts/Courier-Oblique',
'bold_italic' => DOMPDF_DIR . '/lib/fonts/Courier-BoldOblique',
),
'helvetica' =>
array (
'normal' => DOMPDF_DIR . '/lib/fonts/Helvetica',
'bold' => DOMPDF_DIR . '/lib/fonts/Helvetica-Bold',
'italic' => DOMPDF_DIR . '/lib/fonts/Helvetica-Oblique',
'bold_italic' => DOMPDF_DIR . '/lib/fonts/Helvetica-BoldOblique',
),
'zapfdingbats' =>
array (
'normal' => DOMPDF_DIR . '/lib/fonts/ZapfDingbats',
'bold' => DOMPDF_DIR . '/lib/fonts/ZapfDingbats',
'italic' => DOMPDF_DIR . '/lib/fonts/ZapfDingbats',
'bold_italic' => DOMPDF_DIR . '/lib/fonts/ZapfDingbats',
),
'symbol' =>
array (
'normal' => DOMPDF_DIR . '/lib/fonts/Symbol',
'bold' => DOMPDF_DIR . '/lib/fonts/Symbol',
'italic' => DOMPDF_DIR . '/lib/fonts/Symbol',
'bold_italic' => DOMPDF_DIR . '/lib/fonts/Symbol',
),
'serif' =>
array (
'normal' => DOMPDF_DIR . '/lib/fonts/Times-Roman',
'bold' => DOMPDF_DIR . '/lib/fonts/Times-Bold',
'italic' => DOMPDF_DIR . '/lib/fonts/Times-Italic',
'bold_italic' => DOMPDF_DIR . '/lib/fonts/Times-BoldItalic',
),
'monospace' =>
array (
'normal' => DOMPDF_DIR . '/lib/fonts/Courier',
'bold' => DOMPDF_DIR . '/lib/fonts/Courier-Bold',
'italic' => DOMPDF_DIR . '/lib/fonts/Courier-Oblique',
'bold_italic' => DOMPDF_DIR . '/lib/fonts/Courier-BoldOblique',
),
'fixed' =>
array (
'normal' => DOMPDF_DIR . '/lib/fonts/Courier',
'bold' => DOMPDF_DIR . '/lib/fonts/Courier-Bold',
'italic' => DOMPDF_DIR . '/lib/fonts/Courier-Oblique',
'bold_italic' => DOMPDF_DIR . '/lib/fonts/Courier-BoldOblique',
),
) ?>

View file

@ -0,0 +1,17 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
<meta name="generator" content="Adobe GoLive 4">
<title>Core 14 AFM Files - ReadMe</title>
</head>
<body bgcolor="white">
<font color="white">or</font>
<table border="0" cellpadding="0" cellspacing="2">
<tr>
<td width="40"></td>
<td width="300">This file and the 14 PostScript(R) AFM files it accompanies may be used, copied, and distributed for any purpose and without charge, with or without modification, provided that all copyright notices are retained; that the AFM files are not distributed without this file; that all modifications to this file or any of the AFM files are prominently noted in the modified file(s); and that this paragraph is not modified. Adobe Systems has no responsibility or obligation to support the use of the AFM files. <font color="white">Col</font></td>
</tr>
</table>
<p>Source <a href="http://www.adobe.com/devnet/font/#pcfi">http://www.adobe.com/devnet/font/#pcfi</a></p>
</body>
</html>

View file

@ -0,0 +1,114 @@
<?php
// warning: this file is encoded in UTF-8!
class HTML5_Data
{
// at some point this should be moved to a .ser file. Another
// possible optimization is to give UTF-8 bytes, not Unicode
// codepoints
// XXX: Not quite sure why it's named this; this is
// actually the numeric entity dereference table.
protected static $realCodepointTable = array(
0x00 => 0xFFFD, // REPLACEMENT CHARACTER
0x0D => 0x000A, // LINE FEED (LF)
0x80 => 0x20AC, // EURO SIGN ('€')
0x81 => 0x0081, // <control>
0x82 => 0x201A, // SINGLE LOW-9 QUOTATION MARK ('')
0x83 => 0x0192, // LATIN SMALL LETTER F WITH HOOK ('ƒ')
0x84 => 0x201E, // DOUBLE LOW-9 QUOTATION MARK ('„')
0x85 => 0x2026, // HORIZONTAL ELLIPSIS ('…')
0x86 => 0x2020, // DAGGER ('†')
0x87 => 0x2021, // DOUBLE DAGGER ('‡')
0x88 => 0x02C6, // MODIFIER LETTER CIRCUMFLEX ACCENT ('ˆ')
0x89 => 0x2030, // PER MILLE SIGN ('‰')
0x8A => 0x0160, // LATIN CAPITAL LETTER S WITH CARON ('Š')
0x8B => 0x2039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK ('')
0x8C => 0x0152, // LATIN CAPITAL LIGATURE OE ('Œ')
0x8D => 0x008D, // <control>
0x8E => 0x017D, // LATIN CAPITAL LETTER Z WITH CARON ('Ž')
0x8F => 0x008F, // <control>
0x90 => 0x0090, // <control>
0x91 => 0x2018, // LEFT SINGLE QUOTATION MARK ('')
0x92 => 0x2019, // RIGHT SINGLE QUOTATION MARK ('')
0x93 => 0x201C, // LEFT DOUBLE QUOTATION MARK ('“')
0x94 => 0x201D, // RIGHT DOUBLE QUOTATION MARK ('”')
0x95 => 0x2022, // BULLET ('•')
0x96 => 0x2013, // EN DASH ('')
0x97 => 0x2014, // EM DASH ('—')
0x98 => 0x02DC, // SMALL TILDE ('˜')
0x99 => 0x2122, // TRADE MARK SIGN ('™')
0x9A => 0x0161, // LATIN SMALL LETTER S WITH CARON ('š')
0x9B => 0x203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK ('')
0x9C => 0x0153, // LATIN SMALL LIGATURE OE ('œ')
0x9D => 0x009D, // <control>
0x9E => 0x017E, // LATIN SMALL LETTER Z WITH CARON ('ž')
0x9F => 0x0178, // LATIN CAPITAL LETTER Y WITH DIAERESIS ('Ÿ')
);
protected static $namedCharacterReferences;
protected static $namedCharacterReferenceMaxLength;
/**
* Returns the "real" Unicode codepoint of a malformed character
* reference.
*/
public static function getRealCodepoint($ref) {
if (!isset(self::$realCodepointTable[$ref])) return false;
else return self::$realCodepointTable[$ref];
}
public static function getNamedCharacterReferences() {
if (!self::$namedCharacterReferences) {
self::$namedCharacterReferences = unserialize(
file_get_contents(dirname(__FILE__) . '/named-character-references.ser'));
}
return self::$namedCharacterReferences;
}
/**
* Converts a Unicode codepoint to sequence of UTF-8 bytes.
* @note Shamelessly stolen from HTML Purifier, which is also
* shamelessly stolen from Feyd (which is in public domain).
*/
public static function utf8chr($code) {
/* We don't care: we live dangerously
* if($code > 0x10FFFF or $code < 0x0 or
($code >= 0xD800 and $code <= 0xDFFF) ) {
// bits are set outside the "valid" range as defined
// by UNICODE 4.1.0
return "\xEF\xBF\xBD";
}*/
$x = $y = $z = $w = 0;
if ($code < 0x80) {
// regular ASCII character
$x = $code;
} else {
// set up bits for UTF-8
$x = ($code & 0x3F) | 0x80;
if ($code < 0x800) {
$y = (($code & 0x7FF) >> 6) | 0xC0;
} else {
$y = (($code & 0xFC0) >> 6) | 0x80;
if($code < 0x10000) {
$z = (($code >> 12) & 0x0F) | 0xE0;
} else {
$z = (($code >> 12) & 0x3F) | 0x80;
$w = (($code >> 18) & 0x07) | 0xF0;
}
}
}
// set up the actual character
$ret = '';
if($w) $ret .= chr($w);
if($z) $ret .= chr($z);
if($y) $ret .= chr($y);
$ret .= chr($x);
return $ret;
}
}

View file

@ -0,0 +1,299 @@
<?php
/*
Copyright 2009 Geoffrey Sneddon <http://gsnedders.com/>
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.
*/
// Some conventions:
// /* */ indicates verbatim text from the HTML 5 specification
// // indicates regular comments
class HTML5_InputStream {
/**
* The string data we're parsing.
*/
private $data;
/**
* The current integer byte position we are in $data
*/
private $char;
/**
* Length of $data; when $char === $data, we are at the end-of-file.
*/
private $EOF;
/**
* Parse errors.
*/
public $errors = array();
/**
* @param $data | Data to parse
* @throws Exception
*/
public function __construct($data) {
/* Given an encoding, the bytes in the input stream must be
converted to Unicode characters for the tokeniser, as
described by the rules for that encoding, except that the
leading U+FEFF BYTE ORDER MARK character, if any, must not
be stripped by the encoding layer (it is stripped by the rule below).
Bytes or sequences of bytes in the original byte stream that
could not be converted to Unicode characters must be converted
to U+FFFD REPLACEMENT CHARACTER code points. */
// XXX currently assuming input data is UTF-8; once we
// build encoding detection this will no longer be the case
//
// We previously had an mbstring implementation here, but that
// implementation is heavily non-conforming, so it's been
// omitted.
if (extension_loaded('iconv')) {
// non-conforming
$data = @iconv('UTF-8', 'UTF-8//IGNORE', $data);
} else {
// we can make a conforming native implementation
throw new Exception('Not implemented, please install iconv');
}
/* One leading U+FEFF BYTE ORDER MARK character must be
ignored if any are present. */
if (substr($data, 0, 3) === "\xEF\xBB\xBF") {
$data = substr($data, 3);
}
/* All U+0000 NULL characters in the input must be replaced
by U+FFFD REPLACEMENT CHARACTERs. Any occurrences of such
characters is a parse error. */
for ($i = 0, $count = substr_count($data, "\0"); $i < $count; $i++) {
$this->errors[] = array(
'type' => HTML5_Tokenizer::PARSEERROR,
'data' => 'null-character'
);
}
/* U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED
(LF) characters are treated specially. Any CR characters
that are followed by LF characters must be removed, and any
CR characters not followed by LF characters must be converted
to LF characters. Thus, newlines in HTML DOMs are represented
by LF characters, and there are never any CR characters in the
input to the tokenization stage. */
$data = str_replace(
array(
"\0",
"\r\n",
"\r"
),
array(
"\xEF\xBF\xBD",
"\n",
"\n"
),
$data
);
/* Any occurrences of any characters in the ranges U+0001 to
U+0008, U+000B, U+000E to U+001F, U+007F to U+009F,
U+D800 to U+DFFF , U+FDD0 to U+FDEF, and
characters U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFFE, U+2FFFF,
U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF, U+6FFFE,
U+6FFFF, U+7FFFE, U+7FFFF, U+8FFFE, U+8FFFF, U+9FFFE, U+9FFFF,
U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF, U+CFFFE, U+CFFFF, U+DFFFE,
U+DFFFF, U+EFFFE, U+EFFFF, U+FFFFE, U+FFFFF, U+10FFFE, and
U+10FFFF are parse errors. (These are all control characters
or permanently undefined Unicode characters.) */
// Check PCRE is loaded.
if (extension_loaded('pcre')) {
$count = preg_match_all(
'/(?:
[\x01-\x08\x0B\x0E-\x1F\x7F] # U+0001 to U+0008, U+000B, U+000E to U+001F and U+007F
|
\xC2[\x80-\x9F] # U+0080 to U+009F
|
\xED(?:\xA0[\x80-\xFF]|[\xA1-\xBE][\x00-\xFF]|\xBF[\x00-\xBF]) # U+D800 to U+DFFFF
|
\xEF\xB7[\x90-\xAF] # U+FDD0 to U+FDEF
|
\xEF\xBF[\xBE\xBF] # U+FFFE and U+FFFF
|
[\xF0-\xF4][\x8F-\xBF]\xBF[\xBE\xBF] # U+nFFFE and U+nFFFF (1 <= n <= 10_{16})
)/x',
$data,
$matches
);
for ($i = 0; $i < $count; $i++) {
$this->errors[] = array(
'type' => HTML5_Tokenizer::PARSEERROR,
'data' => 'invalid-codepoint'
);
}
} else {
// XXX: Need non-PCRE impl, probably using substr_count
}
$this->data = $data;
$this->char = 0;
$this->EOF = strlen($data);
}
/**
* Returns the current line that the tokenizer is at.
*
* @return int
*/
public function getCurrentLine() {
// Check the string isn't empty
if ($this->EOF) {
// Add one to $this->char because we want the number for the next
// byte to be processed.
return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1;
} else {
// If the string is empty, we are on the first line (sorta).
return 1;
}
}
/**
* Returns the current column of the current line that the tokenizer is at.
*
* @return int
*/
public function getColumnOffset() {
// strrpos is weird, and the offset needs to be negative for what we
// want (i.e., the last \n before $this->char). This needs to not have
// one (to make it point to the next character, the one we want the
// position of) added to it because strrpos's behaviour includes the
// final offset byte.
$lastLine = strrpos($this->data, "\n", $this->char - 1 - strlen($this->data));
// However, for here we want the length up until the next byte to be
// processed, so add one to the current byte ($this->char).
if ($lastLine !== false) {
$findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine);
} else {
$findLengthOf = substr($this->data, 0, $this->char);
}
// Get the length for the string we need.
if (extension_loaded('iconv')) {
return iconv_strlen($findLengthOf, 'utf-8');
} elseif (extension_loaded('mbstring')) {
return mb_strlen($findLengthOf, 'utf-8');
} elseif (extension_loaded('xml')) {
return strlen(utf8_decode($findLengthOf));
} else {
$count = count_chars($findLengthOf);
// 0x80 = 0x7F - 0 + 1 (one added to get inclusive range)
// 0x33 = 0xF4 - 0x2C + 1 (one added to get inclusive range)
return array_sum(array_slice($count, 0, 0x80)) +
array_sum(array_slice($count, 0xC2, 0x33));
}
}
/**
* Retrieve the currently consume character.
* @note This performs bounds checking
*
* @return bool|string
*/
public function char() {
return ($this->char++ < $this->EOF)
? $this->data[$this->char - 1]
: false;
}
/**
* Get all characters until EOF.
* @note This performs bounds checking
*
* @return string|bool
*/
public function remainingChars() {
if ($this->char < $this->EOF) {
$data = substr($this->data, $this->char);
$this->char = $this->EOF;
return $data;
} else {
return false;
}
}
/**
* Matches as far as possible until we reach a certain set of bytes
* and returns the matched substring.
*
* @param $bytes | Bytes to match.
* @param null $max
* @return bool|string
*/
public function charsUntil($bytes, $max = null) {
if ($this->char < $this->EOF) {
if ($max === 0 || $max) {
$len = strcspn($this->data, $bytes, $this->char, $max);
} else {
$len = strcspn($this->data, $bytes, $this->char);
}
$string = (string) substr($this->data, $this->char, $len);
$this->char += $len;
return $string;
} else {
return false;
}
}
/**
* Matches as far as possible with a certain set of bytes
* and returns the matched substring.
*
* @param $bytes | Bytes to match.
* @param null $max
* @return bool|string
*/
public function charsWhile($bytes, $max = null) {
if ($this->char < $this->EOF) {
if ($max === 0 || $max) {
$len = strspn($this->data, $bytes, $this->char, $max);
} else {
$len = strspn($this->data, $bytes, $this->char);
}
$string = (string) substr($this->data, $this->char, $len);
$this->char += $len;
return $string;
} else {
return false;
}
}
/**
* Unconsume one character.
*/
public function unget() {
if ($this->char <= $this->EOF) {
$this->char--;
}
}
}

View file

@ -0,0 +1,37 @@
<?php
require_once dirname(__FILE__) . '/Data.php';
require_once dirname(__FILE__) . '/InputStream.php';
require_once dirname(__FILE__) . '/TreeBuilder.php';
require_once dirname(__FILE__) . '/Tokenizer.php';
/**
* Outwards facing interface for HTML5.
*/
class HTML5_Parser
{
/**
* Parses a full HTML document.
* @param $text | HTML text to parse
* @param $builder | Custom builder implementation
* @return DOMDocument|DOMNodeList Parsed HTML as DOMDocument
*/
static public function parse($text, $builder = null) {
$tokenizer = new HTML5_Tokenizer($text, $builder);
$tokenizer->parse();
return $tokenizer->save();
}
/**
* Parses an HTML fragment.
* @param $text | HTML text to parse
* @param $context String name of context element to pretend parsing is in.
* @param $builder | Custom builder implementation
* @return DOMDocument|DOMNodeList Parsed HTML as DOMDocument
*/
static public function parseFragment($text, $context = null, $builder = null) {
$tokenizer = new HTML5_Tokenizer($text, $builder);
$tokenizer->parseFragment($context);
return $tokenizer->save();
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

View file

@ -0,0 +1,521 @@
/**
* dompdf default stylesheet.
*
* @package dompdf
* @link http://dompdf.github.com/
* @author Benj Carson <benjcarson@digitaljunkies.ca>
* @author Blake Ross <BlakeR1234@aol.com>
* @author Fabien Ménager <fabien.menager@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
*
* Portions from Mozilla
* @link https://dxr.mozilla.org/mozilla-central/source/layout/style/res/html.css
* @license http://mozilla.org/MPL/2.0/ Mozilla Public License, v. 2.0
*
* Portions from W3C
* @link https://drafts.csswg.org/css-ui-3/#default-style-sheet
*
*/
@page {
margin: 1.2cm;
}
html {
display: -dompdf-page;
counter-reset: page;
}
/* blocks */
article,
aside,
details,
div,
dt,
figcaption,
footer,
form,
header,
hgroup,
main,
nav,
noscript,
section,
summary {
display: block;
}
body {
page-break-before: avoid;
display: block;
counter-increment: page;
}
p, dl, multicol {
display: block;
margin: 1em 0;
}
dd {
display: block;
margin-left: 40px;
}
blockquote, figure {
display: block;
margin: 1em 40px;
}
address {
display: block;
font-style: italic;
}
center {
display: block;
text-align: center;
}
blockquote[type=cite] {
display: block;
margin: 1em 0;
padding-left: 1em;
border-left: solid;
border-color: blue;
border-width: thin;
}
h1, h2, h3, h4, h5, h6 {
display: block;
font-weight: bold;
}
h1 {
font-size: 2em;
margin: .67em 0;
}
h2 {
font-size: 1.5em;
margin: .83em 0;
}
h3 {
font-size: 1.17em;
margin: 1em 0;
}
h4 {
margin: 1.33em 0;
}
h5 {
font-size: 0.83em;
margin: 1.67em 0;
}
h6 {
font-size: 0.67em;
margin: 2.33em 0;
}
listing {
display: block;
font-family: fixed;
font-size: medium;
white-space: pre;
margin: 1em 0;
}
plaintext, pre, xmp {
display: block;
font-family: fixed;
white-space: pre;
margin: 1em 0;
}
/* tables */
table {
display: table;
border-spacing: 2px;
border-collapse: separate;
margin-top: 0;
margin-bottom: 0;
text-indent: 0;
text-align: left; /* quirk */
}
table[border] {
border-style: outset;
border-color: gray;
}
/* This won't work (???) */
/*
table[border] td,
table[border] th {
border: 1pt solid grey;
}*/
/* make sure backgrounds are inherited in tables -- see bug 4510 */
td, th, tr {
background: inherit;
}
/* caption inherits from table not table-outer */
caption {
display: table-caption;
text-align: center;
}
tr {
display: table-row;
vertical-align: inherit;
}
col {
display: table-column;
}
colgroup {
display: table-column-group;
}
tbody {
display: table-row-group;
vertical-align: middle;
}
thead {
display: table-header-group;
vertical-align: middle;
}
tfoot {
display: table-footer-group;
vertical-align: middle;
}
/* To simulate tbody auto-insertion */
table > tr {
vertical-align: middle;
}
td {
display: table-cell;
vertical-align: inherit;
text-align: inherit;
padding: 1px;
}
th {
display: table-cell;
vertical-align: inherit;
font-weight: bold;
padding: 1px;
}
/* inlines */
q {
quotes: '"' '"' "'" "'"; /* FIXME only the first level is used */
}
q:before {
content: open-quote;
}
q:after {
content: close-quote;
}
:link {
color: #00c;
text-decoration: underline;
}
b, strong {
font-weight: bolder;
}
i, cite, em, var, dfn {
font-style: italic;
}
tt, code, kbd, samp {
font-family: fixed;
}
u, ins {
text-decoration: underline;
}
s, strike, del {
text-decoration: line-through;
}
big {
font-size: larger;
}
small {
font-size: smaller;
}
sub {
vertical-align: sub;
font-size: smaller;
line-height: normal;
}
sup {
vertical-align: super;
font-size: smaller;
line-height: normal;
}
nobr {
white-space: nowrap;
}
mark {
background: yellow;
color: black;
}
/* titles */
abbr[title], acronym[title] {
text-decoration: dotted underline;
}
/* lists */
ul, menu, dir {
display: block;
list-style-type: disc;
margin: 1em 0;
padding-left: 40px;
}
ol {
display: block;
list-style-type: decimal;
margin: 1em 0;
padding-left: 40px;
}
li {
display: list-item;
}
/*li:before {
display: -dompdf-list-bullet !important;
content: counter(-dompdf-default-counter) ". ";
padding-right: 0.5em;
}*/
/* nested lists have no top/bottom margins */
:matches(ul, ol, dir, menu, dl) ul,
:matches(ul, ol, dir, menu, dl) ol,
:matches(ul, ol, dir, menu, dl) dir,
:matches(ul, ol, dir, menu, dl) menu,
:matches(ul, ol, dir, menu, dl) dl {
margin-top: 0;
margin-bottom: 0;
}
/* 2 deep unordered lists use a circle */
:matches(ul, ol, dir, menu) ul,
:matches(ul, ol, dir, menu) ul,
:matches(ul, ol, dir, menu) ul,
:matches(ul, ol, dir, menu) ul {
list-style-type: circle;
}
/* 3 deep (or more) unordered lists use a square */
:matches(ul, ol, dir, menu) :matches(ul, ol, dir, menu) ul,
:matches(ul, ol, dir, menu) :matches(ul, ol, dir, menu) menu,
:matches(ul, ol, dir, menu) :matches(ul, ol, dir, menu) dir {
list-style-type: square;
}
/* forms */
/* From https://drafts.csswg.org/css-ui-3/#default-style-sheet */
form {
display: block;
}
input, button, select {
display: inline-block;
font-family: sans-serif;
}
input[type=text],
input[type=password],
select {
width: 12em;
}
input[type=text],
input[type=password],
input[type=button],
input[type=submit],
input[type=reset],
input[type=file],
button,
textarea,
select {
background: #FFF;
border: 1px solid #999;
padding: 2px;
margin: 2px;
}
input[type=button],
input[type=submit],
input[type=reset],
input[type=file],
button {
background: #CCC;
text-align: center;
}
input[type=file] {
width: 8em;
}
input[type=text]:before,
input[type=button]:before,
input[type=submit]:before,
input[type=reset]:before {
content: attr(value);
}
input[type=file]:before {
content: "Choose a file";
}
input[type=password][value]:before {
font-family: "DejaVu Sans" !important;
content: "\2022\2022\2022\2022\2022\2022\2022\2022";
line-height: 1em;
}
input[type=checkbox],
input[type=radio],
select:after {
font-family: "DejaVu Sans" !important;
font-size: 18px;
line-height: 1;
}
input[type=checkbox]:before {
content: "\2610";
}
input[type=checkbox][checked]:before {
content: "\2611";
}
input[type=radio]:before {
content: "\25CB";
}
input[type=radio][checked]:before {
content: "\25C9";
}
textarea {
display: block;
height: 3em;
overflow: hidden;
font-family: monospace;
white-space: pre-wrap;
word-wrap: break-word;
}
select {
position: relative!important;
overflow: hidden!important;
}
select:after {
position: absolute;
right: 0;
top: 0;
height: 5em;
width: 1.4em;
text-align: center;
background: #CCC;
content: "\25BE";
}
select option {
display: none;
}
select option[selected] {
display: inline;
}
fieldset {
display: block;
margin: 0.6em 2px 2px;
padding: 0.75em;
border: 1pt groove #666;
position: relative;
}
fieldset > legend {
position: absolute;
top: -0.6em;
left: 0.75em;
padding: 0 0.3em;
background: white;
}
legend {
display: inline-block;
}
/* leafs */
hr {
display: block;
height: 0;
border: 1px inset;
margin: 0.5em auto 0.5em auto;
}
hr[size="1"] {
border-style: solid none none none;
}
iframe {
border: 2px inset;
}
noframes {
display: block;
}
br {
display: -dompdf-br;
}
img, img_generated {
display: -dompdf-image;
}
dompdf_generated {
display: inline;
}
/* hidden elements */
area, base, basefont, head, meta, script, style, title,
noembed, param {
display: none;
-dompdf-keep: yes;
}

View file

@ -0,0 +1,142 @@
<?xml version="1.0"?>
<!--suppress XmlUnboundNsPrefix -->
<ruleset name="PHP-SDK">
<description>Coding standard ruleset based on the PSR-2 coding standard.</description>
<rule ref="PSR2"/>
<rule ref="Generic.Files.LineLength.TooLong">
<severity>0</severity>
</rule>
<rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
<severity>0</severity>
</rule>
<rule ref="PSR2.Methods.MethodDeclaration.Underscore">
<severity>0</severity>
</rule>
<rule ref="PSR2.Classes.PropertyDeclaration.Underscore">
<severity>0</severity>
</rule>
<rule ref="Squiz.Scope.MethodScope.Missing">
<severity>0</severity>
</rule>
<rule ref="PSR2.ControlStructures.SwitchDeclaration.TerminatingComment">
<severity>0</severity>
</rule>
<rule ref="PEAR.Functions.ValidDefaultValue.NotAtEnd">
<severity>0</severity>
</rule>
<rule ref="PSR1.Files.SideEffects.FoundWithSymbols">
<severity>0</severity>
</rule>
<rule ref="PSR2.Classes.PropertyDeclaration.ScopeMissing">
<severity>0</severity>
</rule>
<!-- These can be fixed automatically by phpcbf -->
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.EndLine">
<severity>0</severity>
</rule>
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.EndLine">
<severity>0</severity>
</rule>
<rule ref="Squiz.WhiteSpace.ControlStructureSpacing.SpacingAfterOpen">
<severity>0</severity>
</rule>
<rule ref="Squiz.WhiteSpace.ControlStructureSpacing.SpacingBeforeClose">
<severity>0</severity>
</rule>
<rule ref="Generic.ControlStructures.InlineControlStructure.NotAllowed">
<severity>0</severity>
</rule>
<rule ref="Squiz.ControlStructures.ControlSignature.SpaceBeforeSemicolon">
<severity>0</severity>
</rule>
<rule ref="PSR2.Files.EndFileNewline.NoneFound">
<severity>0</severity>
</rule>
<rule ref="PSR2.Classes.ClassDeclaration.CloseBraceAfterBody">
<severity>0</severity>
</rule>
<rule ref="PSR2.ControlStructures.ElseIfDeclaration.NotAllowed">
<severity>0</severity>
</rule>
<rule ref="PSR2.Methods.FunctionCallSignature.CloseBracketLine">
<severity>0</severity>
</rule>
<rule ref="PSR2.Methods.FunctionCallSignature.Indent">
<severity>0</severity>
</rule>
<rule ref="PSR2.ControlStructures.ElseIfDeclaration.NotAllowed">
<severity>0</severity>
</rule>
<rule ref="Squiz.ControlStructures.ControlSignature.SpaceAfterCloseBrace">
<severity>0</severity>
</rule>
<rule ref="PSR2.ControlStructures.ControlStructureSpacing.SpaceBeforeCloseBrace">
<severity>0</severity>
</rule>
<rule ref="PSR2.Methods.FunctionCallSignature.ContentAfterOpenBracket">
<severity>0</severity>
</rule>
<rule ref="Squiz.WhiteSpace.ControlStructureSpacing.SpacingAfterOpenBrace">
<severity>0</severity>
</rule>
<rule ref="PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace">
<severity>0</severity>
</rule>
<rule ref="PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace">
<severity>0</severity>
</rule>
<rule ref="Generic.Functions.FunctionCallArgumentSpacing.SpaceBeforeComma">
<severity>0</severity>
</rule>
<rule ref="Squiz.WhiteSpace.ScopeClosingBrace.ContentBefore">
<severity>0</severity>
</rule>
<rule ref="Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace">
<severity>0</severity>
</rule>
<rule ref="PSR2.Methods.FunctionCallSignature.SpaceBeforeCloseBracket">
<severity>0</severity>
</rule>
<rule ref="Squiz.ControlStructures.ControlSignature.SpaceAfterCloseParenthesis">
<severity>0</severity>
</rule>
<rule ref="PSR2.ControlStructures.SwitchDeclaration.SpaceBeforeColonCASE">
<severity>0</severity>
</rule>
<rule ref="PSR2.Methods.FunctionCallSignature.MultipleArguments">
<severity>0</severity>
</rule>
<rule ref="PSR2.Methods.FunctionCallSignature.SpaceAfterOpenBracket">
<severity>0</severity>
</rule>
<rule ref="Generic.WhiteSpace.ScopeIndent.Incorrect">
<severity>0</severity>
</rule>
<rule ref="Squiz.ControlStructures.ControlSignature.SpaceAfterKeyword">
<severity>0</severity>
</rule>
<rule ref="PSR2.Classes.ClassDeclaration.OpenBraceNewLine">
<severity>0</severity>
</rule>
<rule ref="Squiz.Functions.MultiLineFunctionDeclaration.SpaceAfterFunction">
<severity>0</severity>
</rule>
<rule ref="Generic.Formatting.DisallowMultipleStatements.SameLine">
<severity>0</severity>
</rule>
<rule ref="PSR2.ControlStructures.SwitchDeclaration.BodyOnNextLineCASE">
<severity>0</severity>
</rule>
<rule ref="PSR2.Files.EndFileNewline.TooMany">
<severity>0</severity>
</rule>
<rule ref="Squiz.Functions.MultiLineFunctionDeclaration.ContentAfterBrace">
<severity>0</severity>
</rule>
<rule ref="PSR2.Methods.MethodDeclaration.StaticBeforeVisibility">
<severity>0</severity>
</rule>
<rule ref="Squiz.Functions.MultiLineFunctionDeclaration.BraceOnSameLine">
<severity>0</severity>
</rule>
</ruleset>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
<?php
namespace Dompdf;
/**
* Autoloads Dompdf classes
*
* @package Dompdf
*/
class Autoloader
{
const PREFIX = 'Dompdf';
/**
* Register the autoloader
*/
public static function register()
{
spl_autoload_register(array(new self, 'autoload'));
}
/**
* Autoloader
*
* @param string
*/
public static function autoload($class)
{
if ($class === 'Cpdf') {
require_once __DIR__ . "/../lib/Cpdf.php";
return;
}
$prefixLength = strlen(self::PREFIX);
if (0 === strncmp(self::PREFIX, $class, $prefixLength)) {
$file = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, $prefixLength));
$file = realpath(__DIR__ . (empty($file) ? '' : DIRECTORY_SEPARATOR) . $file . '.php');
if (file_exists($file)) {
require_once $file;
}
}
}
}

View file

@ -0,0 +1,422 @@
<?php
/**
* @package dompdf
* @link http://dompdf.github.com/
* @author Benj Carson <benjcarson@digitaljunkies.ca>
* @author Fabien Ménager <fabien.menager@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
*/
namespace Dompdf;
/**
* Main rendering interface
*
* Currently {@link Dompdf\Adapter\CPDF}, {@link Dompdf\Adapter\PDFLib}, and {@link Dompdf\Adapter\GD}
* implement this interface.
*
* Implementations should measure x and y increasing to the left and down,
* respectively, with the origin in the top left corner. Implementations
* are free to use a unit other than points for length, but I can't
* guarantee that the results will look any good.
*
* @package dompdf
*/
interface Canvas
{
function __construct($paper = "letter", $orientation = "portrait", Dompdf $dompdf);
/**
* @return Dompdf
*/
function get_dompdf();
/**
* Returns the current page number
*
* @return int
*/
function get_page_number();
/**
* Returns the total number of pages
*
* @return int
*/
function get_page_count();
/**
* Sets the total number of pages
*
* @param int $count
*/
function set_page_count($count);
/**
* Draws a line from x1,y1 to x2,y2
*
* See {@link Style::munge_color()} for the format of the color array.
* See {@link Cpdf::setLineStyle()} for a description of the format of the
* $style parameter (aka dash).
*
* @param float $x1
* @param float $y1
* @param float $x2
* @param float $y2
* @param array $color
* @param float $width
* @param array $style
*/
function line($x1, $y1, $x2, $y2, $color, $width, $style = null);
/**
* Draws a rectangle at x1,y1 with width w and height h
*
* See {@link Style::munge_color()} for the format of the color array.
* See {@link Cpdf::setLineStyle()} for a description of the $style
* parameter (aka dash)
*
* @param float $x1
* @param float $y1
* @param float $w
* @param float $h
* @param array $color
* @param float $width
* @param array $style
*/
function rectangle($x1, $y1, $w, $h, $color, $width, $style = null);
/**
* Draws a filled rectangle at x1,y1 with width w and height h
*
* See {@link Style::munge_color()} for the format of the color array.
*
* @param float $x1
* @param float $y1
* @param float $w
* @param float $h
* @param array $color
*/
function filled_rectangle($x1, $y1, $w, $h, $color);
/**
* Starts a clipping rectangle at x1,y1 with width w and height h
*
* @param float $x1
* @param float $y1
* @param float $w
* @param float $h
*/
function clipping_rectangle($x1, $y1, $w, $h);
/**
* Starts a rounded clipping rectangle at x1,y1 with width w and height h
*
* @param float $x1
* @param float $y1
* @param float $w
* @param float $h
* @param float $tl
* @param float $tr
* @param float $br
* @param float $bl
*
* @return
*/
function clipping_roundrectangle($x1, $y1, $w, $h, $tl, $tr, $br, $bl);
/**
* Ends the last clipping shape
*/
function clipping_end();
/**
* Save current state
*/
function save();
/**
* Restore last state
*/
function restore();
/**
* Rotate
*
* @param float $angle angle in degrees for counter-clockwise rotation
* @param float $x Origin abscissa
* @param float $y Origin ordinate
*/
function rotate($angle, $x, $y);
/**
* Skew
*
* @param float $angle_x
* @param float $angle_y
* @param float $x Origin abscissa
* @param float $y Origin ordinate
*/
function skew($angle_x, $angle_y, $x, $y);
/**
* Scale
*
* @param float $s_x scaling factor for width as percent
* @param float $s_y scaling factor for height as percent
* @param float $x Origin abscissa
* @param float $y Origin ordinate
*/
function scale($s_x, $s_y, $x, $y);
/**
* Translate
*
* @param float $t_x movement to the right
* @param float $t_y movement to the bottom
*/
function translate($t_x, $t_y);
/**
* Transform
*
* @param $a
* @param $b
* @param $c
* @param $d
* @param $e
* @param $f
* @return
*/
function transform($a, $b, $c, $d, $e, $f);
/**
* Draws a polygon
*
* The polygon is formed by joining all the points stored in the $points
* array. $points has the following structure:
* <code>
* array(0 => x1,
* 1 => y1,
* 2 => x2,
* 3 => y2,
* ...
* );
* </code>
*
* See {@link Style::munge_color()} for the format of the color array.
* See {@link Cpdf::setLineStyle()} for a description of the $style
* parameter (aka dash)
*
* @param array $points
* @param array $color
* @param float $width
* @param array $style
* @param bool $fill Fills the polygon if true
*/
function polygon($points, $color, $width = null, $style = null, $fill = false);
/**
* Draws a circle at $x,$y with radius $r
*
* See {@link Style::munge_color()} for the format of the color array.
* See {@link Cpdf::setLineStyle()} for a description of the $style
* parameter (aka dash)
*
* @param float $x
* @param float $y
* @param float $r
* @param array $color
* @param float $width
* @param array $style
* @param bool $fill Fills the circle if true
*/
function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false);
/**
* Add an image to the pdf.
*
* The image is placed at the specified x and y coordinates with the
* given width and height.
*
* @param string $img_url the path to the image
* @param float $x x position
* @param float $y y position
* @param int $w width (in pixels)
* @param int $h height (in pixels)
* @param string $resolution The resolution of the image
*/
function image($img_url, $x, $y, $w, $h, $resolution = "normal");
/**
* Add an arc to the PDF
* See {@link Style::munge_color()} for the format of the color array.
*
* @param float $x X coordinate of the arc
* @param float $y Y coordinate of the arc
* @param float $r1 Radius 1
* @param float $r2 Radius 2
* @param float $astart Start angle in degrees
* @param float $aend End angle in degrees
* @param array $color Color
* @param float $width
* @param array $style
*/
function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = array());
/**
* Writes text at the specified x and y coordinates
* See {@link Style::munge_color()} for the format of the color array.
*
* @param float $x
* @param float $y
* @param string $text the text to write
* @param string $font the font file to use
* @param float $size the font size, in points
* @param array $color
* @param float $word_space word spacing adjustment
* @param float $char_space char spacing adjustment
* @param float $angle angle
*/
function text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0);
/**
* Add a named destination (similar to <a name="foo">...</a> in html)
*
* @param string $anchorname The name of the named destination
*/
function add_named_dest($anchorname);
/**
* Add a link to the pdf
*
* @param string $url The url to link to
* @param float $x The x position of the link
* @param float $y The y position of the link
* @param float $width The width of the link
* @param float $height The height of the link
*/
function add_link($url, $x, $y, $width, $height);
/**
* Add meta information to the pdf
*
* @param string $name Label of the value (Creator, Producer, etc.)
* @param string $value The text to set
*/
function add_info($name, $value);
/**
* Calculates text size, in points
*
* @param string $text the text to be sized
* @param string $font the desired font
* @param float $size the desired font size
* @param float $word_spacing word spacing, if any
* @param float $char_spacing
*
* @return float
*/
function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0);
/**
* Calculates font height, in points
*
* @param string $font
* @param float $size
*
* @return float
*/
function get_font_height($font, $size);
/**
* Calculates font baseline, in points
*
* @param string $font
* @param float $size
*
* @return float
*/
function get_font_baseline($font, $size);
/**
* Returns the PDF's width in points
*
* @return float
*/
function get_width();
/**
* Return the image's height in pixels
*
* @return float
*/
function get_height();
/**
* Returns the font x-height, in points
*
* @param string $font
* @param float $size
*
* @return float
*/
//function get_font_x_height($font, $size);
/**
* Sets the opacity
*
* @param float $opacity
* @param string $mode
*/
function set_opacity($opacity, $mode = "Normal");
/**
* Sets the default view
*
* @param string $view
* 'XYZ' left, top, zoom
* 'Fit'
* 'FitH' top
* 'FitV' left
* 'FitR' left,bottom,right
* 'FitB'
* 'FitBH' top
* 'FitBV' left
* @param array $options
*
* @return void
*/
function set_default_view($view, $options = array());
/**
* @param string $script
*
* @return void
*/
function javascript($script);
/**
* Starts a new page
*
* Subsequent drawing operations will appear on the new page.
*/
function new_page();
/**
* Streams the PDF directly to the browser
*
* @param string $filename the name of the PDF file
* @param array $options associative array, 'Attachment' => 0 or 1, 'compress' => 1 or 0
*/
function stream($filename, $options = null);
/**
* Returns the PDF as a string
*
* @param array $options associative array: 'compress' => 1 or 0
* @return string
*/
function output($options = null);
}

View file

@ -0,0 +1,59 @@
<?php
/**
* @package dompdf
* @link http://dompdf.github.com/
* @author Benj Carson <benjcarson@digitaljunkies.ca>
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
*/
namespace Dompdf;
/**
* Create canvas instances
*
* The canvas factory creates canvas instances based on the
* availability of rendering backends and config options.
*
* @package dompdf
*/
class CanvasFactory
{
/**
* Constructor is private: this is a static class
*/
private function __construct()
{
}
/**
* @param Dompdf $dompdf
* @param string|array $paper
* @param string $orientation
* @param string $class
*
* @return Canvas
*/
static function get_instance(Dompdf $dompdf, $paper = null, $orientation = null, $class = null)
{
$backend = strtolower($dompdf->getOptions()->getPdfBackend());
if (isset($class) && class_exists($class, false)) {
$class .= "_Adapter";
} else {
if (($backend === "auto" || $backend === "pdflib") &&
class_exists("PDFLib", false)
) {
$class = "Dompdf\\Adapter\\PDFLib";
}
else {
if ($backend === "gd") {
$class = "Dompdf\\Adapter\\GD";
} else {
$class = "Dompdf\\Adapter\\CPDF";
}
}
}
return new $class($paper, $orientation, $dompdf);
}
}

View file

@ -0,0 +1,918 @@
<?php
/**
* @package dompdf
* @link http://dompdf.github.com/
* @author Benj Carson <benjcarson@digitaljunkies.ca>
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
*/
namespace Dompdf;
use Dompdf\Exception;
use Dompdf\Frame;
use Dompdf\FrameDecorator\Table as TableFrameDecorator;
use Dompdf\FrameDecorator\TableCell as TableCellFrameDecorator;
/**
* Maps table cells to the table grid.
*
* This class resolves borders in tables with collapsed borders and helps
* place row & column spanned table cells.
*
* @package dompdf
*/
class Cellmap
{
/**
* Border style weight lookup for collapsed border resolution.
*
* @var array
*/
protected static $_BORDER_STYLE_SCORE = array(
"inset" => 1,
"groove" => 2,
"outset" => 3,
"ridge" => 4,
"dotted" => 5,
"dashed" => 6,
"solid" => 7,
"double" => 8,
"hidden" => 9,
"none" => 0,
);
/**
* The table object this cellmap is attached to.
*
* @var TableFrameDecorator
*/
protected $_table;
/**
* The total number of rows in the table
*
* @var int
*/
protected $_num_rows;
/**
* The total number of columns in the table
*
* @var int
*/
protected $_num_cols;
/**
* 2D array mapping <row,column> to frames
*
* @var Frame[][]
*/
protected $_cells;
/**
* 1D array of column dimensions
*
* @var array
*/
protected $_columns;
/**
* 1D array of row dimensions
*
* @var array
*/
protected $_rows;
/**
* 2D array of border specs
*
* @var array
*/
protected $_borders;
/**
* 1D Array mapping frames to (multiple) <row, col> pairs, keyed on frame_id.
*
* @var Frame[]
*/
protected $_frames;
/**
* Current column when adding cells, 0-based
*
* @var int
*/
private $__col;
/**
* Current row when adding cells, 0-based
*
* @var int
*/
private $__row;
/**
* Tells wether the columns' width can be modified
*
* @var bool
*/
private $_columns_locked = false;
/**
* Tells wether the table has table-layout:fixed
*
* @var bool
*/
private $_fixed_layout = false;
/**
* @param TableFrameDecorator $table
*/
public function __construct(TableFrameDecorator $table)
{
$this->_table = $table;
$this->reset();
}
/**
*
*/
public function reset()
{
$this->_num_rows = 0;
$this->_num_cols = 0;
$this->_cells = array();
$this->_frames = array();
if (!$this->_columns_locked) {
$this->_columns = array();
}
$this->_rows = array();
$this->_borders = array();
$this->__col = $this->__row = 0;
}
/**
*
*/
public function lock_columns()
{
$this->_columns_locked = true;
}
/**
* @return bool
*/
public function is_columns_locked()
{
return $this->_columns_locked;
}
/**
* @param $fixed
*/
public function set_layout_fixed($fixed)
{
$this->_fixed_layout = $fixed;
}
/**
* @return bool
*/
public function is_layout_fixed()
{
return $this->_fixed_layout;
}
/**
* @return int
*/
public function get_num_rows()
{
return $this->_num_rows;
}
/**
* @return int
*/
public function get_num_cols()
{
return $this->_num_cols;
}
/**
* @return array
*/
public function &get_columns()
{
return $this->_columns;
}
/**
* @param $columns
*/
public function set_columns($columns)
{
$this->_columns = $columns;
}
/**
* @param int $i
*
* @return mixed
*/
public function &get_column($i)
{
if (!isset($this->_columns[$i])) {
$this->_columns[$i] = array(
"x" => 0,
"min-width" => 0,
"max-width" => 0,
"used-width" => null,
"absolute" => 0,
"percent" => 0,
"auto" => true,
);
}
return $this->_columns[$i];
}
/**
* @return array
*/
public function &get_rows()
{
return $this->_rows;
}
/**
* @param int $j
*
* @return mixed
*/
public function &get_row($j)
{
if (!isset($this->_rows[$j])) {
$this->_rows[$j] = array(
"y" => 0,
"first-column" => 0,
"height" => null,
);
}
return $this->_rows[$j];
}
/**
* @param int $i
* @param int $j
* @param mixed $h_v
* @param null|mixed $prop
*
* @return mixed
*/
public function get_border($i, $j, $h_v, $prop = null)
{
if (!isset($this->_borders[$i][$j][$h_v])) {
$this->_borders[$i][$j][$h_v] = array(
"width" => 0,
"style" => "solid",
"color" => "black",
);
}
if (isset($prop)) {
return $this->_borders[$i][$j][$h_v][$prop];
}
return $this->_borders[$i][$j][$h_v];
}
/**
* @param int $i
* @param int $j
*
* @return array
*/
public function get_border_properties($i, $j)
{
return array(
"top" => $this->get_border($i, $j, "horizontal"),
"right" => $this->get_border($i, $j + 1, "vertical"),
"bottom" => $this->get_border($i + 1, $j, "horizontal"),
"left" => $this->get_border($i, $j, "vertical"),
);
}
/**
* @param Frame $frame
*
* @return null|Frame
*/
public function get_spanned_cells(Frame $frame)
{
$key = $frame->get_id();
if (isset($this->_frames[$key])) {
return $this->_frames[$key];
}
return null;
}
/**
* @param Frame $frame
*
* @return bool
*/
public function frame_exists_in_cellmap(Frame $frame)
{
$key = $frame->get_id();
return isset($this->_frames[$key]);
}
/**
* @param Frame $frame
*
* @return array
* @throws Exception
*/
public function get_frame_position(Frame $frame)
{
global $_dompdf_warnings;
$key = $frame->get_id();
if (!isset($this->_frames[$key])) {
throw new Exception("Frame not found in cellmap");
}
$col = $this->_frames[$key]["columns"][0];
$row = $this->_frames[$key]["rows"][0];
if (!isset($this->_columns[$col])) {
$_dompdf_warnings[] = "Frame not found in columns array. Check your table layout for missing or extra TDs.";
$x = 0;
} else {
$x = $this->_columns[$col]["x"];
}
if (!isset($this->_rows[$row])) {
$_dompdf_warnings[] = "Frame not found in row array. Check your table layout for missing or extra TDs.";
$y = 0;
} else {
$y = $this->_rows[$row]["y"];
}
return array($x, $y, "x" => $x, "y" => $y);
}
/**
* @param Frame $frame
*
* @return int
* @throws Exception
*/
public function get_frame_width(Frame $frame)
{
$key = $frame->get_id();
if (!isset($this->_frames[$key])) {
throw new Exception("Frame not found in cellmap");
}
$cols = $this->_frames[$key]["columns"];
$w = 0;
foreach ($cols as $i) {
$w += $this->_columns[$i]["used-width"];
}
return $w;
}
/**
* @param Frame $frame
*
* @return int
* @throws Exception
* @throws Exception
*/
public function get_frame_height(Frame $frame)
{
$key = $frame->get_id();
if (!isset($this->_frames[$key])) {
throw new Exception("Frame not found in cellmap");
}
$rows = $this->_frames[$key]["rows"];
$h = 0;
foreach ($rows as $i) {
if (!isset($this->_rows[$i])) {
throw new Exception("The row #$i could not be found, please file an issue in the tracker with the HTML code");
}
$h += $this->_rows[$i]["height"];
}
return $h;
}
/**
* @param int $j
* @param mixed $width
*/
public function set_column_width($j, $width)
{
if ($this->_columns_locked) {
return;
}
$col =& $this->get_column($j);
$col["used-width"] = $width;
$next_col =& $this->get_column($j + 1);
$next_col["x"] = $next_col["x"] + $width;
}
/**
* @param int $i
* @param mixed $height
*/
public function set_row_height($i, $height)
{
$row =& $this->get_row($i);
if ($row["height"] !== null && $height <= $row["height"]) {
return;
}
$row["height"] = $height;
$next_row =& $this->get_row($i + 1);
$next_row["y"] = $row["y"] + $height;
}
/**
* @param int $i
* @param int $j
* @param mixed $h_v
* @param mixed $border_spec
*
* @return mixed
*/
protected function _resolve_border($i, $j, $h_v, $border_spec)
{
$n_width = $border_spec["width"];
$n_style = $border_spec["style"];
if (!isset($this->_borders[$i][$j][$h_v])) {
$this->_borders[$i][$j][$h_v] = $border_spec;
return $this->_borders[$i][$j][$h_v]["width"];
}
$border = & $this->_borders[$i][$j][$h_v];
$o_width = $border["width"];
$o_style = $border["style"];
if (($n_style === "hidden" ||
$n_width > $o_width ||
$o_style === "none")
or
($o_width == $n_width &&
in_array($n_style, self::$_BORDER_STYLE_SCORE) &&
self::$_BORDER_STYLE_SCORE[$n_style] > self::$_BORDER_STYLE_SCORE[$o_style])
) {
$border = $border_spec;
}
return $border["width"];
}
/**
* @param Frame $frame
*/
public function add_frame(Frame $frame)
{
$style = $frame->get_style();
$display = $style->display;
$collapse = $this->_table->get_style()->border_collapse == "collapse";
// Recursively add the frames within tables, table-row-groups and table-rows
if ($display === "table-row" ||
$display === "table" ||
$display === "inline-table" ||
in_array($display, TableFrameDecorator::$ROW_GROUPS)
) {
$start_row = $this->__row;
foreach ($frame->get_children() as $child) {
// Ignore all Text frames and :before/:after pseudo-selector elements.
if (!($child instanceof FrameDecorator\Text) && $child->get_node()->nodeName !== 'dompdf_generated') {
$this->add_frame($child);
}
}
if ($display === "table-row") {
$this->add_row();
}
$num_rows = $this->__row - $start_row - 1;
$key = $frame->get_id();
// Row groups always span across the entire table
$this->_frames[$key]["columns"] = range(0, max(0, $this->_num_cols - 1));
$this->_frames[$key]["rows"] = range($start_row, max(0, $this->__row - 1));
$this->_frames[$key]["frame"] = $frame;
if ($display !== "table-row" && $collapse) {
$bp = $style->get_border_properties();
// Resolve the borders
for ($i = 0; $i < $num_rows + 1; $i++) {
$this->_resolve_border($start_row + $i, 0, "vertical", $bp["left"]);
$this->_resolve_border($start_row + $i, $this->_num_cols, "vertical", $bp["right"]);
}
for ($j = 0; $j < $this->_num_cols; $j++) {
$this->_resolve_border($start_row, $j, "horizontal", $bp["top"]);
$this->_resolve_border($this->__row, $j, "horizontal", $bp["bottom"]);
}
}
return;
}
$node = $frame->get_node();
// Determine where this cell is going
$colspan = $node->getAttribute("colspan");
$rowspan = $node->getAttribute("rowspan");
if (!$colspan) {
$colspan = 1;
$node->setAttribute("colspan", 1);
}
if (!$rowspan) {
$rowspan = 1;
$node->setAttribute("rowspan", 1);
}
$key = $frame->get_id();
$bp = $style->get_border_properties();
// Add the frame to the cellmap
$max_left = $max_right = 0;
// Find the next available column (fix by Ciro Mondueri)
$ac = $this->__col;
while (isset($this->_cells[$this->__row][$ac])) {
$ac++;
}
$this->__col = $ac;
// Rows:
for ($i = 0; $i < $rowspan; $i++) {
$row = $this->__row + $i;
$this->_frames[$key]["rows"][] = $row;
for ($j = 0; $j < $colspan; $j++) {
$this->_cells[$row][$this->__col + $j] = $frame;
}
if ($collapse) {
// Resolve vertical borders
$max_left = max($max_left, $this->_resolve_border($row, $this->__col, "vertical", $bp["left"]));
$max_right = max($max_right, $this->_resolve_border($row, $this->__col + $colspan, "vertical", $bp["right"]));
}
}
$max_top = $max_bottom = 0;
// Columns:
for ($j = 0; $j < $colspan; $j++) {
$col = $this->__col + $j;
$this->_frames[$key]["columns"][] = $col;
if ($collapse) {
// Resolve horizontal borders
$max_top = max($max_top, $this->_resolve_border($this->__row, $col, "horizontal", $bp["top"]));
$max_bottom = max($max_bottom, $this->_resolve_border($this->__row + $rowspan, $col, "horizontal", $bp["bottom"]));
}
}
$this->_frames[$key]["frame"] = $frame;
// Handle seperated border model
if (!$collapse) {
list($h, $v) = $this->_table->get_style()->border_spacing;
// Border spacing is effectively a margin between cells
$v = $style->length_in_pt($v);
if (is_numeric($v)) {
$v = $v / 2;
}
$h = $style->length_in_pt($h);
if (is_numeric($h)) {
$h = $h / 2;
}
$style->margin = "$v $h";
// The additional 1/2 width gets added to the table proper
} else {
// Drop the frame's actual border
$style->border_left_width = $max_left / 2;
$style->border_right_width = $max_right / 2;
$style->border_top_width = $max_top / 2;
$style->border_bottom_width = $max_bottom / 2;
$style->margin = "none";
}
if (!$this->_columns_locked) {
// Resolve the frame's width
if ($this->_fixed_layout) {
list($frame_min, $frame_max) = array(0, 10e-10);
} else {
list($frame_min, $frame_max) = $frame->get_min_max_width();
}
$width = $style->width;
$val = null;
if (Helpers::is_percent($width)) {
$var = "percent";
$val = (float)rtrim($width, "% ") / $colspan;
} else if ($width !== "auto") {
$var = "absolute";
$val = $style->length_in_pt($frame_min) / $colspan;
}
$min = 0;
$max = 0;
for ($cs = 0; $cs < $colspan; $cs++) {
// Resolve the frame's width(s) with other cells
$col =& $this->get_column($this->__col + $cs);
// Note: $var is either 'percent' or 'absolute'. We compare the
// requested percentage or absolute values with the existing widths
// and adjust accordingly.
if (isset($var) && $val > $col[$var]) {
$col[$var] = $val;
$col["auto"] = false;
}
$min += $col["min-width"];
$max += $col["max-width"];
}
if ($frame_min > $min) {
// The frame needs more space. Expand each sub-column
// FIXME try to avoid putting this dummy value when table-layout:fixed
$inc = ($this->is_layout_fixed() ? 10e-10 : ($frame_min - $min) / $colspan);
for ($c = 0; $c < $colspan; $c++) {
$col =& $this->get_column($this->__col + $c);
$col["min-width"] += $inc;
}
}
if ($frame_max > $max) {
// FIXME try to avoid putting this dummy value when table-layout:fixed
$inc = ($this->is_layout_fixed() ? 10e-10 : ($frame_max - $max) / $colspan);
for ($c = 0; $c < $colspan; $c++) {
$col =& $this->get_column($this->__col + $c);
$col["max-width"] += $inc;
}
}
}
$this->__col += $colspan;
if ($this->__col > $this->_num_cols) {
$this->_num_cols = $this->__col;
}
}
/**
*
*/
public function add_row()
{
$this->__row++;
$this->_num_rows++;
// Find the next available column
$i = 0;
while (isset($this->_cells[$this->__row][$i])) {
$i++;
}
$this->__col = $i;
}
/**
* Remove a row from the cellmap.
*
* @param Frame
*/
public function remove_row(Frame $row)
{
$key = $row->get_id();
if (!isset($this->_frames[$key])) {
return; // Presumably this row has alredy been removed
}
$this->__row = $this->_num_rows--;
$rows = $this->_frames[$key]["rows"];
$columns = $this->_frames[$key]["columns"];
// Remove all frames from this row
foreach ($rows as $r) {
foreach ($columns as $c) {
if (isset($this->_cells[$r][$c])) {
$id = $this->_cells[$r][$c]->get_id();
$this->_cells[$r][$c] = null;
unset($this->_cells[$r][$c]);
// has multiple rows?
if (isset($this->_frames[$id]) && count($this->_frames[$id]["rows"]) > 1) {
// remove just the desired row, but leave the frame
if (($row_key = array_search($r, $this->_frames[$id]["rows"])) !== false) {
unset($this->_frames[$id]["rows"][$row_key]);
}
continue;
}
$this->_frames[$id] = null;
unset($this->_frames[$id]);
}
}
$this->_rows[$r] = null;
unset($this->_rows[$r]);
}
$this->_frames[$key] = null;
unset($this->_frames[$key]);
}
/**
* Remove a row group from the cellmap.
*
* @param Frame $group The group to remove
*/
public function remove_row_group(Frame $group)
{
$key = $group->get_id();
if (!isset($this->_frames[$key])) {
return; // Presumably this row has alredy been removed
}
$iter = $group->get_first_child();
while ($iter) {
$this->remove_row($iter);
$iter = $iter->get_next_sibling();
}
$this->_frames[$key] = null;
unset($this->_frames[$key]);
}
/**
* Update a row group after rows have been removed
*
* @param Frame $group The group to update
* @param Frame $last_row The last row in the row group
*/
public function update_row_group(Frame $group, Frame $last_row)
{
$g_key = $group->get_id();
$r_key = $last_row->get_id();
$r_rows = $this->_frames[$g_key]["rows"];
$this->_frames[$g_key]["rows"] = range($this->_frames[$g_key]["rows"][0], end($r_rows));
}
/**
*
*/
public function assign_x_positions()
{
// Pre-condition: widths must be resolved and assigned to columns and
// column[0]["x"] must be set.
if ($this->_columns_locked) {
return;
}
$x = $this->_columns[0]["x"];
foreach (array_keys($this->_columns) as $j) {
$this->_columns[$j]["x"] = $x;
$x += $this->_columns[$j]["used-width"];
}
}
/**
*
*/
public function assign_frame_heights()
{
// Pre-condition: widths and heights of each column & row must be
// calcluated
foreach ($this->_frames as $arr) {
$frame = $arr["frame"];
$h = 0;
foreach ($arr["rows"] as $row) {
if (!isset($this->_rows[$row])) {
// The row has been removed because of a page split, so skip it.
continue;
}
$h += $this->_rows[$row]["height"];
}
if ($frame instanceof TableCellFrameDecorator) {
$frame->set_cell_height($h);
} else {
$frame->get_style()->height = $h;
}
}
}
/**
* Re-adjust frame height if the table height is larger than its content
*/
public function set_frame_heights($table_height, $content_height)
{
// Distribute the increased height proportionally amongst each row
foreach ($this->_frames as $arr) {
$frame = $arr["frame"];
$h = 0;
foreach ($arr["rows"] as $row) {
if (!isset($this->_rows[$row])) {
continue;
}
$h += $this->_rows[$row]["height"];
}
if ($content_height > 0) {
$new_height = ($h / $content_height) * $table_height;
} else {
$new_height = 0;
}
if ($frame instanceof TableCellFrameDecorator) {
$frame->set_cell_height($new_height);
} else {
$frame->get_style()->height = $new_height;
}
}
}
/**
* Used for debugging:
*
* @return string
*/
public function __toString()
{
$str = "";
$str .= "Columns:<br/>";
$str .= Helpers::pre_r($this->_columns, true);
$str .= "Rows:<br/>";
$str .= Helpers::pre_r($this->_rows, true);
$str .= "Frames:<br/>";
$arr = array();
foreach ($this->_frames as $key => $val) {
$arr[$key] = array("columns" => $val["columns"], "rows" => $val["rows"]);
}
$str .= Helpers::pre_r($arr, true);
if (php_sapi_name() == "cli") {
$str = strip_tags(str_replace(array("<br/>", "<b>", "</b>"),
array("\n", chr(27) . "[01;33m", chr(27) . "[0m"),
$str));
}
return $str;
}
}

View file

@ -0,0 +1,639 @@
<?php
/**
* @package dompdf
* @link http://dompdf.github.com/
* @author Benj Carson <benjcarson@digitaljunkies.ca>
* @author Fabien Ménager <fabien.menager@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
*/
namespace Dompdf\Css;
use Dompdf\Frame;
/**
* Translates HTML 4.0 attributes into CSS rules
*
* @package dompdf
*/
class AttributeTranslator
{
static $_style_attr = "_html_style_attribute";
// Munged data originally from
// http://www.w3.org/TR/REC-html40/index/attributes.html
// http://www.cs.tut.fi/~jkorpela/html2css.html
static private $__ATTRIBUTE_LOOKUP = array(
//'caption' => array ( 'align' => '', ),
'img' => array(
'align' => array(
'bottom' => 'vertical-align: baseline;',
'middle' => 'vertical-align: middle;',
'top' => 'vertical-align: top;',
'left' => 'float: left;',
'right' => 'float: right;'
),
'border' => 'border: %0.2Fpx solid;',
'height' => 'height: %spx;',
'hspace' => 'padding-left: %1$0.2Fpx; padding-right: %1$0.2Fpx;',
'vspace' => 'padding-top: %1$0.2Fpx; padding-bottom: %1$0.2Fpx;',
'width' => 'width: %spx;',
),
'table' => array(
'align' => array(
'left' => 'margin-left: 0; margin-right: auto;',
'center' => 'margin-left: auto; margin-right: auto;',
'right' => 'margin-left: auto; margin-right: 0;'
),
'bgcolor' => 'background-color: %s;',
'border' => '!set_table_border',
'cellpadding' => '!set_table_cellpadding', //'border-spacing: %0.2F; border-collapse: separate;',
'cellspacing' => '!set_table_cellspacing',
'frame' => array(
'void' => 'border-style: none;',
'above' => 'border-top-style: solid;',
'below' => 'border-bottom-style: solid;',
'hsides' => 'border-left-style: solid; border-right-style: solid;',
'vsides' => 'border-top-style: solid; border-bottom-style: solid;',
'lhs' => 'border-left-style: solid;',
'rhs' => 'border-right-style: solid;',
'box' => 'border-style: solid;',
'border' => 'border-style: solid;'
),
'rules' => '!set_table_rules',
'width' => 'width: %s;',
),
'hr' => array(
'align' => '!set_hr_align', // Need to grab width to set 'left' & 'right' correctly
'noshade' => 'border-style: solid;',
'size' => '!set_hr_size', //'border-width: %0.2F px;',
'width' => 'width: %s;',
),
'div' => array(
'align' => 'text-align: %s;',
),
'h1' => array(
'align' => 'text-align: %s;',
),
'h2' => array(
'align' => 'text-align: %s;',
),
'h3' => array(
'align' => 'text-align: %s;',
),
'h4' => array(
'align' => 'text-align: %s;',
),
'h5' => array(
'align' => 'text-align: %s;',
),
'h6' => array(
'align' => 'text-align: %s;',
),
//TODO: translate more form element attributes
'input' => array(
'size' => '!set_input_width'
),
'p' => array(
'align' => 'text-align: %s;',
),
// 'col' => array(
// 'align' => '',
// 'valign' => '',
// ),
// 'colgroup' => array(
// 'align' => '',
// 'valign' => '',
// ),
'tbody' => array(
'align' => '!set_table_row_align',
'valign' => '!set_table_row_valign',
),
'td' => array(
'align' => 'text-align: %s;',
'bgcolor' => '!set_background_color',
'height' => 'height: %s;',
'nowrap' => 'white-space: nowrap;',
'valign' => 'vertical-align: %s;',
'width' => 'width: %s;',
),
'tfoot' => array(
'align' => '!set_table_row_align',
'valign' => '!set_table_row_valign',
),
'th' => array(
'align' => 'text-align: %s;',
'bgcolor' => '!set_background_color',
'height' => 'height: %s;',
'nowrap' => 'white-space: nowrap;',
'valign' => 'vertical-align: %s;',
'width' => 'width: %s;',
),
'thead' => array(
'align' => '!set_table_row_align',
'valign' => '!set_table_row_valign',
),
'tr' => array(
'align' => '!set_table_row_align',
'bgcolor' => '!set_table_row_bgcolor',
'valign' => '!set_table_row_valign',
),
'body' => array(
'background' => 'background-image: url(%s);',
'bgcolor' => '!set_background_color',
'link' => '!set_body_link',
'text' => '!set_color',
),
'br' => array(
'clear' => 'clear: %s;',
),
'basefont' => array(
'color' => '!set_color',
'face' => 'font-family: %s;',
'size' => '!set_basefont_size',
),
'font' => array(
'color' => '!set_color',
'face' => 'font-family: %s;',
'size' => '!set_font_size',
),
'dir' => array(
'compact' => 'margin: 0.5em 0;',
),
'dl' => array(
'compact' => 'margin: 0.5em 0;',
),
'menu' => array(
'compact' => 'margin: 0.5em 0;',
),
'ol' => array(
'compact' => 'margin: 0.5em 0;',
'start' => 'counter-reset: -dompdf-default-counter %d;',
'type' => 'list-style-type: %s;',
),
'ul' => array(
'compact' => 'margin: 0.5em 0;',
'type' => 'list-style-type: %s;',
),
'li' => array(
'type' => 'list-style-type: %s;',
'value' => 'counter-reset: -dompdf-default-counter %d;',
),
'pre' => array(
'width' => 'width: %s;',
),
);
static protected $_last_basefont_size = 3;
static protected $_font_size_lookup = array(
// For basefont support
-3 => "4pt",
-2 => "5pt",
-1 => "6pt",
0 => "7pt",
1 => "8pt",
2 => "10pt",
3 => "12pt",
4 => "14pt",
5 => "18pt",
6 => "24pt",
7 => "34pt",
// For basefont support
8 => "48pt",
9 => "44pt",
10 => "52pt",
11 => "60pt",
);
/**
* @param Frame $frame
*/
static function translate_attributes(Frame $frame)
{
$node = $frame->get_node();
$tag = $node->nodeName;
if (!isset(self::$__ATTRIBUTE_LOOKUP[$tag])) {
return;
}
$valid_attrs = self::$__ATTRIBUTE_LOOKUP[$tag];
$attrs = $node->attributes;
$style = rtrim($node->getAttribute(self::$_style_attr), "; ");
if ($style != "") {
$style .= ";";
}
foreach ($attrs as $attr => $attr_node) {
if (!isset($valid_attrs[$attr])) {
continue;
}
$value = $attr_node->value;
$target = $valid_attrs[$attr];
// Look up $value in $target, if $target is an array:
if (is_array($target)) {
if (isset($target[$value])) {
$style .= " " . self::_resolve_target($node, $target[$value], $value);
}
} else {
// otherwise use target directly
$style .= " " . self::_resolve_target($node, $target, $value);
}
}
if (!is_null($style)) {
$style = ltrim($style);
$node->setAttribute(self::$_style_attr, $style);
}
}
/**
* @param \DOMNode $node
* @param string $target
* @param string $value
*
* @return string
*/
static protected function _resolve_target(\DOMNode $node, $target, $value)
{
if ($target[0] === "!") {
// Function call
$func = "_" . mb_substr($target, 1);
return self::$func($node, $value);
}
return $value ? sprintf($target, $value) : "";
}
/**
* @param \DOMElement $node
* @param string $new_style
*/
static function append_style(\DOMElement $node, $new_style)
{
$style = rtrim($node->getAttribute(self::$_style_attr), ";");
$style .= $new_style;
$style = ltrim($style, ";");
$node->setAttribute(self::$_style_attr, $style);
}
/**
* @param \DOMNode $node
*
* @return \DOMNodeList|\DOMElement[]
*/
static protected function get_cell_list(\DOMNode $node)
{
$xpath = new \DOMXpath($node->ownerDocument);
switch ($node->nodeName) {
default:
case "table":
$query = "tr/td | thead/tr/td | tbody/tr/td | tfoot/tr/td | tr/th | thead/tr/th | tbody/tr/th | tfoot/tr/th";
break;
case "tbody":
case "tfoot":
case "thead":
$query = "tr/td | tr/th";
break;
case "tr":
$query = "td | th";
break;
}
return $xpath->query($query, $node);
}
/**
* @param string $value
*
* @return string
*/
static protected function _get_valid_color($value)
{
if (preg_match('/^#?([0-9A-F]{6})$/i', $value, $matches)) {
$value = "#$matches[1]";
}
return $value;
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return string
*/
static protected function _set_color(\DOMElement $node, $value)
{
$value = self::_get_valid_color($value);
return "color: $value;";
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return string
*/
static protected function _set_background_color(\DOMElement $node, $value)
{
$value = self::_get_valid_color($value);
return "background-color: $value;";
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return null
*/
static protected function _set_table_cellpadding(\DOMElement $node, $value)
{
$cell_list = self::get_cell_list($node);
foreach ($cell_list as $cell) {
self::append_style($cell, "; padding: {$value}px;");
}
return null;
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return string
*/
static protected function _set_table_border(\DOMElement $node, $value)
{
$cell_list = self::get_cell_list($node);
foreach ($cell_list as $cell) {
$style = rtrim($cell->getAttribute(self::$_style_attr));
$style .= "; border-width: " . ($value > 0 ? 1 : 0) . "pt; border-style: inset;";
$style = ltrim($style, ";");
$cell->setAttribute(self::$_style_attr, $style);
}
$style = rtrim($node->getAttribute(self::$_style_attr), ";");
$style .= "; border-width: $value" . "px; ";
return ltrim($style, "; ");
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return string
*/
static protected function _set_table_cellspacing(\DOMElement $node, $value)
{
$style = rtrim($node->getAttribute(self::$_style_attr), ";");
if ($value == 0) {
$style .= "; border-collapse: collapse;";
} else {
$style .= "; border-spacing: {$value}px; border-collapse: separate;";
}
return ltrim($style, ";");
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return null|string
*/
static protected function _set_table_rules(\DOMElement $node, $value)
{
$new_style = "; border-collapse: collapse;";
switch ($value) {
case "none":
$new_style .= "border-style: none;";
break;
case "groups":
// FIXME: unsupported
return null;
case "rows":
$new_style .= "border-style: solid none solid none; border-width: 1px; ";
break;
case "cols":
$new_style .= "border-style: none solid none solid; border-width: 1px; ";
break;
case "all":
$new_style .= "border-style: solid; border-width: 1px; ";
break;
default:
// Invalid value
return null;
}
$cell_list = self::get_cell_list($node);
foreach ($cell_list as $cell) {
$style = $cell->getAttribute(self::$_style_attr);
$style .= $new_style;
$cell->setAttribute(self::$_style_attr, $style);
}
$style = rtrim($node->getAttribute(self::$_style_attr), ";");
$style .= "; border-collapse: collapse; ";
return ltrim($style, "; ");
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return string
*/
static protected function _set_hr_size(\DOMElement $node, $value)
{
$style = rtrim($node->getAttribute(self::$_style_attr), ";");
$style .= "; border-width: " . max(0, $value - 2) . "; ";
return ltrim($style, "; ");
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return null|string
*/
static protected function _set_hr_align(\DOMElement $node, $value)
{
$style = rtrim($node->getAttribute(self::$_style_attr), ";");
$width = $node->getAttribute("width");
if ($width == "") {
$width = "100%";
}
$remainder = 100 - (double)rtrim($width, "% ");
switch ($value) {
case "left":
$style .= "; margin-right: $remainder %;";
break;
case "right":
$style .= "; margin-left: $remainder %;";
break;
case "center":
$style .= "; margin-left: auto; margin-right: auto;";
break;
default:
return null;
}
return ltrim($style, "; ");
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return null|string
*/
static protected function _set_input_width(\DOMElement $node, $value)
{
if (empty($value)) { return null; }
if ($node->hasAttribute("type") && in_array(strtolower($node->getAttribute("type")), array("text","password"))) {
return sprintf("width: %Fem", (((int)$value * .65)+2));
} else {
return sprintf("width: %upx;", (int)$value);
}
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return null
*/
static protected function _set_table_row_align(\DOMElement $node, $value)
{
$cell_list = self::get_cell_list($node);
foreach ($cell_list as $cell) {
self::append_style($cell, "; text-align: $value;");
}
return null;
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return null
*/
static protected function _set_table_row_valign(\DOMElement $node, $value)
{
$cell_list = self::get_cell_list($node);
foreach ($cell_list as $cell) {
self::append_style($cell, "; vertical-align: $value;");
}
return null;
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return null
*/
static protected function _set_table_row_bgcolor(\DOMElement $node, $value)
{
$cell_list = self::get_cell_list($node);
$value = self::_get_valid_color($value);
foreach ($cell_list as $cell) {
self::append_style($cell, "; background-color: $value;");
}
return null;
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return null
*/
static protected function _set_body_link(\DOMElement $node, $value)
{
$a_list = $node->getElementsByTagName("a");
$value = self::_get_valid_color($value);
foreach ($a_list as $a) {
self::append_style($a, "; color: $value;");
}
return null;
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return null
*/
static protected function _set_basefont_size(\DOMElement $node, $value)
{
// FIXME: ? we don't actually set the font size of anything here, just
// the base size for later modification by <font> tags.
self::$_last_basefont_size = $value;
return null;
}
/**
* @param \DOMElement $node
* @param string $value
*
* @return string
*/
static protected function _set_font_size(\DOMElement $node, $value)
{
$style = $node->getAttribute(self::$_style_attr);
if ($value[0] === "-" || $value[0] === "+") {
$value = self::$_last_basefont_size + (int)$value;
}
if (isset(self::$_font_size_lookup[$value])) {
$style .= "; font-size: " . self::$_font_size_lookup[$value] . ";";
} else {
$style .= "; font-size: $value;";
}
return ltrim($style, "; ");
}
}

View file

@ -0,0 +1,307 @@
<?php
/**
* @package dompdf
* @link http://dompdf.github.com/
* @author Benj Carson <benjcarson@digitaljunkies.ca>
* @author Fabien Ménager <fabien.menager@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
*/
namespace Dompdf\Css;
use Dompdf\Helpers;
class Color
{
static $cssColorNames = array(
"aliceblue" => "F0F8FF",
"antiquewhite" => "FAEBD7",
"aqua" => "00FFFF",
"aquamarine" => "7FFFD4",
"azure" => "F0FFFF",
"beige" => "F5F5DC",
"bisque" => "FFE4C4",
"black" => "000000",
"blanchedalmond" => "FFEBCD",
"blue" => "0000FF",
"blueviolet" => "8A2BE2",
"brown" => "A52A2A",
"burlywood" => "DEB887",
"cadetblue" => "5F9EA0",
"chartreuse" => "7FFF00",
"chocolate" => "D2691E",
"coral" => "FF7F50",
"cornflowerblue" => "6495ED",
"cornsilk" => "FFF8DC",
"crimson" => "DC143C",
"cyan" => "00FFFF",
"darkblue" => "00008B",
"darkcyan" => "008B8B",
"darkgoldenrod" => "B8860B",
"darkgray" => "A9A9A9",
"darkgreen" => "006400",
"darkgrey" => "A9A9A9",
"darkkhaki" => "BDB76B",
"darkmagenta" => "8B008B",
"darkolivegreen" => "556B2F",
"darkorange" => "FF8C00",
"darkorchid" => "9932CC",
"darkred" => "8B0000",
"darksalmon" => "E9967A",
"darkseagreen" => "8FBC8F",
"darkslateblue" => "483D8B",
"darkslategray" => "2F4F4F",
"darkslategrey" => "2F4F4F",
"darkturquoise" => "00CED1",
"darkviolet" => "9400D3",
"deeppink" => "FF1493",
"deepskyblue" => "00BFFF",
"dimgray" => "696969",
"dimgrey" => "696969",
"dodgerblue" => "1E90FF",
"firebrick" => "B22222",
"floralwhite" => "FFFAF0",
"forestgreen" => "228B22",
"fuchsia" => "FF00FF",
"gainsboro" => "DCDCDC",
"ghostwhite" => "F8F8FF",
"gold" => "FFD700",
"goldenrod" => "DAA520",
"gray" => "808080",
"green" => "008000",
"greenyellow" => "ADFF2F",
"grey" => "808080",
"honeydew" => "F0FFF0",
"hotpink" => "FF69B4",
"indianred" => "CD5C5C",
"indigo" => "4B0082",
"ivory" => "FFFFF0",
"khaki" => "F0E68C",
"lavender" => "E6E6FA",
"lavenderblush" => "FFF0F5",
"lawngreen" => "7CFC00",
"lemonchiffon" => "FFFACD",
"lightblue" => "ADD8E6",
"lightcoral" => "F08080",
"lightcyan" => "E0FFFF",
"lightgoldenrodyellow" => "FAFAD2",
"lightgray" => "D3D3D3",
"lightgreen" => "90EE90",
"lightgrey" => "D3D3D3",
"lightpink" => "FFB6C1",
"lightsalmon" => "FFA07A",
"lightseagreen" => "20B2AA",
"lightskyblue" => "87CEFA",
"lightslategray" => "778899",
"lightslategrey" => "778899",
"lightsteelblue" => "B0C4DE",
"lightyellow" => "FFFFE0",
"lime" => "00FF00",
"limegreen" => "32CD32",
"linen" => "FAF0E6",
"magenta" => "FF00FF",
"maroon" => "800000",
"mediumaquamarine" => "66CDAA",
"mediumblue" => "0000CD",
"mediumorchid" => "BA55D3",
"mediumpurple" => "9370DB",
"mediumseagreen" => "3CB371",
"mediumslateblue" => "7B68EE",
"mediumspringgreen" => "00FA9A",
"mediumturquoise" => "48D1CC",
"mediumvioletred" => "C71585",
"midnightblue" => "191970",
"mintcream" => "F5FFFA",
"mistyrose" => "FFE4E1",
"moccasin" => "FFE4B5",
"navajowhite" => "FFDEAD",
"navy" => "000080",
"oldlace" => "FDF5E6",
"olive" => "808000",
"olivedrab" => "6B8E23",
"orange" => "FFA500",
"orangered" => "FF4500",
"orchid" => "DA70D6",
"palegoldenrod" => "EEE8AA",
"palegreen" => "98FB98",
"paleturquoise" => "AFEEEE",
"palevioletred" => "DB7093",
"papayawhip" => "FFEFD5",
"peachpuff" => "FFDAB9",
"peru" => "CD853F",
"pink" => "FFC0CB",
"plum" => "DDA0DD",
"powderblue" => "B0E0E6",
"purple" => "800080",
"red" => "FF0000",
"rosybrown" => "BC8F8F",
"royalblue" => "4169E1",
"saddlebrown" => "8B4513",
"salmon" => "FA8072",
"sandybrown" => "F4A460",
"seagreen" => "2E8B57",
"seashell" => "FFF5EE",
"sienna" => "A0522D",
"silver" => "C0C0C0",
"skyblue" => "87CEEB",
"slateblue" => "6A5ACD",
"slategray" => "708090",
"slategrey" => "708090",
"snow" => "FFFAFA",
"springgreen" => "00FF7F",
"steelblue" => "4682B4",
"tan" => "D2B48C",
"teal" => "008080",
"thistle" => "D8BFD8",
"tomato" => "FF6347",
"turquoise" => "40E0D0",
"violet" => "EE82EE",
"wheat" => "F5DEB3",
"white" => "FFFFFF",
"whitesmoke" => "F5F5F5",
"yellow" => "FFFF00",
"yellowgreen" => "9ACD32",
);
/**
* @param $color
* @return array|mixed|null|string
*/
static function parse($color)
{
if (is_array($color)) {
// Assume the array has the right format...
// FIXME: should/could verify this.
return $color;
}
static $cache = array();
$color = strtolower($color);
if (isset($cache[$color])) {
return $cache[$color];
}
if (in_array($color, array("transparent", "inherit"))) {
return $cache[$color] = $color;
}
if (isset(self::$cssColorNames[$color])) {
return $cache[$color] = self::getArray(self::$cssColorNames[$color]);
}
$length = mb_strlen($color);
// #rgb format
if ($length == 4 && $color[0] === "#") {
return $cache[$color] = self::getArray($color[1] . $color[1] . $color[2] . $color[2] . $color[3] . $color[3]);
} // #rgba format
else if ($length == 5 && $color[0] === "#") {
$alpha = round(hexdec($color[4] . $color[4])/255, 2);
return $cache[$color] = self::getArray($color[1] . $color[1] . $color[2] . $color[2] . $color[3] . $color[3], $alpha);
} // #rrggbb format
else if ($length == 7 && $color[0] === "#") {
return $cache[$color] = self::getArray(mb_substr($color, 1, 6));
} // #rrggbbaa format
else if ($length == 9 && $color[0] === "#") {
$alpha = round(hexdec(mb_substr($color, 7, 2))/255, 2);
return $cache[$color] = self::getArray(mb_substr($color, 1, 8), $alpha);
} // rgb( r,g,b ) / rgbaa( r,g,b,α ) format
else if (mb_strpos($color, "rgb") !== false) {
$i = mb_strpos($color, "(");
$j = mb_strpos($color, ")");
// Bad color value
if ($i === false || $j === false) {
return null;
}
$triplet = explode(",", mb_substr($color, $i + 1, $j - $i - 1));
// alpha transparency
// FIXME: not currently using transparency
$alpha = 1.0;
if (count($triplet) == 4) {
$alpha = (float)(trim(array_pop($triplet)));
// bad value, set to fully opaque
if ($alpha > 1.0 || $alpha < 0.0) {
$alpha = 1.0;
}
}
if (count($triplet) != 3) {
return null;
}
foreach (array_keys($triplet) as $c) {
$triplet[$c] = trim($triplet[$c]);
if (Helpers::is_percent($triplet[$c])) {
$triplet[$c] = round((float)$triplet[$c] * 2.55);
}
}
return $cache[$color] = self::getArray(vsprintf("%02X%02X%02X", $triplet), $alpha);
}
// cmyk( c,m,y,k ) format
// http://www.w3.org/TR/css3-gcpm/#cmyk-colors
else if (mb_strpos($color, "cmyk") !== false) {
$i = mb_strpos($color, "(");
$j = mb_strpos($color, ")");
// Bad color value
if ($i === false || $j === false) {
return null;
}
$values = explode(",", mb_substr($color, $i + 1, $j - $i - 1));
if (count($values) != 4) {
return null;
}
$values = array_map(function($c) {
return min(1.0, max(0.0, floatval(trim($c))));
}, $values);
return $cache[$color] = self::getArray($values);
}
return null;
}
/**
* @param $color
* @param float $alpha
* @return array
*/
static function getArray($color, $alpha = 1.0)
{
$c = array(null, null, null, null, "alpha" => $alpha, "hex" => null);
if (is_array($color)) {
$c = $color;
$c["c"] = $c[0];
$c["m"] = $c[1];
$c["y"] = $c[2];
$c["k"] = $c[3];
$c["alpha"] = $alpha;
$c["hex"] = "cmyk($c[0],$c[1],$c[2],$c[3])";
} else {
$c[0] = hexdec(mb_substr($color, 0, 2)) / 0xff;
$c[1] = hexdec(mb_substr($color, 2, 2)) / 0xff;
$c[2] = hexdec(mb_substr($color, 4, 2)) / 0xff;
$c["r"] = $c[0];
$c["g"] = $c[1];
$c["b"] = $c[2];
$c["alpha"] = $alpha;
$c["hex"] = sprintf("#%s%02X", mb_substr($color, 0, 6), round($alpha * 255));
}
return $c;
}
}

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more